ultimatepp/bazaar/PixRaster/PixRaster.cpp
micio a74e1468c9 PixRaster : updated Leptonica library to version 1.65
git-svn-id: svn://ultimatepp.org/upp/trunk@2598 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2010-08-07 23:38:03 +00:00

1355 lines
30 KiB
C++

#include "PixRaster.h"
NAMESPACE_UPP
// used in PIX file I/O
enum {
READ_24_BIT_COLOR = 0, /* read in as 24 (really 32) bit pix */
CONVERT_TO_PALETTE = 1, /* convert to 8 bit colormapped pix */
READ_GRAY = 2 /* read gray only */
};
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Pix class wrapping Leptonica PIX image
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// internal destructor
void Pix::Destroy()
{
// destroys underlying PIX
if(pix)
pixDestroy(&pix);
// frees format and palette
if(rasterFormat)
{
delete rasterFormat;
rasterFormat = NULL;
}
if(localPalette)
{
delete[] localPalette;
localPalette = NULL;
}
markers.Clear();
} // END Pix::Destroy()
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// sets raster format depending on current page's pix format
void Pix::SetRasterFormat()
{
// removes old format for page
if (rasterFormat)
{
delete rasterFormat;
rasterFormat = NULL;
}
if(IsEmpty())
return;
rasterFormat = new RasterFormat;
switch (pixGetDepth(pix))
{
case 1:
rasterFormat->Set1mf();
break;
case 2:
rasterFormat->Set2mf();
break;
case 4:
rasterFormat->Set4mf();
break;
case 8:
rasterFormat->Set8();
break;
case 16:
// Upp does 16bpp color, Leptonica does 16bpp grayscale
// MakeRGBA() will fail converting from Leptonica format anyways
// we should add a 16bpp grayscale to Upp
// in the meanwhile 16 bit Leptonica are converted to RGBA
rasterFormat->Set32be(
0x000000FF << L_RED_SHIFT,
0x000000FF << L_GREEN_SHIFT,
0x000000FF << L_BLUE_SHIFT
);
break;
case 24:
rasterFormat->Set24be(
0x000000FF << L_RED_SHIFT,
0x000000FF << L_GREEN_SHIFT,
0x000000FF << L_BLUE_SHIFT
);
break;
case 32:
rasterFormat->Set32be(
0x000000FF << L_RED_SHIFT,
0x000000FF << L_GREEN_SHIFT,
0x000000FF << L_BLUE_SHIFT
);
break;
default:
NEVER();
} // switch
} // END Pix::SetRasterFormat()
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// synthesyze grayscale palettes
void Pix::CreateGrayPalette2()
{
if (localPalette)
{
delete[] localPalette;
localPalette = NULL;
}
if (IsEmpty())
return;
localPalette = new RGBA[2];
*(dword *)localPalette = 0xFFFFFFFF;
*((dword *)localPalette + 1) = 0xFF000000;
} // END Pix::CreateGrayPalette2()
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Pix::CreateGrayPalette4()
{
if (localPalette)
{
delete[] localPalette;
localPalette = NULL;
}
if (IsEmpty())
return;
localPalette = new RGBA[4];
*(dword *)localPalette = 0xFF0000;
*((dword *)localPalette + 1) = 0xFF555555;
*((dword *)localPalette + 2) = 0xFFAAAAAA;
*((dword *)localPalette + 3) = 0xFFFFFFFF;
} // END Pix::CreateGrayPalette4()
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Pix::CreateGrayPalette16()
{
if (localPalette)
{
delete[] localPalette;
localPalette = NULL;
}
if (IsEmpty())
return;
localPalette = new RGBA[16];
dword *palPnt = (dword *)localPalette;
for (dword i = 0; i < 16; i++)
*palPnt++ = i << 4 | i << 12 | i << 20 | 0xff000000;
} // END Pix::CreateGrayPalette16()
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Pix::CreateGrayPalette256()
{
if (localPalette)
{
delete[] localPalette;
localPalette = NULL;
}
if (IsEmpty())
return;
localPalette = new RGBA[256];
dword *palPnt = (dword *)localPalette;
dword val;
for (dword i = 0; i < 256; i++)
{
val = (255 * i) / 255;
*palPnt++ = val | val << 8 | val << 16 | 0xff000000;
}
} // END Pix::CreateGrayPalette256()
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// convert PIX palette
void Pix::ConvertPIXPalette(PIXCMAP *colormap)
{
int iColor, numColors;
l_int32 rval, gval, bval;
RGBA *palPnt;
if (localPalette)
{
delete[] localPalette;
localPalette = NULL;
}
if (IsEmpty())
return;
// get number of entries in colormap
numColors = pixcmapGetCount(colormap);
if (numColors > 256)
numColors = 256;
localPalette = new RGBA[numColors];
// convert and copy it to local palette
palPnt = localPalette;
for (iColor = 0; iColor < numColors; iColor++)
{
pixcmapGetColor(colormap, iColor, &rval, &gval, &bval);
palPnt->a = 255;
palPnt->r = (byte)rval;
palPnt->g = (byte)gval;
palPnt->b = (byte)bval;
palPnt++;
}
} // END Pix::ConvertPIXPalette()
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// loads Pix from another raster object
void Pix::Load(Raster& raster, bool deepCopy, int page)
{
PixBase *pixBase;
Destroy();
// shortcut if raster is a pixRaster
Raster::Info info = raster.GetInfo();
int width = raster.GetWidth();
// check whether we're loading from a PixBase derived raster
// the process don't require conversion then
pixBase = dynamic_cast<PixBase *>(&raster);
if (pixBase)
{
pix = pixBase->GetPIX(page);
if(!pix)
return;
if(deepCopy)
pix = pixCopy(NULL, pix);
else
pix = pixClone(pix);
return;
}
// not a PixRaster, we should go the slow way
// stores old active page, we need to change it
int oldPage = raster.GetActivePage();
// gets current page on source raster
raster.SeekPage(page);
// gets information from source object
const RasterFormat *format = raster.GetFormat();
// convert source image to PIX
if (!format)
{
// null RasterFormat -- standard Upp RGBA
LoadRASTER_RGBA(raster);
}
else
{
switch (format->GetType())
{
case RASTER_1:
LoadRASTER_1(raster);
break;
case RASTER_1 | RASTER_MSBFIRST:
LoadRASTER_1_MSBFIRST(raster);
break;
case RASTER_2:
LoadRASTER_2(raster);
break;
case RASTER_2 | RASTER_MSBFIRST:
LoadRASTER_2_MSBFIRST(raster);
break;
case RASTER_4:
LoadRASTER_4(raster);
break;
case RASTER_4 | RASTER_MSBFIRST:
LoadRASTER_4_MSBFIRST(raster);
break;
case RASTER_8:
case RASTER_8 | RASTER_MSBFIRST:
LoadRASTER_8(raster);
break;
case RASTER_8ALPHA:
case RASTER_8ALPHA | RASTER_MSBFIRST:
LoadRASTER_8ALPHA(raster);
break;
case RASTER_16:
LoadRASTER_16(raster);
break;
case RASTER_16 | RASTER_MSBFIRST:
LoadRASTER_16_MSBFIRST(raster);
break;
case RASTER_24:
LoadRASTER_24(raster);
break;
case RASTER_24 | RASTER_MSBFIRST:
LoadRASTER_24_MSBFIRST(raster);
break;
case RASTER_32:
case RASTER_32ALPHA:
case RASTER_32PREMULTIPLIED:
LoadRASTER_32(raster);
break;
case RASTER_32 | RASTER_MSBFIRST:
case RASTER_32ALPHA | RASTER_MSBFIRST:
case RASTER_32PREMULTIPLIED | RASTER_MSBFIRST:
LoadRASTER_32_MSBFIRST(raster);
break;
default:
NEVER();
} // switch
}
// if source raster has a palette, create a corresponding
// PIXCMAP and fill it
const RGBA *palette = raster.GetPalette();
int palCount = raster.GetPaletteCount(); // needed because of bug of png plugin
if (palette && palCount)
{
int bpp = raster.GetInfo().bpp;
PIXCMAP *colorTable = pixcmapCreate(bpp);
palCount = min(1 << bpp, palCount);
for (int iPal = 0; iPal < palCount; iPal++)
{
pixcmapAddColor(colorTable, palette->r, palette->g, palette->b);
palette++;
}
pixSetColormap(pix, colorTable);
}
// gets physical resolution from source raster pys dimensions, if any
int dotX = raster.GetInfo().dots.cx;
int dotY = raster.GetInfo().dots.cy;
int resX, resY;
if (dotX)
resX = iscale(600, raster.GetWidth(), dotX);
else
resX = 0;
if (dotY)
resY = iscale(600, raster.GetHeight(), dotY);
else
resY = 0;
pixSetXRes(pix, resX);
pixSetYRes(pix, resY);
// restores old page on source raster
raster.SeekPage(oldPage);
} // END Pix::Load()
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// empty constructor -- sets NULL PIX
Pix::Pix()
{
pix = NULL;
rasterFormat = NULL;
localPalette = NULL;
markers.Clear();
} // END Pix::Pix()
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// creates a PIX in given format and size
Pix::Pix(int width, int height, int depth, RGBA *colorTable)
{
pix = pixCreate(width, height, depth);
if(colorTable)
{
NEVER(); // FIXME-- Convert color table to PIX format
}
rasterFormat = NULL;
localPalette = NULL;
markers.Clear();
} // END Pix::Pix()
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// constructor -- takes a Leptonica PIX
// TAKES OWNERSHIP of underlying PIX object which is NULLed
Pix::Pix(PIX **_pix)
{
pix = *_pix;
*_pix = NULL;
rasterFormat = NULL;
localPalette = NULL;
markers.Clear();
} // END Pix::Pix()
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// copy constructor -- reference increments underlying PIX
Pix::Pix(Pix const &_pix)
{
pix = pixClone((Pix &)_pix);
rasterFormat = NULL;
localPalette = NULL;
markers <<= _pix.markers;
} // END Pix::Pix()
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// deep copy constructor -- deep copy of underlying PIX
Pix::Pix(Pix const &_pix, int i)
{
pix = pixCopy(NULL, (Pix &)_pix);
rasterFormat = NULL;
localPalette = NULL;
markers <<= _pix.markers;
} // END Pix::Pix()
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// creation of Pix from a raster object
Pix::Pix(Raster &raster, bool deepCopy, int page)
{
pix = NULL;
Load(raster, deepCopy, page);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// creation of Pix from file/stream
Pix::Pix(FileIn &fs, int page)
{
pix = NULL;
Load(fs, page);
}
Pix::Pix(String const &fileName, int page)
{
pix = NULL;
Load(fileName, page);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// destructor
Pix::~Pix()
{
Destroy();
} // END Pix::~Pix()
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// assignment -- increment reference of underlying PIX
Pix &Pix::operator=(Pix &_pix)
{
Destroy();
if(!_pix)
return *this;
pix = pixClone(_pix);
rasterFormat = NULL;
localPalette = NULL;
markers <<= _pix.markers;
return *this;
} // END Pix::operator=()
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// deep copy -- deep copies underlying PIX
Pix &Pix::operator <<=(Pix &_pix)
{
Destroy();
if(!_pix)
return *this;
pix = pixCopy(NULL, _pix);
rasterFormat = NULL;
localPalette = NULL;
markers <<= _pix.markers;
return *this;
} // END Pix::operator <<=()
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
Pix &Pix::DeepCopy(Pix &_pix)
{
Destroy();
if(!_pix)
return *this;
pix = pixCopy(NULL, _pix);
rasterFormat = NULL;
localPalette = NULL;
markers <<= _pix.markers;
return *this;
} // END Pix::DeepCopy()
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// standard Raster functions -- they operate on active page
Size Pix::GetSizeEx(int)
{
Size sz;
pixGetDimensions(pix, &sz.cx, &sz.cy, NULL);
return sz;
} // END Pix::GetSizeEx()
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
Raster::Info Pix::GetInfoEx(int)
{
Raster::Info info;
memset(&info, sizeof(info), 0);
if (IsEmpty())
return Raster::Info();
// image dimensions from pixel sizes and resolution
info.bpp = pixGetDepth(pix);
int width = pixGetWidth(pix);
int height = pixGetHeight(pix);
int xRes = pixGetXRes(pix);
int yRes = pixGetYRes(pix);
if (xRes)
info.dots.cx = iscale(width, 600, xRes);
else
info.dots.cx = 0;
if (yRes)
info.dots.cy = iscale(height, 600, yRes);
else
info.dots.cy = 0;
// image kind -- Leptonica just handles opaque images
info.kind = IMAGE_OPAQUE;
// number of colors
if (pixGetColormap(pix))
info.colors = pixcmapGetCount(pixGetColormap(pix));
else
info.colors = 1 << pixGetDepth(pix);
return info;
} // END Pix::GetInfoEx()
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
Raster::Line Pix::GetLineEx(int line, int)
{
// empty line on empty image
if (IsEmpty())
return Raster::Line();
// if line out of bounds, return empty line
if (line < 0 || line >= pixGetHeight(pix))
return Raster::Line();
// gets PIX bpp -- we must handle special case for 16bpp grayscale
// which don't have an Upp counterpart
// as a side problem, for 16 bit grayscaled BPP we must precalculate
// both raw and RGBA data
if (pixGetDepth(pix) == 16)
{
// we return here an RGBA buffer filled with
// MSBs from PIX
dword mask;
byte shift;
dword grayVal;
// gets image width
int width = pixGetWidth(pix);
// allocates an RGBA buffer for data
RGBA *rgba = new RGBA[width];
RGBA *rgbaPtr = rgba;
l_uint32 *pixPtr = pixGetData(pix) + line * pixGetWpl(pix);
for (int iPix = 0, mask = 0xFFFF0000, shift = 16; iPix < width; iPix++)
{
grayVal = ((*pixPtr & mask) >> shift) >> 4;
*(dword *)rgbaPtr++ = grayVal | (grayVal << 8) | (grayVal << 16);
mask >>= 16;
shift -= 16;
if (!mask)
{
mask = 0xFFFF0000;
shift = 16;
pixPtr++;
}
}
return Raster::Line((byte *)rgba, this, true);
}
// normal case, we use RasterFormat's converting support
// BUT, for LE machines we must re-swap bytes inside words
// to reverse the weird Leptonica mechanics
int Wpl = pixGetWpl(pix);
byte *pixData = (byte *)(pixGetData(pix) + line * Wpl);
#ifdef L_LITTLE_ENDIAN
byte *pixPtr = pixData;
byte *fmtData = new byte[Wpl*4];
byte *fmtPtr = fmtData;
for (int iDWord = 0; iDWord < Wpl; iDWord++)
{
*fmtPtr++ = *(pixPtr + 3);
*fmtPtr++ = *(pixPtr + 2);
*fmtPtr++ = *(pixPtr + 1);
*fmtPtr++ = *(pixPtr + 0);
pixPtr += 4;
}
Raster::Line l(fmtData, this, true);
#else
Raster::Line l(pixData, this, false);
#endif
return l;
} // END Pix::GetLineEx()
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
int Pix::GetPaletteCountEx(int)
{
PIXCMAP *colormap;
int palCount;
int bpp;
if (IsEmpty())
return 0;
// get current pix's depth
bpp = pixGetDepth(pix);
// we must handle un-paletted PIX grayscale images
// so, in that case, we use one of 4 predefined grayscale palettes
colormap = pixGetColormap(pix);
if (!colormap)
if (bpp <= 8)
palCount = 1 << bpp;
else
palCount = 0;
else
palCount = pixcmapGetCount(colormap);
return palCount;
} // END Pix::GetPaletteCountEx()
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
const RGBA *Pix::GetPaletteEx(int)
{
PIXCMAP *colormap;
int bpp;
if (IsEmpty())
return NULL;
// if palette is up to date, just return it
if(localPalette)
return localPalette;
// get current pix's depth
bpp = pixGetDepth(pix);
// we must handle un-paletted PIX grayscale images
// so, in that case, we use one of 4 predefined grayscale palettes
colormap = pixGetColormap(pix);
if (!colormap || bpp == 1 /* 1bpp PIXs seems not care of colormap.... */)
{
switch (bpp)
{
case 1:
CreateGrayPalette2();
break;
case 2:
CreateGrayPalette4();
break;
case 4:
CreateGrayPalette16();
break;
case 8:
CreateGrayPalette256();
break;
default:
break;
}
}
else
{
// convert PIX palette
ConvertPIXPalette(colormap);
}
return localPalette;
} // END Pix::GetPaletteEx()
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
const RasterFormat *Pix::GetFormatEx(int)
{
if(!rasterFormat)
SetRasterFormat();
return rasterFormat;
} // END Pix::GetFormatEx()
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// file I/O
bool Pix::Load(FileIn &fs, int page)
{
int format;
#ifdef WIN32
HANDLE fh;
#else
int fh;
#endif
Destroy();
fh = fs.GetHandle();
if (!fh)
return false;
FILE *fp = fdopen(fh, "r");
if(!fp)
return false;
if(findFileFormat(fp, &format))
{
fclose(fp);
return false;
}
switch (format)
{
case IFF_BMP:
if (page || (pix = pixReadStreamBmp(fp)) == NULL )
{
fclose(fp);
return false;
}
pixSetInputFormat(pix, format);
break;
case IFF_JFIF_JPEG:
if (page || (pix = pixReadStreamJpeg(fp, READ_24_BIT_COLOR, 1, NULL, 0)) == NULL)
{
fclose(fp);
return false;
}
pixSetInputFormat(pix, format);
break;
case IFF_PNG:
if (page || (pix = pixReadStreamPng(fp)) == NULL)
{
fclose(fp);
return false;
}
pixSetInputFormat(pix, format);
break;
case IFF_TIFF:
case IFF_TIFF_PACKBITS:
case IFF_TIFF_RLE:
case IFF_TIFF_G3:
case IFF_TIFF_G4:
case IFF_TIFF_LZW:
case IFF_TIFF_ZIP:
// read requested page
if ((pix = pixReadStreamTiff(fp, page)) == NULL)
{
fclose(fp);
return false;
}
pixSetInputFormat(pix, format);
break;
case IFF_PNM:
if (page || (pix = pixReadStreamPnm(fp)) == NULL)
{
fclose(fp);
return false;
}
pixSetInputFormat(pix, format);
break;
case IFF_GIF:
if (page || (pix = pixReadStreamGif(fp)) == NULL)
{
fclose(fp);
return false;
}
pixSetInputFormat(pix, format);
break;
case IFF_UNKNOWN:
fclose(fp);
return false;
break;
}
fclose(fp);
return true;
} // END Pix::Load()
bool Pix::Load(String fileName, int page)
{
FileIn f(fileName);
return Load(f, page);
} // END Pix::Load()
bool Pix::Save(String fileName, int quality, bool progressive) // @@ to do - add compression and fine control
{
// gets file extension
String fileExt = ToUpper(fileName.Right(4));
int format;
if(fileExt == ".JPG")
format = IFF_JFIF_JPEG;
else if(fileExt == ".PNG")
format = IFF_PNG;
else if(fileExt == ".TIF")
format = IFF_TIFF;
else if(fileExt == ".BMP")
format = IFF_BMP;
else if(fileExt == ".PNM")
format = IFF_PNM;
else if(fileExt == ".PS")
format = IFF_PS;
else if(fileExt == ".GIF")
format = IFF_GIF;
else // still unsupported formats
{
format = IFF_UNKNOWN;
return false;
}
if(format == IFF_JFIF_JPEG)
return pixWriteJpeg(fileName, pix, quality, progressive ? 1 : 0) == 0;
else
return pixWrite(fileName, pix, format) == 0;
} // END Pix::Save()
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////// PixRaster PRIVATE/PROTECTED /////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// gets real page
int PixRaster::getTruePage(int page)
{
// if error page, throw exception
// shouldn't happen, but....
if (page == PIXRASTER_INVALID_PAGE)
NEVER();
// if empty raster, returns INVALID_PAGE
else
if (IsEmpty() )
return 0;
// special value for current page
else
if (page == PIXRASTER_CURPAGE)
return curPage;
// special value for last page
else
if (page == PIXRASTER_LASTPAGE)
return pages.GetCount() - 1;
// negative values mean back offset from last page
else
if (page < 0)
{
page = pages.GetCount() - 1 + page;
if (page < 0)
page = 0;
return page;
}
else
if (page >= pages.GetCount())
return pages.GetCount() - 1;
else
return page;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// gets PIX from raster
// warning -- object references are NOT changed
// so objects must NOT be destroyed
PIX *PixRaster::GetPIX(int page)
{
if (IsEmpty())
return NULL;
page = getTruePage(page);
return At(page).GetPIX();
} // END PixRaster::GetPix()
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////// PixRaster PUBLIC ////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// loads / appends Pix from another raster object
void PixRaster::Load(Raster& raster, bool Append, bool deepCopy)
{
if(!Append)
pages.Clear();
for(int page = 0; page < raster.GetPageCount(); page++)
pages.Add(new Pix(raster, deepCopy, page));
} // END PixRaster::Load()
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// constructor -- empty raster
PixRaster::PixRaster()
{
curPage = 0;
} // END Constructor class PixRaster
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
// constructor -- takes a Leptonica Pix
// PixRaster TAKES OWNERSHIP of underlying PIX object which is NULLed
PixRaster::PixRaster(PIX **pix)
{
pages.Add(new Pix(pix));
// sets the current page
curPage = 0;
} // END Constructor class PixRaster
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// constructor -- takes an array of Leptonica Pix
// PIXA gets destroyed and NULLed
PixRaster::PixRaster(PIXA **pixa)
{
PIX *pix;
curPage = 0;
if(!pixa || !*pixa)
return;
for(int i = 0; i < pixaGetCount(*pixa); i++)
{
pix = pixaGetPix(*pixa, i, L_CLONE);
pages.Add(new Pix(&pix));
}
pixaDestroy(pixa);
} // END Constructor class PixRaster
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// destructor
PixRaster::~PixRaster()
{
} // END Destructor class PixRaster
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
void PixRaster::SeekPage(int page)
{
if (IsEmpty())
return;
// gets true page number
page = getTruePage(page);
curPage = page;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
int PixRaster::GetPageCount()
{
return pages.GetCount();
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
int PixRaster::GetActivePage()
{
return curPage;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
Size PixRaster::GetSizeEx(int page)
{
// if empty raster, returns a zero size
if (IsEmpty())
return Size(0,0);
// gets true page number
page = getTruePage(page);
return At(page).GetSize();
} // END PixRaster::GetSizeEx()
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
Raster::Info PixRaster::GetInfoEx(int page)
{
if (IsEmpty())
return Raster::Info();
// gets true page number
page = getTruePage(page);
return At(page).GetInfo();
} // END PixRaster::GetInfoEx()
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
Raster::Line PixRaster::GetLineEx(int line, int page)
{
// empty line on empty image
if (IsEmpty())
return Raster::Line();
// gets true page number
page = getTruePage(page);
return At(page).GetLine(line);
} // END PixRaster::GetLineEx()
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
int PixRaster::GetPaletteCountEx(int page)
{
// no palette on empty image
if (IsEmpty())
return 0;
// gets true page number
page = getTruePage(page);
return At(page).GetPaletteCount();
} // END PixRaster::GetPaletteCountEx()
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
const RGBA *PixRaster::GetPaletteEx(int page)
{
// no palette on empty image
if (IsEmpty())
return 0;
// gets true page number
page = getTruePage(page);
return At(page).GetPalette();
} // END PixRaster::GetPaletteEx()
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
const RasterFormat *PixRaster::GetFormatEx(int page)
{
if (IsEmpty())
return NULL;
// gets true page number
page = getTruePage(page);
return At(page).GetFormat();
} // END PixRaster::GetFormatEx()
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// read page polymarkers
Markers *PixRaster::GetMarkersEx(int page)
{
if (IsEmpty())
return NULL;
// gets true page number
page = getTruePage(page);
return At(page).GetMarkers();
} // END PixRaster::GetPolyMarkersEx()
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// sets PIX and PIX array
void PixRaster::Set(Pix &pix, int page, bool deepCopy)
{
if (IsEmpty())
return;
page = getTruePage(page);
if(deepCopy)
pages.At(page) <<= pix;
else
pages.At(page) = pix;
} // END PixRaster::Set()
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// adds a PIX or a PIX array
void PixRaster::Add(Pix &pix, bool deepCopy)
{
if(deepCopy)
pages.Add(new Pix(pix, 1));
else
pages.Add(new Pix(pix));
} // END PixRaster::Add()
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
void PixRaster::Add(PixRaster &pixr, bool deepCopy)
{
for(int i = 0; i < pixr.GetPageCount(); i++)
{
if(deepCopy)
pages.Add(new Pix(pixr[i], 1));
else
pages.Add(new Pix(pixr[i]));
}
} // END PixRaster::Add()
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// inserts a PIX or a PIX array
void PixRaster::Insert(Pix &pix, int where, bool deepCopy)
{
// if adding at end, just append
if (where == PIXRASTER_END || !GetPageCount())
{
Add(pix, deepCopy);
return;
}
// gets true page
where = getTruePage(where);
// insert pix into pixa array
if(deepCopy)
pages.Insert(where, new Pix(pix, 1));
else
pages.Insert(where, new Pix(pix));
} // END PixRaster::Insert()
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
void PixRaster::Insert(PixRaster &pixr, int where, bool deepCopy)
{
// if adding at end, just append
if (where == PIXRASTER_END || !GetPageCount())
{
Add(pixr, deepCopy);
return;
}
// gets true page
where = getTruePage(where);
for (int i = 0; i < pixr.GetPageCount(); i++)
{
if(deepCopy)
pages.Insert(where, new Pix(pixr[i], 1));
else
pages.Insert(where, new Pix(pixr[i]));
where++;
}
} // END PixRaster::Insert()
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// removes a Pix or a series of Pix
void PixRaster::Remove(int where, int count)
{
if (IsEmpty())
return;
if (where == PIXRASTER_END)
where = GetPageCount() - 1;
where = getTruePage(where);
if (GetPageCount() - where < count)
count = GetPageCount() - where;
pages.Remove(where, count);
} // END PixRaster::Remove()
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// duplicates a page at the end of array (useful for stack-like operations)
Pix &PixRaster::Dup(int page)
{
// if raster empty, creates an empty Pix
if (IsEmpty())
{
pages.Add(new Pix);
return pages[0];
}
if (page == PIXRASTER_END)
page = GetPageCount() - 1;
page = getTruePage(page);
Pix *pix = new Pix(pages[page], 1);
pages.Add(pix);
SeekPage(PIXRASTER_LASTPAGE);
return *this;
} // END PixRaster::Dup()
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Drops last page(s) of array (ditto)
void PixRaster::Drop(int count)
{
if (IsEmpty())
return;
int start = GetPageCount() - count;
if (start < 0)
{
count += start;
start = 0;
}
Remove(start, count);
SeekPage(PIXRASTER_LASTPAGE);
} // END PixRaster::Drop()
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// array access
Pix &PixRaster::At(int page)
{
ASSERT(!IsEmpty());
page = getTruePage(page);
return pages[page];
} // END PixRaster::At()
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// File I/O operations
bool PixRaster::Load(FileIn &fs, bool Append)
{
// if not appending, destroy actual content
if(!Append)
pages.Clear();
int page = 0;
Pix *pix = new Pix(fs, page);
if(!pix)
return false;
while(pix)
{
pages.Add(pix);
page++;
pix = new Pix(fs, page);
}
return true;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool PixRaster::Load(String fileName, bool Append)
{
FileIn f(fileName);
return Load(f, Append);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool PixRaster::Save(String fileName, int page) // @@ to do - add compression and type handling
{
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool PixRaster::SaveAll(String fileName)
{
}
END_UPP_NAMESPACE