// ---------------------------------------------------------------------------- // MODULE : PResolutionLevel // LANGUAGE : C++ // CREATOR : Philippe BOSSUT // CREAT. DATE : Wednesday, March 13, 1996 // DESCRIPTION : // COMMENTS : // SCCSID : @(#)pr_level.cpp 1.3 15:10:59 14 Apr 1997 // ---------------------------------------------------------------------------- // Copyright (c) 1999 Digital Imaging Group, Inc. // For conditions of distribution and use, see copyright notice // in Flashpix.h // ---------------------------------------------------------------------------- // ---------------------------------------------------------------------------- // ---------------------------------------------------------------------------- #include "pr_level.h" // ---------------------------------------------------------------------------- // Includes // -------- #ifndef Memoire_h #include "b_memory.h" #endif #ifndef PHierarchicalImage_h #include "ph_image.h" #endif #ifndef PTile_h #include "ptile.h" #endif #ifndef PImageFile_h #include "pimgfile.h" #endif #ifndef Numbers_h #include "numbers.h" #endif #ifndef Couleur_h #include "fpx_color.h" #endif #ifndef CorrectLut_h #include "corr_lut.h" #endif // Constants // --------- // Variables // --------- // ---------------------------------------------------------------------------- // Internal Functions // ---------------------------------------------------------------------------- // ---------------------------------------------------------------------------- // Member Functions // ---------------------------------------------------------------------------- // ---------------------------------------------------------------------------- // Methods of the PResolutionLevel class : this is the Resolution Level object. // // Manage an array on PTile objects which contain pixels. // Each PResolutionLevel points to the next PResolutionLevel which has a resolution // 1/2 of the current PResolutionLevel. // ---------------------------------------------------------------------------- // ---------------------------------------------------------------------------- // Initialize resolution information and create the next sub-image // Use this constructor in Create mode PResolutionLevel::PResolutionLevel (PHierarchicalImage* father, int width, int height, int* whatImage) { fatherFile = father; posFic = 0; // Position at the begining os the file identifier = *whatImage; register int TILE_WIDTH = fatherFile->tileWidth; register int TILE_SHIFT = fatherFile->log2TileWidth; // Compute number of tiles in height and width nbTilesH = (short)((height + TILE_WIDTH - 1) >> TILE_SHIFT); nbTilesW = (short)((width + TILE_WIDTH - 1) >> TILE_SHIFT); realHeight = height; realWidth = width; tiles = NULL; isAlpha = false; // No alpha by default premultiplied = false; // No premultiplication by default (in general... different in Core FlashPix...) alphaOffset = 0; // Default is aRGB, thus no offset... currentLine = 0; next = NULL; // Make a test to create or not the next sub image if ((realHeight > TILE_WIDTH) || (realWidth > TILE_WIDTH)) imageStatus = 0; else imageStatus = -1; // Increment sub-image number "whatImage" (*whatImage)++; } // ---------------------------------------------------------------------------- // Initialize resolution information and create the next sub-image // Use this constructor in Read or Write mode PResolutionLevel::PResolutionLevel (PHierarchicalImage* father, int* offset, int id) { fatherFile = father; posFic = *offset; identifier = id; nbTilesH = 0; nbTilesW = 0; realHeight = 0; realWidth = 0; tiles = NULL; isAlpha = false; // No alpha by default premultiplied = false; // No premultiplication by default (in general... different in Core FlashPix...) alphaOffset = 0; // Default is aRGB, thus no offset... currentLine = 0; imageStatus = 0; next = NULL; } // ---------------------------------------------------------------------------- // Clean resolution level and delete all related objects PResolutionLevel::~PResolutionLevel() { if (next) { delete next; next = NULL; } } // ---------------------------------------------------------------------------- void PResolutionLevel::InitWhenCreate() { } // ---------------------------------------------------------------------------- void PResolutionLevel::InitWhenReading() { } // ---------------------------------------------------------------------------- PResolutionLevel* PResolutionLevel::Previous() { PResolutionLevel* previous = NULL; if (identifier != 0) previous = fatherFile->subImages[identifier-1]; return previous; } // ---------------------------------------------------------------------------- // Allocate resolution levels array and compute resolution information FPXStatus PResolutionLevel::Allocation () { register int TILE_WIDTH = fatherFile->tileWidth; register int TILE_SHIFT = fatherFile->log2TileWidth; register int TILE_MASK = fatherFile->maskTileWidth; short i; short j; FPXStatus status = FPX_OK; // Update level infos if necessary: this happen only in rare case like when regenerating a flat file if (!nbTilesH || !nbTilesW) { PResolutionLevel* previous = Previous(); int width = previous->realWidth; int height = previous->realHeight; width = (width + 1) / 2; height = (height + 1) / 2; nbTilesH = (short)((height + TILE_WIDTH - 1) >> TILE_SHIFT); nbTilesW = (short)((width + TILE_WIDTH - 1) >> TILE_SHIFT); realHeight = height; realWidth = width; } // Allocate tiles array and init each tile if (nbTilesH && nbTilesW) { if ((status = AllocTilesArray()) != FPX_OK) return status; if (tiles) { PTile* tile = tiles; int index = 0; for (i = 0; i < (nbTilesH-1); i++, tile++) { for (j = 0; j < (nbTilesW-1); j++, tile++) tile->InitializeCreate(this,TILE_WIDTH,TILE_WIDTH,index++); // Init each tile of the line tile->InitializeCreate(this,((realWidth - 1) & TILE_MASK)+1,TILE_WIDTH,index++); // Init last tile of the line } for (j = 0; j < (nbTilesW-1); j++, tile++) tile->InitializeCreate(this,TILE_WIDTH,((realHeight - 1) & TILE_MASK)+1,index++); // Init last line of tiles tile->InitializeCreate(this,((realWidth - 1) & TILE_MASK)+1,((realHeight - 1) & TILE_MASK)+1,index++); // Init last tile } else { realHeight = 0; realWidth = 0; nbTilesH = 0; nbTilesW = 0; } } else { // If we can't allocate the tiles array, invalid the sub image record tiles = NULL; realHeight = 0; realWidth = 0; nbTilesH = 0; nbTilesW = 0; } return status; } // ---------------------------------------------------------------------------- Boolean PResolutionLevel::HasBeenUsed () { return (tiles != NULL); } // ---------------------------------------------------------------------------- FPXStatus PResolutionLevel::AllocTilesArray () { return FPX_OK; } // ---------------------------------------------------------------------------- // Inverse alpha channel in all opened display tiles FPXStatus PResolutionLevel::InverseAlpha() { if (!HasBeenUsed()) return FPX_OK; register int i = nbTilesH * nbTilesW; register PTile* tile = tiles; while (i--) tile++->InverseAlpha(); return FPX_OK; } // ---------------------------------------------------------------------------- // Read a resolution level and initialize the buffer 'pixels' FPXStatus PResolutionLevel::Read () { return FPX_OK; } // ---------------------------------------------------------------------------- // Write the tile header of a sub-image : FPXStatus PResolutionLevel::Write() { return FPX_OK; } // ---------------------------------------------------------------------------- // Write all remaining buffers of all sub-images // CAUTION : recursive function ... FPXStatus PResolutionLevel::CloseSubImage () { FPXStatus status = FPX_OK; if ((fatherFile->mode != mode_Lecture) && HasBeenUsed()) { // Write all remaining buffers of all sub-images FlushModifiedTiles(); // Write the tile header of a sub-image : if (status == FPX_OK) status = Write(); } if (next) status = next->CloseSubImage(); return status; } // ---------------------------------------------------------------------------- // Write a rectangle in a resolution level FPXStatus PResolutionLevel::WriteRectangle (int x0, int y0, int x1, int y1, Pixel* pix, short plan) { FPXStatus status = FPX_OK; int x, y, X, Y, X0 = 0, Y0 = 0; PTile *tile; Pixel *cur_pix; int h, w; int rowOffset = x1 - x0 + 1; register int TILE_WIDTH = fatherFile->tileWidth; register int TILE_SHIFT = fatherFile->log2TileWidth; register int TILE_MASK = fatherFile->maskTileWidth; // Test input values if ((x1 < x0) || (y1 < y0)) return FPX_BAD_COORDINATES; // Inconsistent bounds of rectangle if ((x0 >= realWidth) || (y0 >= realHeight) || (x1 < 0) || (y1 < 0)) return FPX_BAD_COORDINATES; // Attempt to write outside the image // Clipping if (x0 < 0) { pix -= x0; x0 = 0; } if (y0 < 0) { pix -= y0*rowOffset; y0 = 0; } if (x1 >= realWidth) x1 = realWidth - 1; if (y1 >= realHeight) y1 = realHeight - 1; X0 = x0 & (~TILE_MASK); Y0 = y0 & (~TILE_MASK); // PTCH_105 - added following to implement progress callbacks.... int totalTileCount, tilesWritten; totalTileCount = ((x1 - x0 + TILE_WIDTH - 1) >> TILE_SHIFT) * ((y1 - y0 + TILE_WIDTH - 1) >> TILE_SHIFT); tilesWritten = 0; // PTCH_105 - ....end of addition // Write on each tile Y = Y0; y = y0 & TILE_MASK; h = ((y1-Y+1) >= TILE_WIDTH ? TILE_WIDTH - y : (y1-y0+1)); while (Y <= y1) { X = X0; x = x0 & TILE_MASK; w = ((x1-X+1) >= TILE_WIDTH ? TILE_WIDTH - x : (x1-x0+1)); cur_pix = pix; tile = tiles + (Y>>TILE_SHIFT)*nbTilesW + (X>>TILE_SHIFT); while (X <= x1) { status = tile->WriteRectangle (cur_pix, w, h, rowOffset, x, y, plan); if (status) // stop the writing if one tile couldn't be writen return status; tile++; cur_pix += w; x = 0; X += TILE_WIDTH; w = ((x1-X+1) >= TILE_WIDTH ? TILE_WIDTH : (x1-X+1)); // PTCH_105 - added following to implement progress callbacks.... if ( GtheSystemToolkit->fnctProgFunc) { tilesWritten++; if (GtheSystemToolkit->fnctProgFunc( totalTileCount, tilesWritten)) return FPX_USER_ABORT; } // PTCH_105 - ....end of addition } pix += rowOffset * h; y = 0; Y += TILE_WIDTH; h = ((y1-Y+1) >= TILE_WIDTH ? TILE_WIDTH : (y1-Y+1)); } return FPX_OK; } // ---------------------------------------------------------------------------- FPXStatus PResolutionLevel::FlushModifiedTiles() { FPXStatus status = FPX_OK; if (tiles) { int n = nbTilesH * nbTilesW; for ( int i = 0; (i < n) && (status == FPX_OK); i++) { if (tiles[i].HasFreshPixels()) status = tiles[i].WriteTile(); } } return status; } // ---------------------------------------------------------------------------- // Just call the decimation function for each tile of the level FPXStatus PResolutionLevel::DecimateLevel () { FPXStatus status = FPX_OK; if (tiles) { int n = nbTilesH * nbTilesW; for (int i = 0; (i < n) && (status == FPX_OK); ++i) status = tiles[i].DecimateTile(); } else status = FPX_ERROR; return status; } // ---------------------------------------------------------------------------- FPXStatus PResolutionLevel::ReadRectangle (int x0, int y0, int x1, int y1, Pixel* pix) { FPXStatus status = FPX_OK; FPXStatus currentStatus = FPX_OK; int x, y, X, Y, X0 = 0, Y0 = 0; PTile *tile; Pixel *cur_pix = pix; int h, w; int rowOffset = x1 - x0 + 1; register int TILE_WIDTH = fatherFile->tileWidth; register int TILE_SHIFT = fatherFile->log2TileWidth; register int TILE_MASK = fatherFile->maskTileWidth; Pixel BACKGROUND = fatherFile->backgroundUsed; // Test input values if ((x1 < x0) || (y1 < y0)) return FPX_BAD_COORDINATES; // Inconsistent bounds of rectangle // VISU2 "obj_SubImageIO::ReadRectangle : x0 = %d, y0 = %d, x1 = %d, y1 = %d\n", x0, y0, x1, y1 FIN // Compute cropping for this scale : int cropx0 = fatherFile->cropX0 >> identifier; int cropy0 = fatherFile->cropY0 >> identifier; int cropx1 = fatherFile->cropX1 >> identifier; int cropy1 = fatherFile->cropY1 >> identifier; // Take cropping into account : px and py are given in the cropped coordinates => translate first x0 += cropx0; y0 += cropy0; x1 += cropx0; y1 += cropy0; if ((x0 >= cropx1) || (y0 >= cropy1) || (x1 < cropx0) || (y1 < cropy0)) { for (y = y0; y <= y1; y++) for (x = x0; x <= x1; x++) *pix++ = BACKGROUND; return FPX_BAD_COORDINATES; // Attempt to read outside the image } // Clipping : if clipping if ((x1 >= cropx1) || (y1 >= cropy1) || (x0 < cropx0) || (y0 < cropy0)) { // Init rectangle with BACKGROUND color for (y = y0; y <= y1; y++) for (x = x0; x <= x1; x++) *cur_pix++ = BACKGROUND; if (x0 < cropx0) { pix += (cropx0 - x0); x0 = cropx0; } if (y0 < cropy0) { pix += (cropy0 - y0)*rowOffset; y0 = cropy0; } if (x1 >= cropx1) x1 = cropx1-1; if (y1 >= cropy1) y1 = cropy1-1; } X0 = x0 & (~TILE_MASK); Y0 = y0 & (~TILE_MASK); // Read each tile and copy pixels to output rectangle Y = Y0; y = y0 & TILE_MASK; h = ((y1-Y+1) >= TILE_WIDTH ? TILE_WIDTH - y : (y1-y0+1)); while (Y <= y1) { X = X0; x = x0 & TILE_MASK; w = ((x1-X+1) >= TILE_WIDTH ? TILE_WIDTH - x : (x1-x0+1)); cur_pix = pix; tile = tiles + (Y>>TILE_SHIFT)*nbTilesW + (X>>TILE_SHIFT); while (X <= x1) { // read a rectangle in a tile, if a fatal error occur stop the loop if ((currentStatus = tile->ReadRectangle (cur_pix, w, h, rowOffset, x, y))) { if (currentStatus == FPX_MEMORY_ALLOCATION_FAILED) return currentStatus; // Stop if no memory available else // otherwise status = currentStatus; // save the error for return later } tile++; cur_pix += w; x = 0; X += TILE_WIDTH; w = ((x1-X+1) >= TILE_WIDTH ? TILE_WIDTH : (x1-X+1)); } pix += rowOffset * h; y = 0; Y += TILE_WIDTH; h = ((y1-Y+1) >= TILE_WIDTH ? TILE_WIDTH : (y1-Y+1)); } return status; } // ---------------------------------------------------------------------------- FPXStatus PResolutionLevel::Convolution (int x, int y, Pixel* pix, int width, int height) { // CAUTION : no line or column is allocated for tiles of one line or one column // They contribution to the convoluted image is 0 -> skip these tiles if ((width <= 1) || (height <= 1)) return FPX_OK; int numTile = ((y>>1)*nbTilesW) + (x>>1); int quadrant = (x&0x01) | ((y&0x01)<<1); return tiles[numTile].Convolution (pix, width, height, quadrant); } // ---------------------------------------------------------------------------- // Read a rectangular area of a sub-image. Read on disk if necessary. // If decompressor is missing, return false and fill "table[]" with "BACKGROUND". // // Returns an FPX_ error (e.g., FPX_OK, etc.) // FPXStatus PResolutionLevel::Read(int* px, int* py, Pixel* table) { register int TILE_WIDTH = fatherFile->tileWidth; register int TILE_SHIFT = fatherFile->log2TileWidth; register int TILE_MASK = fatherFile->maskTileWidth; Pixel BACKGROUND = fatherFile->backgroundUsed; Boolean useAlpha = fatherFile->useAlphaChannel | (isAlpha & premultiplied); unsigned char alphaOffset = fatherFile->alphaOffset; PTile *tile; FPXStatus readStatus, status = FPX_OK; int i; // Compute cropping for this scale : int cropx0 = fatherFile->cropX0 >> identifier; int cropy0 = fatherFile->cropY0 >> identifier; int cropx1 = fatherFile->cropX1 >> identifier; int cropy1 = fatherFile->cropY1 >> identifier; // ----- if table[] clip the edge of the image ----- // if ((px[P00] >= cropx1) || (py[P00] >= cropy1) || (px[P00] < cropx0) || (py[P00] < cropy0) || (px[P30] >= cropx1) || (py[P30] >= cropy1) || (px[P30] < cropx0) || (py[P30] < cropy0) || (px[P03] >= cropx1) || (py[P03] >= cropy1) || (px[P03] < cropx0) || (py[P03] < cropy0) || (px[P33] >= cropx1) || (py[P33] >= cropy1) || (px[P33] < cropx0) || (py[P33] < cropy0)) { if (useAlpha && PTile::invertLUT) { short alpha, beta; unsigned char* srcPix; unsigned char* desPix; int index; for (i = 0; i < 16; ++i, ++table) { if ((px[i] < cropx1) && (py[i] < cropy1) && (px[i] >= cropx0) && (py[i] >= cropy0)) { tile = tiles + (py[i] >> TILE_SHIFT) * nbTilesW + (px[i] >> TILE_SHIFT); if ((readStatus = tile->Read())) status = readStatus; if (!tile->pixels) { // If error reading data *table = BACKGROUND; // VISU2 "obj_SubImageIO::Read, read error 1 => BACKGROUND\n" FIN } else { srcPix = (unsigned char*)(tile->pixels + ((px[i] & TILE_MASK) + (py[i] & TILE_MASK) * tile->width)); alpha = *(srcPix + alphaOffset); beta = PTile::invertLUT[alpha]; desPix = (unsigned char*)(table); if (premultiplied) for (index = 4; index; --index, ++desPix, ++srcPix) *desPix = (unsigned char)((*desPix*beta)/0xFF + *srcPix); else for (index = 4; index; --index, ++desPix, ++srcPix) *desPix = (unsigned char)((*desPix*beta + *srcPix*alpha)/0xFF); } } } } else { for(i = 0; i < 16; ++i, ++table) { if ((px[i] < cropx1) && (py[i] < cropy1) && (px[i] >= cropx0) && (py[i] >= cropy0)) { tile = tiles + (py[i] >> TILE_SHIFT) * nbTilesW + (px[i] >> TILE_SHIFT); if ((readStatus = tile->Read())) status = readStatus; if (!tile->pixels) { // If error reading data *table = BACKGROUND; // VISU2 "obj_SubImageIO::Read, read error 1 => BACKGROUND\n" FIN } else *table = tile->pixels[(px[i] & TILE_MASK) + (py[i] & TILE_MASK) * tile->width]; } else if (Toolkit_WriteOnBackground()) *table = BACKGROUND; } } } else { int p = px[P00] >> TILE_SHIFT; int q = py[P00] >> TILE_SHIFT; // ----- table[] meets several tiles boundaries -----// if (((px[P03] >> TILE_SHIFT) != p) || ((py[P03] >> TILE_SHIFT) != q) || ((px[P30] >> TILE_SHIFT) != p) || ((py[P30] >> TILE_SHIFT) != q) || ((px[P33] >> TILE_SHIFT) != p) || ((py[P33] >> TILE_SHIFT) != q)) { if (useAlpha && PTile::invertLUT) { short alpha, beta; unsigned char* srcPix; unsigned char* desPix; int index; for(i = 0; i < 16; ++i, ++table) { tile = tiles + (py[i] >> TILE_SHIFT) * nbTilesW + (px[i] >> TILE_SHIFT); if ((readStatus = tile->Read())) status = readStatus; if (!tile->pixels) { // If error reading data *table = BACKGROUND; // VISU2 "obj_SubImageIO::Read, read error 2 => BACKGROUND\n" FIN } else { srcPix = (unsigned char*)(tile->pixels + ((px[i] & TILE_MASK) + (py[i] & TILE_MASK) * tile->width)); alpha = *(srcPix + alphaOffset); beta = PTile::invertLUT[alpha]; desPix = (unsigned char*)(table); if (premultiplied) for (index = 4; index; --index, ++desPix, ++srcPix) *desPix = (unsigned char)((*desPix*beta)/0xFF + *srcPix); else for (index = 4; index; --index, ++desPix, ++srcPix) *desPix = (unsigned char)((*desPix*beta + *srcPix*alpha)/0xFF); } } } else { for(i = 0; i < 16; ++i, ++table) { tile = tiles + (py[i] >> TILE_SHIFT) * nbTilesW + (px[i] >> TILE_SHIFT); if ((readStatus = tile->Read())) status = readStatus; if (!tile->pixels) { // If error reading data *table = BACKGROUND; // VISU2 "obj_SubImageIO::Read, read error 2 => BACKGROUND\n" FIN } else *table = tile->pixels[(px[i] & TILE_MASK) + (py[i] & TILE_MASK) * tile->width]; } } } else { // ----- table[] is included within a single tile -> Optimization of the reading loop -----// tile = tiles + q * nbTilesW + p; if ((readStatus = tile->Read())) status = readStatus; if (!tile->pixels) { // If error reading data for (i = 0; i < 16; ++i, ++table) *table = BACKGROUND; // VISU2 "obj_SubImageIO::Read, read error 3 => BACKGROUND\n" FIN } else { // most common case Pixel* pix = tile->pixels; int l = tile->width; if (l == TILE_WIDTH) { // --- If the tile Width is the tileWidth -> use fast acces algorithm ---// if (useAlpha && PTile::invertLUT) { short alpha, beta; unsigned char* srcPix; unsigned char* desPix; if (premultiplied) { for (i = 0; i < 16; ++i, ++table) { srcPix = (unsigned char*)(pix + ((px[i] & TILE_MASK) + ((py[i] & TILE_MASK) << TILE_SHIFT))); alpha = *(srcPix + alphaOffset); beta = PTile::invertLUT[alpha]; desPix = (unsigned char*)(table); for (int index = 4; index; --index, ++desPix, ++srcPix) *desPix = (unsigned char)((*desPix*beta)/0xFF + *srcPix); } } else { for (i = 0; i < 16; ++i, ++table) { srcPix = (unsigned char*)(pix + ((px[i] & TILE_MASK) + ((py[i] & TILE_MASK) << TILE_SHIFT))); alpha = *(srcPix + alphaOffset); beta = PTile::invertLUT[alpha]; desPix = (unsigned char*)(table); for (int index = 4; index; --index, ++desPix, ++srcPix) *desPix = (unsigned char)((*desPix*beta + *srcPix*alpha)/0xFF); } } } else { for (i = 0; i < 16; ++i, ++table) *table = pix[(px[i] & TILE_MASK) + ((py[i] & TILE_MASK) << TILE_SHIFT)]; } } else { // --- If table[] is in the last tile of the line. ---// if (useAlpha && PTile::invertLUT) { short alpha, beta; unsigned char* srcPix; unsigned char* desPix; if (premultiplied) { for (i = 0; i < 16; ++i, ++table) { srcPix = (unsigned char*)(pix + ((px[i] & TILE_MASK) + (py[i] & TILE_MASK) * l)); alpha = *(srcPix + alphaOffset); beta = PTile::invertLUT[alpha]; desPix = (unsigned char*)(table); for (int index = 4; index; --index, ++desPix, ++srcPix) *desPix = (unsigned char)((*desPix*beta)/0xFF + *srcPix); } } else { for (i = 0; i < 16; ++i, ++table) { srcPix = (unsigned char*)(pix + ((px[i] & TILE_MASK) + (py[i] & TILE_MASK) * l)); alpha = *(srcPix + alphaOffset); beta = PTile::invertLUT[alpha]; desPix = (unsigned char*)(table); for (int index = 4; index; --index, ++desPix, ++srcPix) *desPix = (unsigned char)((*desPix*beta + *srcPix*alpha)/0xFF); } } } else { for (i = 0; i < 16; ++i, ++table) *table = pix[(px[i] & TILE_MASK) + (py[i] & TILE_MASK) * l]; } } } } } return status; } // ---------------------------------------------------------------------------- FPXStatus PResolutionLevel::ReadInterpolated (int* px, int* py, Pixel* table) { register int TILE_SHIFT = fatherFile->log2TileWidth; register int TILE_MASK = fatherFile->maskTileWidth; Pixel BACKGROUND = fatherFile->backgroundUsed; PTile * tile; int ax, ay, bx, by, i, j, xi, yi, x0, y0, x1, y1, n, c0, c1, c2, c3, index; Pixel *pix0, *pix1, *pix2, *pix3; Boolean alphaPresent= fatherFile->existAlphaChannel; Boolean useAlpha = fatherFile->useAlphaChannel | (isAlpha & premultiplied); unsigned char alphaOffset = fatherFile->alphaOffset; FPXStatus status = FPX_OK; // Compute cropping for this scale : int cropx0 = fatherFile->cropX0 >> identifier; int cropy0 = fatherFile->cropY0 >> identifier; int cropx1 = fatherFile->cropX1 >> identifier; int cropy1 = fatherFile->cropY1 >> identifier; if (px[P00] > px[P30]) { ax = px[P30]; bx = px[P00]; } else { bx = px[P30]; ax = px[P00]; } if (px[P03] > px[P33]) { x0 = px[P33]; x1 = px[P03]; } else { x1 = px[P33]; x0 = px[P03]; } if (ax > x0) ax = x0; if (bx < x1) bx = x1; if (py[P00] > py[P30]) { ay = py[P30]; by = py[P00]; } else { by = py[P30]; ay = py[P00]; } if (py[P03] > py[P33]) { y0 = py[P33]; y1 = py[P03]; } else { y1 = py[P33]; y0 = py[P03]; } if (ay > y0) ay = y0; if (by < y1) by = y1; ax = (ax - 2) >> 8; ay = (ay - 2) >> 8; bx = (bx + 257) >> 8; by = (by + 257) >> 8; xi = ax >> TILE_SHIFT; yi = ay >> TILE_SHIFT; if ((ax < cropx0) || (ay < cropy0) || (bx >= cropx1) || (by >= cropy1) || (xi != (bx >> TILE_SHIFT)) || (yi != (by >> TILE_SHIFT))) { FPXStatus readStatus = FPX_OK; for (index = 0; index < 16; index++) if( (readStatus = ReadMeanInterpolated (px[index], py[index], table[index])) ) status = readStatus; return (status); } tile = tiles + yi * nbTilesW + xi; status = tile->Read(); if (status) { // If error reading on disk and pixels not created *table = BACKGROUND; // VISU2 "obj_SubImageIO::ReadInterpolated, read error without clipping => BACKGROUND\n" FIN return (status); } if (useAlpha && PTile::invertLUT) { short alpha, beta; Pixel srcPix; for (index = 0; index < 16; ++index, ++table) { xi = px[index]; yi = py[index]; x0 = xi >> 8; y0 = yi >> 8; n = (i = (x0 & TILE_MASK)) + (j = (y0 & TILE_MASK)) * tile->width; pix0 = tile->pixels + n; pix1 = pix0 + 1; pix2 = pix0 + tile->width; pix3 = pix2 + 1; ax = xi & 0xff; ay = yi & 0xff; bx = 256 - ax; by = 256 - ay; c0 = by * bx; c1 = by * ax; c2 = ay * bx; c3 = ay * ax; srcPix.alpha = (unsigned char)((c0 * pix0->alpha + c1 * pix1->alpha + c2 * pix2->alpha + c3 * pix3->alpha) >> 16); srcPix.rouge = (unsigned char)((c0 * pix0->rouge + c1 * pix1->rouge + c2 * pix2->rouge + c3 * pix3->rouge) >> 16); srcPix.vert = (unsigned char)((c0 * pix0->vert + c1 * pix1->vert + c2 * pix2->vert + c3 * pix3->vert) >> 16); srcPix.bleu = (unsigned char)((c0 * pix0->bleu + c1 * pix1->bleu + c2 * pix2->bleu + c3 * pix3->bleu) >> 16); unsigned char* sPix = (unsigned char*)(&srcPix); unsigned char* dPix = (unsigned char*)(table); alpha = *(sPix + alphaOffset); beta = PTile::invertLUT[alpha]; int index2; if (premultiplied) for (index2 = 4; index2; --index2, ++dPix, ++sPix) *dPix = (unsigned char)(*dPix*beta/0xFF + *sPix); else for (index2 = 4; index2; --index2, ++dPix, ++sPix) *dPix = (unsigned char)((*dPix*beta + *sPix*alpha)/0xFF); } } else { for (index = 0; index < 16; ++index, ++table) { xi = px[index]; yi = py[index]; x0 = xi >> 8; y0 = yi >> 8; n = (i = (x0 & TILE_MASK)) + (j = (y0 & TILE_MASK)) * tile->width; pix0 = tile->pixels + n; pix1 = pix0 + 1; pix2 = pix0 + tile->width; pix3 = pix2 + 1; ax = xi & 0xff; ay = yi & 0xff; bx = 256 - ax; by = 256 - ay; c0 = by * bx; c1 = by * ax; c2 = ay * bx; c3 = ay * ax; table->rouge = (unsigned char)((c0 * pix0->rouge + c1 * pix1->rouge + c2 * pix2->rouge + c3 * pix3->rouge) >> 16); table->vert = (unsigned char)((c0 * pix0->vert + c1 * pix1->vert + c2 * pix2->vert + c3 * pix3->vert) >> 16); table->bleu = (unsigned char)((c0 * pix0->bleu + c1 * pix1->bleu + c2 * pix2->bleu + c3 * pix3->bleu) >> 16); if (alphaPresent) table->alpha = (unsigned char)((c0 * pix0->alpha + c1 * pix1->alpha + c2 * pix2->alpha + c3 * pix3->alpha) >> 16); } } return status; } // ---------------------------------------------------------------------------- FPXStatus PResolutionLevel::ReadMeanInterpolated (int xi, int yi, Pixel& pixel) { PTile *tile; int x0, y0; Boolean WriteOnBackground = Toolkit_WriteOnBackground(); Boolean useAlpha = fatherFile->useAlphaChannel | (isAlpha & premultiplied); FPXStatus status = FPX_OK; register int TILE_SHIFT = fatherFile->log2TileWidth; register int TILE_MASK = fatherFile->maskTileWidth; Pixel BACKGROUND = fatherFile->backgroundUsed; unsigned char alphaOffset = fatherFile->alphaOffset; x0 = xi >> 8; y0 = yi >> 8; // Compute cropping for this scale : int cropx0 = fatherFile->cropX0 >> identifier; int cropy0 = fatherFile->cropY0 >> identifier; int cropx1 = fatherFile->cropX1 >> identifier; int cropy1 = fatherFile->cropY1 >> identifier; if ((x0 >= cropx1) || (y0 >= cropy1) || (x0 < cropx0) || (y0 < cropy0) || (xi < -255) || (yi < -255)) { if (WriteOnBackground && !useAlpha) pixel = BACKGROUND; } else { int ax, ay, bx, by, i, j, x1, y1, n, c0, c1, c2, c3; Pixel pix0, pix1, pix2, pix3; if ((xi >= 0) && (yi >= 0)) { tile = tiles + (y0 >> TILE_SHIFT) * nbTilesW + (x0 >> TILE_SHIFT); status = tile->Read(); if (status) { // If error reading on disk and pixels not created pixel = BACKGROUND; // VISU2 "obj_SubImageIO::ReadMeanInterpolated, read error 1 => BACKGROUND\n" FIN return (status); } pix0 = tile->pixels[n = (i = (x0 & TILE_MASK)) + (j = (y0 & TILE_MASK)) * tile->width]; if ((i == tile->width - 1) || (j == tile->height - 1)) { x1 = x0 + 1; y1 = y0 + 1; if (x1 < realWidth) { tile = tiles + (y0 >> TILE_SHIFT) * nbTilesW + (x1 >> TILE_SHIFT); status = tile->Read(); if (status) { // If error reading on disk and pixels not created pixel = BACKGROUND; // VISU2 "obj_SubImageIO::ReadMeanInterpolated, read error 2 => BACKGROUND\n" FIN return (status); } pix1 = tile->pixels[(x1 & TILE_MASK) + (y0 & TILE_MASK) * tile->width]; } else { if (WriteOnBackground) pix1 = BACKGROUND; else pix1 = pixel; } if (y1 < realHeight) { tile = tiles + (y1 >> TILE_SHIFT) * nbTilesW + (x0 >> TILE_SHIFT); status = tile->Read(); if (status) { // If error reading on disk and pixels not created pixel = BACKGROUND; // VISU2 "obj_SubImageIO::ReadMeanInterpolated, read error 3 => BACKGROUND\n" FIN return (status); } pix2 = tile->pixels[(x0 & TILE_MASK) + (y1 & TILE_MASK) * tile->width]; } else { if (WriteOnBackground) pix2 = BACKGROUND; else pix2 = pixel; } if ((x1 < realWidth) && (y1 < realHeight)) { tile = tiles + (y1 >> TILE_SHIFT) * nbTilesW + (x1 >> TILE_SHIFT); status = tile->Read(); if (status) { // If error reading on disk and pixels not created pixel = BACKGROUND; // VISU2 "obj_SubImageIO::ReadMeanInterpolated, read error 4 => BACKGROUND\n" FIN return (status); } pix3 = tile->pixels[(x1 & TILE_MASK) + (y1 & TILE_MASK) * tile->width]; } else { if (WriteOnBackground) pix3 = BACKGROUND; else pix3 = pixel; } } else { pix1 = tile->pixels[n + 1]; pix2 = tile->pixels[n += tile->width]; pix3 = tile->pixels[n + 1]; } ax = xi & 0xff; ay = yi & 0xff; } else { if (WriteOnBackground) pix0 = BACKGROUND; else pix0 = pixel; if (xi < 0) { x0 = -1; ax = 256 + xi; } else ax = xi & 0xff; if (yi < 0) { y0 = -1; ay = 256 + yi; } else ay = yi & 0xff; x1 = x0 + 1; y1 = y0 + 1; if ((x1 < realWidth) && (y0 >= 0)) { tile = tiles + (y0 >> TILE_SHIFT) * nbTilesW + (x1 >> TILE_SHIFT); status = tile->Read(); if (status) { // If error reading on disk and pixels not created pixel = BACKGROUND; // VISU2 "obj_SubImageIO::ReadMeanInterpolated, read error 5 => BACKGROUND\n" FIN return (status); } pix1 = tile->pixels[(x1 & TILE_MASK) + (y0 & TILE_MASK) * tile->width]; } else { if (WriteOnBackground) pix1 = BACKGROUND; else pix1 = pixel; } if ((y1 < realHeight) && (x0 >= 0)) { tile = tiles + (y1 >> TILE_SHIFT) * nbTilesW + (x0 >> TILE_SHIFT); status = tile->Read(); if (status) { // If error reading on disk and pixels not created pixel = BACKGROUND; // VISU2 "obj_SubImageIO::ReadMeanInterpolated, read error 6 => BACKGROUND\n" FIN return (status); } pix2 = tile->pixels[(x0 & TILE_MASK) + (y1 & TILE_MASK) * tile->width]; } else { if (WriteOnBackground) pix2 = BACKGROUND; else pix2 = pixel; } if ((x1 < realWidth) && (y1 < realHeight)) { tile = tiles + (y1 >> TILE_SHIFT) * nbTilesW + (x1 >> TILE_SHIFT); status = tile->Read(); if (status) { // If error reading on disk and pixels not created pixel = BACKGROUND; // VISU2 "obj_SubImageIO::ReadMeanInterpolated, read error 7 => BACKGROUND\n" FIN return (status); } pix3 = tile->pixels[(x1 & TILE_MASK) + (y1 & TILE_MASK) * tile->width]; } else { if (WriteOnBackground) pix3 = BACKGROUND; else pix3 = pixel; } } bx = 256 - ax; by = 256 - ay; c0 = by * bx; c1 = by * ax; c2 = ay * bx; c3 = ay * ax; if (useAlpha && PTile::invertLUT) { short alpha, beta; Pixel srcPix; int index; srcPix.alpha = (unsigned char)((c0 * pix0.alpha + c1 * pix1.alpha + c2 * pix2.alpha + c3 * pix3.alpha) >> 16); srcPix.rouge = (unsigned char)((c0 * pix0.rouge + c1 * pix1.rouge + c2 * pix2.rouge + c3 * pix3.rouge) >> 16); srcPix.vert = (unsigned char)((c0 * pix0.vert + c1 * pix1.vert + c2 * pix2.vert + c3 * pix3.vert) >> 16); srcPix.bleu = (unsigned char)((c0 * pix0.bleu + c1 * pix1.bleu + c2 * pix2.bleu + c3 * pix3.bleu) >> 16); unsigned char* sPix = (unsigned char*)(&srcPix); unsigned char* dPix = (unsigned char*)(&pixel); alpha = *(sPix + alphaOffset); beta = PTile::invertLUT[alpha]; if (premultiplied) for (index = 4; index; --index, ++dPix, ++sPix) *dPix = (unsigned char)((*dPix*beta)/0xFF + *sPix); else for (index = 4; index; --index, ++dPix, ++sPix) *dPix = (unsigned char)((*dPix*beta + *sPix*alpha)/0xFF); } else { pixel.rouge = (unsigned char)((c0 * pix0.rouge + c1 * pix1.rouge + c2 * pix2.rouge + c3 * pix3.rouge) >> 16); pixel.vert = (unsigned char)((c0 * pix0.vert + c1 * pix1.vert + c2 * pix2.vert + c3 * pix3.vert) >> 16); pixel.bleu = (unsigned char)((c0 * pix0.bleu + c1 * pix1.bleu + c2 * pix2.bleu + c3 * pix3.bleu) >> 16); if (fatherFile->existAlphaChannel) pixel.alpha = (unsigned char)((c0 * pix0.alpha + c1 * pix1.alpha + c2 * pix2.alpha + c3 * pix3.alpha) >> 16); } } return (status); } // ---------------------------------------------------------------------------- // Compute histogram for the 4 channels of the display-modified pixels FPXStatus PResolutionLevel::GetHistogram (int* alpha, int* red, int* green, int* blue, int* brightness, const CorrectLut* correctLut) { short i, j; PTile* tile = tiles; // Histograms initialization for (i=0; i<256; i++) { alpha[i] = 0; red[i] = 0; green[i] = 0; blue[i] = 0; brightness[i] = 0; } // Read pixels if necessary FPXStatus status = tile->Read(); if (status == FPX_OK) { Pixel* pt = tile->pixels; Pixel interm; // Compute histograms for (j=0; jheight; j++) { for (i=0; iwidth; i++, pt++) { if (correctLut) interm = (*correctLut)(*pt); else interm = *pt; alpha[interm.alpha]++; red[interm.rouge]++; green[interm.vert]++; blue[interm.bleu]++; brightness[((int32)(interm.rouge)+((int32)(interm.vert)<<1)+(int32)(interm.bleu))>>2]++; } } } return status; } // ---------------------------------------------------------------------------- FPXStatus PResolutionLevel::GetResolutionSizeInfo (int* width, int* height, int* nbTilesWidth, int* nbTilesHeight) { *width = realWidth; *height = realHeight; *nbTilesWidth = nbTilesW; *nbTilesHeight = nbTilesH; return FPX_OK; } // ---------------------------------------------------------------------------- // Return true if the position is on the border of the crop rectangle // CAUTION: coordinates are discrete with 0 bit precision (true pixel position in the level) Boolean PResolutionLevel::IsOnTheBorder (int xi, int yi) { // Compute cropping for this scale: int cropx0 = fatherFile->cropX0 >> identifier; int cropy0 = fatherFile->cropY0 >> identifier; int cropx1 = (fatherFile->cropX1 >> identifier) - 1; int cropy1 = (fatherFile->cropY1 >> identifier) - 1; // Check position on the borders: return ((xi >= cropx1) || (yi >= cropy1) || (xi <= cropx0) || (yi <= cropy0)); } // ---------------------------------------------------------------------------- // Read a pixel of a sub image. Read it on disk if necessary. // If error, return false and pixel is set to 0. // CAUTION: coordinates are discrete with 0 bit precision (true pixel position in the level) FPXStatus PResolutionLevel::ReadMean (int xi, int yi, Pixel& pixel) { PTile *tile; FPXStatus status = FPX_OK; Boolean WriteOnBackground = Toolkit_WriteOnBackground(); Boolean useAlpha = fatherFile->useAlphaChannel | (isAlpha & premultiplied); unsigned char alphaOffset = fatherFile->alphaOffset; register int TILE_SHIFT = fatherFile->log2TileWidth; register int TILE_MASK = fatherFile->maskTileWidth; Pixel BACKGROUND = fatherFile->backgroundUsed; // Compute cropping for this scale : int cropx0 = fatherFile->cropX0 >> identifier; int cropy0 = fatherFile->cropY0 >> identifier; int cropx1 = fatherFile->cropX1 >> identifier; int cropy1 = fatherFile->cropY1 >> identifier; if ((xi >= cropx1) || (yi >= cropy1) || (xi < cropx0) || (yi < cropy0)) { if (WriteOnBackground && !useAlpha) pixel = BACKGROUND; } else { tile = tiles + (yi >> TILE_SHIFT) * nbTilesW + (xi >> TILE_SHIFT); status = tile->Read(); if (status) { // If error reading on disk and pixels not created pixel = BACKGROUND; // VISU2 "obj_SubImageIO::ReadMean, read error => BACKGROUND\n" FIN } else { if (useAlpha) { short alpha, beta; unsigned char* srcPix; int index; srcPix = (unsigned char *)(tile->pixels + ((xi & TILE_MASK) + (yi & TILE_MASK) * tile->width)); alpha = *(srcPix + alphaOffset); beta = PTile::invertLUT[alpha]; unsigned char* desPix = (unsigned char*)(&pixel); if (premultiplied) for (index = 4; index; --index, ++desPix, ++srcPix) *desPix = (unsigned char)((*desPix*beta)/0xFF + *srcPix); else for (index = 4; index; --index, ++desPix, ++srcPix) *desPix = (unsigned char)((*desPix*beta + *srcPix*alpha)/0xFF); } else pixel = tile->pixels[(xi & TILE_MASK) + (yi & TILE_MASK) * tile->width]; } } return status; } // ---------------------------------------------------------------------------- // Read a rectangle (x0,y0,x1,y1) in a map // The correct sub image is read and sampled in order to fill the map with the rectangle // CAUTION : map must be allocated and freed by calling routine // FPXStatus PResolutionLevel::ReadSampledRectangle(int x0, int y0,int x1, int y1, Pixel* map, short pixelsPerLine, int mapWidth, int mapHeight, Boolean showAlphaChannel, float ratio) { int i, j, k; Pixel* bufferPtr = map; register int TILE_WIDTH = fatherFile->tileWidth; register int TILE_SHIFT = fatherFile->log2TileWidth; Pixel BACKGROUND = fatherFile->backgroundUsed; unsigned char alphaOffset = fatherFile->alphaOffset; BACKGROUND.rouge = 0xFF; FPXStatus status; if (ratio == 0) ratio = MIN(float(float(mapWidth)/float(x1 - x0)) , float(float(mapHeight)/float(y1 - y0))); // Set use of alpha channel if ((showAlphaChannel && fatherFile->existAlphaChannel) || (fatherFile->useAlphaChannel) || (isAlpha & premultiplied)) showAlphaChannel = true; else showAlphaChannel = false; short *pixToTile; int tileWidth = FLOAT_TO_LONG(TILE_WIDTH * ratio); // Reserve an intermediate buffer FastAllocArray(pixToTile, short, tileWidth); if (pixToTile == NULL) { // If not enough space available to Toolkit => fill with background color and quit Pixel* bufferLine = bufferPtr; for (j=0; j= x0Tile) && (y0 < y1Tile) && (y1 >= y0Tile) ) { // Tile Initialisation status = tile->Read(); if (!tile->pixels || (status != FPX_OK)) { // if error reading data => fill with background color and quit Pixel* bufferLine = bufferPtr; for (j=0; jheight)); if (topInBuffer < 0) { firstInTileH = -topInBuffer; topInBuffer = 0; } if (lTile < (nbTilesW-1)) widthOfBuffer = FLOAT_TO_LONG(ratio * float(x1Tile - x0Tile)); else widthOfBuffer = FLOAT_TO_LONG(ratio * float(tile->width) ); if (leftInBuffer < 0) { firstInTileW = -leftInBuffer; leftInBuffer = 0; } if (heightOfBuffer - firstInTileH + topInBuffer > mapHeight) heightOfBuffer = mapHeight - topInBuffer + firstInTileH; if (widthOfBuffer - firstInTileW + leftInBuffer > mapWidth) widthOfBuffer = mapWidth - leftInBuffer + firstInTileW; Pixel* bufferLine = bufferPtr + (topInBuffer * pixelsPerLine + leftInBuffer); for (j = firstInTileH; j < heightOfBuffer; ++j) { Pixel* pixelPtr = tile->pixels + (pixToTile[j] * tile->width); // Copy pixels with sampling if (firstInTileW) for (i = firstInTileW, k = 0; i < widthOfBuffer; ++i, ++k) bufferLine[k] = pixelPtr[pixToTile[i]]; else for (i = 0; i < widthOfBuffer; ++i) bufferLine[i] = pixelPtr[pixToTile[i]]; // Take alpha channel into account if (showAlphaChannel) { short alpha, beta; unsigned char* sPix; unsigned char* dPix; int index; for (i = 0; i < widthOfBuffer; ++i) { sPix = (unsigned char*)(bufferLine + i); alpha = (short)(*(sPix + alphaOffset)); beta = (short)(PTile::invertLUT[alpha]); if (!alpha) bufferLine[i] = BACKGROUND; else if (alpha < 0xFF) { dPix = (unsigned char*)(&BACKGROUND); if (premultiplied) for (index = 4; index; --index, ++dPix, ++sPix) *sPix = (unsigned char)(*dPix*beta/0xFF + *sPix); else for (index = 4; index; --index, ++dPix, ++sPix) *sPix = (unsigned char)((*dPix*beta + *sPix*alpha)/0xFF); } // else if (alpha == 0xFF) bufferLine[i] is unchanged } } bufferLine += pixelsPerLine; } leftInBuffer += widthOfBuffer - firstInTileW; } ++tile; } if (!firstInLine) { first = false; topInBuffer += heightOfBuffer - firstInTileH; } } FastDeleteArray(pixToTile, short); return status; } // ---------------------------------------------------------------------------- // Search the top and left corner of the screen pixel which contains the given position // This function is used when 1 image pixel is represented by more than 1 screen pixel FPXStatus PResolutionLevel::SearchPixelTopLeftCorner(int* x1, int* y1, float ratio) { register int TILE_WIDTH = fatherFile->tileWidth; register int TILE_SHIFT = fatherFile->log2TileWidth; short *pixToTile; FPXStatus status; int tileWidth = FLOAT_TO_LONG(TILE_WIDTH * ratio); // Reserve an intermediate buffer FastAllocArray(pixToTile, short, tileWidth); if (pixToTile == NULL) return FPX_MEMORY_ALLOCATION_FAILED; int i; // pixToTile will contains the screen pixels' positions for (i = 0; i < tileWidth; ++i) pixToTile[i] = short(float(i) / ratio + 0.01); PTile* tile = tiles; Boolean end = false; for (short hTile = 0; hTile < nbTilesH; ++hTile) { int y0Tile = FLOAT_TO_LONG(float(hTile << TILE_SHIFT) * ratio); int y1Tile = FLOAT_TO_LONG(float((hTile+1) << TILE_SHIFT) * ratio); for (short lTile = 0; lTile < nbTilesW; ++lTile) { int x0Tile = FLOAT_TO_LONG(float( lTile << TILE_SHIFT) * ratio); int x1Tile = FLOAT_TO_LONG(float((lTile+1) << TILE_SHIFT) * ratio); // compare the tile position with the position to find if ((*x1 < x1Tile) && (*x1 >= x0Tile) && (*y1 < y1Tile) && (*y1 >= y0Tile) ) { // Tile Initialisation status = tile->Read(); if (status != FPX_OK) { // if error reading data => quit FastDeleteArray(pixToTile,short); return status; } int topInBuffer = *y1 - y0Tile; short pixelY = pixToTile[topInBuffer]; int leftInBuffer = *x1 - x0Tile; short pixelX = pixToTile[leftInBuffer]; while ((topInBuffer > 0) && (pixToTile[topInBuffer-1] == pixelY)) topInBuffer--; while ((leftInBuffer > 0) && (pixToTile[leftInBuffer-1] == pixelX)) leftInBuffer--; *y1 = topInBuffer + y0Tile; *x1 = leftInBuffer + x0Tile; end = true; break; } ++tile; } if ( end ) break; } FastDeleteArray(pixToTile, short); return status; } // ---------------------------------------------------------------------------- // Send back the smallest image contained in a rectangle width * height. // Read it on disk if necessary. // If decompressor is missing, send back NULL. FPXStatus PResolutionLevel::ReadInARectangle(Pixel* bufferOut, short pixelsPerLine, short width, short height, const CorrectLut* correctLut, Boolean useAlphaChannel, const CombinMat* combinaisonMatrix) { short i, j; Pixel* bufferPtr; float ratio; FPXStatus status = FPX_OK; register int TILE_WIDTH = fatherFile->tileWidth; Pixel BACKGROUND = fatherFile->backgroundUsed; unsigned char alphaOffset = fatherFile->alphaOffset; BACKGROUND.rouge = 0xFF; // Set use of alpha channel if ((useAlphaChannel && fatherFile->existAlphaChannel) || (fatherFile->useAlphaChannel) || (isAlpha & premultiplied)) useAlphaChannel = true; else useAlphaChannel = false; // Reduce the width or the height in order to have : realHeight * width == realWidth * height if (realHeight * width >= realWidth * height) { ratio = float(height) / float(realHeight); short newWidth = (short)(realWidth * ratio); bufferPtr = bufferOut + ((width - newWidth)/2); width = newWidth; } else { ratio = float(width) / float(realWidth); short newHeight = (short)(realHeight * ratio); bufferPtr = bufferOut + ((height - newHeight)/2) * pixelsPerLine; height = newHeight; } // Reserve an intermediate buffer short* pixToTile; int tileWidth = FLOAT_TO_LONG(float(TILE_WIDTH) * ratio); FastAllocArray(pixToTile, short, tileWidth); if (pixToTile == NULL) { // If not enough space available to Toolkit => fill with background color and quit Pixel* bufferLine = bufferPtr; for (j = 0; j < height; ++j, bufferLine += pixelsPerLine) { bufferPtr = bufferLine; for (i = 0; i < width; ++i, ++bufferPtr) *bufferPtr = BACKGROUND; } return FPX_MEMORY_ALLOCATION_FAILED; } // pixToTile will contains the pixels' positions to put into the new rectangle for (i = 0; i < tileWidth; ++i) pixToTile[i] = short(float(i) / ratio + 0.01); // Declare and init some variables before the main loop... int heightOfBuffer, widthOfBuffer; // Width and height to be written for each bloc int yBloc = 0; // Top coordinate in the resolution level int topInBuffer = 0; // Top coordinate in the buffer PTile* tile = tiles; // Pointer to the current bloc of the resolution level // Loop on the height for (short hBloc = 0; hBloc < nbTilesH; ++hBloc) { int xBloc = 0; // Left coordinate in the resolution level int leftInBuffer = 0; // Left coordinate in the buffer // Loop on the width for (short lBloc = 0; lBloc < nbTilesW; ++lBloc) { // Bloc Initialisation status = tile->Read(); if (status != FPX_OK) { // if error reading data => fill with background color and quit Pixel* bufferLine = bufferPtr; for (j = 0; j < height; ++j, bufferLine += pixelsPerLine) { bufferPtr = bufferLine; for (i = 0; i < width; ++i, bufferPtr++) *bufferPtr = BACKGROUND; } FastDeleteArray(pixToTile,short); return status; } // Compute the height and width of the tile to be read heightOfBuffer = FLOAT_TO_LONG(float(tile->height) * ratio); widthOfBuffer = FLOAT_TO_LONG(float(tile->width) * ratio); if (heightOfBuffer + topInBuffer > height) heightOfBuffer = height - topInBuffer; if (widthOfBuffer + leftInBuffer > width) widthOfBuffer = width - leftInBuffer; // Position the pointer to the first pixel to be written Pixel* bufferLine = bufferPtr + (topInBuffer * pixelsPerLine + leftInBuffer); for (j = 0; j < heightOfBuffer; ++j) { // Position a pointer to the first pixel to be read Pixel* pixelPtr = tile->pixels + (pixToTile[j] * tile->width); // Copy pixels with sampling for (i = 0; i < widthOfBuffer; ++i) bufferLine[i] = pixelPtr[pixToTile[i]]; // Take channel combinaison into account if (combinaisonMatrix) { for (i = 0; i < widthOfBuffer; ++i) bufferLine[i] = (*combinaisonMatrix)(bufferLine[i]); } // Take LUT into account if (correctLut) { for (i = 0; i < widthOfBuffer; ++i) bufferLine[i] = (*correctLut)(bufferLine[i]); } // Take alpha channel into account if (useAlphaChannel && PTile::invertLUT) { short alpha, beta; unsigned char* sPix; unsigned char* dPix; int index; for (i = 0; i < widthOfBuffer; ++i) { sPix = (unsigned char*)(bufferLine + i); dPix = (unsigned char*)(&BACKGROUND); alpha = (short)(*(sPix + alphaOffset)); beta = (short)(PTile::invertLUT[alpha]); if (!alpha) bufferLine[i] = BACKGROUND; else if (alpha < 0xFF) { if (premultiplied) for (index = 4; index; --index, ++dPix, ++sPix) *sPix = (unsigned char)(*dPix*beta/0xFF + *sPix); else for (index = 4; index; --index, ++dPix, ++sPix) *sPix = (unsigned char)((*dPix*beta + *sPix*alpha)/0xFF); } // else if (alpha == 0xFF) bufferLine[i] is unchanged } } // Next line to be written bufferLine += pixelsPerLine; } xBloc += tile->width; // Increment left coordinate in the resolution level leftInBuffer += widthOfBuffer; // Increment left coordinate in the buffer ++tile; // Next tile } yBloc += tile->height; // Increment top coordinate in the resolution level topInBuffer += heightOfBuffer; // Increment top coordinate in the buffer } FastDeleteArray(pixToTile, short); return status; } // ---------------------------------------------------------------------------- // External Functions // ---------------------------------------------------------------------------- // - EOF ----------------------------------------------------------------------