void PLFilterGetAlpha::Apply(PLBmpBase * pBmpSource, PLBmp * pBmpDest) const { // Only works for 32 bpp bitmaps. PLASSERT (pBmpSource->GetBitsPerPixel() == 32); PLASSERT (pBmpSource->HasAlpha()); pBmpDest->Create (pBmpSource->GetWidth(), pBmpSource->GetHeight(), PLPixelFormat::L8, NULL, 0, pBmpSource->GetResolution()); PLPixel32 ** pSrcLines = pBmpSource->GetLineArray32(); PLBYTE ** pDstLines = pBmpDest->GetLineArray(); for (int y = 0; y<pBmpDest->GetHeight(); ++y) { // For each line PLPixel32 * pSrcPixel = pSrcLines[y]; PLBYTE * pDstPixel = pDstLines[y]; for (int x = 0; x < pBmpDest->GetWidth(); ++x) { // For each pixel *pDstPixel = pSrcPixel->GetA(); ++pSrcPixel; ++pDstPixel; } } }
void PLFilterResizeBilinear::Apply(PLBmpBase * pBmpSource, PLBmp * pBmpDest) const { PLASSERT(pBmpSource->GetBitsPerPixel()==32 || pBmpSource->GetBitsPerPixel()==24); // Create a new Bitmap pBmpDest->Create(m_NewXSize, m_NewYSize, pBmpSource->GetPixelFormat(), NULL, 0, pBmpSource->GetResolution()); // Create a Filter Class from template PLBilinearContribDef f(0.64); if (pBmpSource->GetBitsPerPixel() == 32) { C2PassScale <CDataRGBA_UBYTE> sS(f); sS.Scale ((CDataRGBA_UBYTE::_RowType *) pBmpSource->GetLineArray(), pBmpSource->GetWidth(), pBmpSource->GetHeight(), (CDataRGBA_UBYTE::_RowType *) pBmpDest->GetLineArray(), pBmpDest->GetWidth(), pBmpDest->GetHeight()); } else { C2PassScale <CDataRGB_UBYTE> sS(f); sS.Scale ((CDataRGB_UBYTE::_RowType *) pBmpSource->GetLineArray(), pBmpSource->GetWidth(), pBmpSource->GetHeight(), (CDataRGB_UBYTE::_RowType *) pBmpDest->GetLineArray(), pBmpDest->GetWidth(), pBmpDest->GetHeight()); } }
void PLFilterThreshold::Apply(PLBmpBase * pBmpSource, PLBmp * pBmpDest) const { int threshold_min = m_threshold_min; int threshold_max = m_threshold_max; int channel = m_channel; // Only works for 32 bpp bitmaps at the moment. PLASSERT (pBmpSource->GetBitsPerPixel() == 32); pBmpDest->Create (pBmpSource->GetWidth(), pBmpSource->GetHeight(), PLPixelFormat::L8, NULL, 0, pBmpSource->GetResolution()); PLBYTE ** pSrcLines = pBmpSource->GetLineArray(); PLBYTE ** pDstLines = pBmpDest->GetLineArray(); for (int y = 0; y<pBmpDest->GetHeight(); ++y) { // For each line PLBYTE * pSrcPixel = pSrcLines[y]; PLBYTE * pDstPixel = pDstLines[y]; for (int x = 0; x < pBmpDest->GetWidth(); ++x) { // For each pixel if ((PLBYTE (pSrcPixel[channel]) <= PLBYTE (threshold_min)) || (PLBYTE (pSrcPixel[channel]) >= PLBYTE(threshold_max))) *pDstPixel = 0; else *pDstPixel = pSrcPixel[channel]; pSrcPixel += sizeof(PLPixel32); ++pDstPixel; } } }
void PLWinBmp::AlphaBlt (PLWinBmp * pSrPLBmp, int x, int y) // Do a bitblt using the alpha channel of pSrPLBmp. // Legacy routine. Should not be used. { PLASSERT_VALID (this); PLASSERT (GetBitsPerPixel() == 32); PLASSERT_VALID (pSrPLBmp); // Overlay picture int DestLineLen = GetWidth()*4; int SrcLineLen = pSrPLBmp->GetBytesPerLine(); PLPixel32 * pPal = pSrPLBmp->GetPalette(); // Perform clipping. int maxy = min (pSrPLBmp->GetHeight(), GetHeight()-y); int maxx = min (pSrPLBmp->GetWidth(), GetWidth()-x); int miny = max (0,-y); int minx = max (0,-x); if (pSrPLBmp->HasAlpha()) { int alpha, negalpha; for (int sy = miny; sy<maxy; sy++) { // For each line BYTE * pDest = m_pBits+DestLineLen*(y+sy)+x*4; BYTE * pSrc = pSrPLBmp->m_pBits+SrcLineLen*sy; for (int sx = minx; sx<maxx; sx++) { // For each pixel if (pPal) { BYTE * pPixel = (BYTE *)&(pPal[*pSrc]); alpha = pPixel[3]; negalpha = 255-alpha; pDest[0] = (pDest[0]*negalpha+pPixel[0]*alpha)>>8; pDest[1] = (pDest[1]*negalpha+pPixel[1]*alpha)>>8; pDest[2] = (pDest[2]*negalpha+pPixel[2]*alpha)>>8; pSrc++; } else { alpha = pSrc[3]; negalpha = 255-alpha; pDest[0] = (pDest[0]*negalpha+pSrc[0]*alpha)>>8; pDest[1] = (pDest[1]*negalpha+pSrc[1]*alpha)>>8; pDest[2] = (pDest[2]*negalpha+pSrc[2]*alpha)>>8; pSrc += 4; } pDest += 4; } }
void PLDIBSection::AssertValid () const { // call inherited PLASSERT_VALID first PLWinBmp::AssertValid(); // Bitmap must exist PLASSERT (m_hBitmap); }
// the actual data buffer is allocated in the derived classes void PLDataSink::Open ( const char * pszName, PLBYTE* pData, size_t MaxFileSize ) { // Data source may not be open already! PLASSERT (! m_pStartData); PLASSERT (MaxFileSize > 0); m_nMaxFileSize = MaxFileSize; // unchecked memory allocation, here! m_pszName = new char [strlen (pszName)+1]; strcpy (m_pszName, pszName); m_pStartData = pData; m_nCurPos = 0; #ifdef _WIN32 m_bNameIsWide = false; #endif }
void PLDataSink::OpenW ( const wchar_t * pszwName, PLBYTE* pData, size_t MaxFileSize ) { // Data source may not be open already! PLASSERT (! m_pStartData); PLASSERT (MaxFileSize > 0); m_nMaxFileSize = MaxFileSize; // unchecked memory allocation, here! m_pszwName = new wchar_t [wcslen (pszwName)+1]; m_pszName = new char[strlen("Wide")+1]; strcpy(m_pszName,"Wide"); wcscpy (m_pszwName, pszwName); m_pStartData = pData; m_nCurPos = 0; m_bNameIsWide = true; }
void PLDataSource::OpenW ( const wchar_t * pszwName, int FileSize ) { // Data source may not be open already! PLASSERT (!m_FileSize); m_pszwName = new wchar_t [wcslen (pszwName)+1]; wcscpy (m_pszwName, pszwName); m_pszName = new char[strlen("Wide")+1]; strcpy(m_pszName,"Wide"); m_FileSize = FileSize; m_BytesRead = 0; m_bNameIsWide = true; }
void PLDataSource::Open ( const char * pszName, int FileSize ) { // Data source may not be open already! PLASSERT (!m_FileSize); m_pszName = new char [strlen (pszName)+1]; strcpy (m_pszName, pszName); m_FileSize = FileSize; m_BytesRead = 0; #ifdef _WIN32 m_bNameIsWide = false; #endif }
void PLTIFFDecoder::Open (PLDataSource * pDataSrc) { PLASSERT (m_pTif == 0); m_pTif = TIFFOpenMem (pDataSrc->ReadEverything(), pDataSrc->GetFileSize(), NULL); if (!m_pTif) raiseError (PL_ERRWRONG_SIGNATURE, m_szLastErr); uint16 BitsPerSample; uint16 SamplesPerPixel; uint32 ImageHeight; uint32 ImageWidth; // get tagged image parameters TIFFGetFieldDefaulted(m_pTif, TIFFTAG_IMAGEWIDTH, &ImageWidth); TIFFGetFieldDefaulted(m_pTif, TIFFTAG_IMAGELENGTH, &ImageHeight); TIFFGetFieldDefaulted(m_pTif, TIFFTAG_BITSPERSAMPLE, &BitsPerSample); TIFFGetFieldDefaulted(m_pTif, TIFFTAG_SAMPLESPERPIXEL, &SamplesPerPixel); int16 PhotometricInterpretation; TIFFGetFieldDefaulted(m_pTif, TIFFTAG_PHOTOMETRIC, &PhotometricInterpretation); PLPixelFormat pf = PLPixelFormat::X8R8G8B8; if (!TIFFIsTiled(m_pTif)) { if (SamplesPerPixel == 1 && BitsPerSample ==1) pf = PLPixelFormat::L1; else if (SamplesPerPixel < 3 && BitsPerSample <= 8) if (PhotometricInterpretation == PHOTOMETRIC_MINISWHITE || PhotometricInterpretation == PHOTOMETRIC_MINISBLACK) pf = PLPixelFormat::L8; else pf = PLPixelFormat::I8; else if (SamplesPerPixel < 3 && BitsPerSample <= 16) pf = PLPixelFormat::L16; } if (SamplesPerPixel == 4 && (PhotometricInterpretation == PHOTOMETRIC_MINISWHITE || PhotometricInterpretation == PHOTOMETRIC_MINISBLACK || PhotometricInterpretation == PHOTOMETRIC_RGB || PhotometricInterpretation == PHOTOMETRIC_PALETTE)) pf = PLPixelFormat::A8R8G8B8; SetBmpInfo (PLPoint (ImageWidth, ImageHeight), getResolution (m_pTif), pf); }
void PLTIFFEncoder::DoEncode (PLBmpBase * pBmp, PLDataSink* pDataSnk) { TIFF* tif = TIFFOpenMem (pDataSnk->m_pStartData, pDataSnk->m_nMaxFileSize, &(pDataSnk->m_nCurPos)); PLASSERT( tif ); /* if (!tif) raiseError (PL_ERRWRONG_SIGNATURE, PLTIFFDecoder::m_szLastErr); */ // initialize TIFF "directory" SetBaseTags( tif, pBmp ); DoTiffEncode( pBmp, tif ); TIFFClose( tif ); }
void PLFilterVideoInvert::Apply(PLBmpBase *pBmpSource, PLBmp *pBmpDest) const { // Only works for 32 bpp bitmaps at the moment. PLASSERT (pBmpSource->GetBitsPerPixel() == 32); pBmpDest->Create (pBmpSource->GetWidth(), pBmpSource->GetHeight(), PLPixelFormat::X8R8G8B8, NULL, 0, pBmpSource->GetResolution()); PLBYTE ** pSrcLines = pBmpSource->GetLineArray(); PLBYTE ** pDstLines = pBmpDest->GetLineArray(); for (int y = 0; y<pBmpDest->GetHeight(); ++y) { // For each line PLBYTE * pSrcPixel = pSrcLines[y]; PLBYTE * pDstPixel = pDstLines[y]; for (int x = 0; x < pBmpDest->GetWidth(); ++x) { // For each pixel double v1, v2, v3; v1 = (double)pSrcPixel[PL_RGBA_RED]; v2 = (double)pSrcPixel[PL_RGBA_GREEN]; v3 = (double)pSrcPixel[PL_RGBA_BLUE]; fp_rgb_to_hsv(&v1, &v2, &v3); v3 = 255.0-v3; fp_hsv_to_rgb(&v1, &v2, &v3); *pDstPixel = static_cast<PLBYTE>(v3); pDstPixel++; *pDstPixel = static_cast<PLBYTE>(v2); pDstPixel++; *pDstPixel = static_cast<PLBYTE>(v1); pDstPixel++; pDstPixel++; /*PLBYTE (pSrcPixel[PL_RGBA_RED]*0.212671+ pSrcPixel[PL_RGBA_GREEN]*0.715160+ pSrcPixel[PL_RGBA_BLUE]*0.072169);*/ pSrcPixel += sizeof(PLPixel32); } } }
// now flush the data to disk void PLFileSink::Close () { #ifdef PL_FILE_MAPPING # ifdef _WIN32 UnmapViewOfFile (m_pStartData); CloseHandle (m_hm); m_hm = NULL; ::SetFilePointer(m_hf,GetDataSize(),0,FILE_BEGIN); ::SetEndOfFile(m_hf); //Truncate the file to the right size CloseHandle (m_hf); m_hf = NULL; # else resizeMapping(GetDataSize()); if (munmap(m_pDataBuf, GetDataSize()) != 0) { std::cerr <<"munmap failed, got error "<< strerror(errno)<<std::endl; throw PLTextException(PL_ERRINTERNAL, "munmap failed"); } m_pDataBuf = NULL; close( m_File ); m_File = 0; # endif #else int towrite = GetDataSize(); int written = fwrite( m_pStartData, 1, towrite, m_pFile ); # ifndef _DEBUG // avoid warnings (void)(towrite); (void)(written); # endif PLASSERT( written == towrite ); fclose( m_pFile ); m_pFile = 0; if (m_pDataBuf) { delete[] m_pDataBuf; m_pDataBuf = NULL; } #endif PLDataSink::Close(); }
void PLFilterColorize::ApplyInPlace(PLBmpBase * pBmp) const { PLAnyBmp TempBmp; TempBmp.CreateFilteredCopy(*pBmp, PLFilterGrayscale()); PLPixel24 ColorTable[256]; for (int i=0; i<256; i++) { ColorTable[i] = hls2rgb(m_Hue, i, m_Saturation); } PLBYTE ** pSrcLines = TempBmp.GetLineArray(); for (int y = 0; y < TempBmp.GetHeight(); y++) { PLBYTE * pSrcLine = pSrcLines[y]; switch (pBmp->GetBitsPerPixel()) { case 32: { PLPixel32 * pDestLine = pBmp->GetLineArray32()[y]; for (int x = 0; x < TempBmp.GetWidth(); x++) { pDestLine[x] = ColorTable[pSrcLine[x]]; } } break; case 24: { PLPixel24 * pDestLine = pBmp->GetLineArray24()[y]; for (int x = 0; x < TempBmp.GetWidth(); x++) { pDestLine[x] = ColorTable[pSrcLine[x]]; } } break; default: // bpp other than 8 and 24 are not supported. PLASSERT(false); } } }
void PLWinBmp::AssertValid () const { // call inherited PLASSERT_VALID first PLBmp::AssertValid(); // Bitmap must exist PLASSERT (m_pBMI); // Bitmapinfo must equal member variables PLASSERT (m_pBMI->biHeight == m_Size.y); PLASSERT (m_pBMI->biWidth == m_Size.x); PLASSERT (m_pBMI->biBitCount == GetBitsPerPixel()); // Only uncompressed bitmaps allowed. PLASSERT (m_pBMI->biCompression == BI_RGB); // No optimized color tables allowed. PLASSERT (m_pBMI->biClrUsed == 0 || m_pBMI->biClrUsed == (DWORD)(1 << GetBitsPerPixel())); }
void PLFilterContrast::Apply(PLBmpBase * pBmpSource, PLBmp * pBmpDest) const { // Consider a coordinate system with two axes: The x axis represents // an input RGB component or intensity, the y axis an output RGB // component or intensity. The ranges of input and output values go // from 0 - 255. // If I take a straight line that intersects (0,0) through (255,255), // I have defined a Null filter that leaves the image unchanged. // Next step: Let's rotate this straight line around the point (128,128). // If I increase the slope, output values above (128,128) are increased // by the slope factor, output values below (128, 128) are decreased // likewise. This is how I create the contrast enhancement effect. // Now we are having a problem: Increasing the slope means that our // straight line intersects the line (x, 255), creating output values // above 255 which are not defined in our RGB model. Since in the RGB world // there is nothing whiter than white, I'll set all these values to 255. A // similar thing happens on the lower left of our imaginary diagram: All // values smaller than 0 have to be set 0 - according to the fact that // there is nothing darker than absolute darkness... // Ok, now what is that offset value good for? Remember the point // (128,128). At this position, input and output values of our filter // remain unchanged, independent of the slope of our straight line. Now // imagine we are shifting our line parallel to the x axis. Our filter // works quite differently now: We create a cut-off for the higher output // value range (shift right), or the lower ones (shift left). // int total = 0; register int inc = 0; double contrast = m_contrast; PLASSERT (pBmpSource->GetBitsPerPixel() >= 24); pBmpDest->Create (pBmpSource->GetWidth(), pBmpSource->GetHeight(), pBmpSource->GetPixelFormat(), NULL, 0, pBmpSource->GetResolution()); PLBYTE ** pSrcLines = pBmpSource->GetLineArray(); PLBYTE ** pDstLines = pBmpDest->GetLineArray(); register int destWidth = pBmpDest->GetWidth(); if(pBmpSource->GetBitsPerPixel() == 24) inc = 3; if(pBmpSource->GetBitsPerPixel() == 32) inc = sizeof(PLPixel32); register double red, green, blue; register double csupp = contrast * (m_offset - 128.0) + 128.0; for (int y = 0; y < pBmpDest->GetHeight(); ++y) { // For each line register PLBYTE * pSrcPixel = pSrcLines[y]; register PLBYTE * pDstPixel = pDstLines[y]; for (register int x = 0; x < destWidth; ++x) { // Formel für Kontrastberechnung: // v = (contrast * (v - 12580 + m_offset) + 128.0); red = contrast * ((double) (pSrcPixel[PL_RGBA_RED])) + csupp; green = contrast * ((double) (pSrcPixel[PL_RGBA_GREEN])) + csupp; blue = contrast * ((double) (pSrcPixel[PL_RGBA_BLUE])) + csupp; if(red >= 255.0) pDstPixel[PL_RGBA_RED] = (PLBYTE) 255; else if (red < 0.0) pDstPixel[PL_RGBA_RED] = (PLBYTE) 0; else pDstPixel[PL_RGBA_RED] = (PLBYTE) red; if(green >= 255.0) pDstPixel[PL_RGBA_GREEN] = (PLBYTE) 255; else if (green < 0.0) pDstPixel[PL_RGBA_GREEN] = (PLBYTE) 0; else pDstPixel[PL_RGBA_GREEN] = (PLBYTE) green; if(blue >= 255.0) pDstPixel[PL_RGBA_BLUE] = (PLBYTE) 255; else if (blue < 0.0) pDstPixel[PL_RGBA_BLUE] = (PLBYTE) 0; else pDstPixel[PL_RGBA_BLUE] = (PLBYTE) blue; pSrcPixel += inc; pDstPixel += inc; } } }
void PLTIFFDecoder::doLoColor (TIFF * tif, PLBmpBase * pBmp) { uint16 BitsPerSample; uint16 SamplePerPixel; int32 LineSize; int16 PhotometricInterpretation; int row; PLBYTE *pBits; TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &BitsPerSample); TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &SamplePerPixel); TIFFGetFieldDefaulted(tif, TIFFTAG_PHOTOMETRIC, &PhotometricInterpretation); if (PhotometricInterpretation!=PHOTOMETRIC_MINISWHITE && PhotometricInterpretation!=PHOTOMETRIC_MINISBLACK && PhotometricInterpretation!=PHOTOMETRIC_PALETTE) { PhotometricInterpretation = PHOTOMETRIC_MINISWHITE; Trace(2,"unexpected PhotometricInterpretation, default to PHOTOMETRIC_MINISWHITE"); } LineSize = TIFFScanlineSize(tif); //Number of bytes in one line PLPixel32 pPal[256]; pBits = new PLBYTE [LineSize]; // enough for 16-bits per pixel if (pBits == NULL) raiseError (PL_ERRNO_MEMORY, "Out of memory allocating TIFF buffer."); // phase one: build color map if (BitsPerSample < 16) { if /* monochrome (=bitonal) or grayscale */ (PhotometricInterpretation == PHOTOMETRIC_MINISWHITE || PhotometricInterpretation == PHOTOMETRIC_MINISBLACK) { int numColors = 1 << BitsPerSample; PLBYTE step = static_cast<PLBYTE>(255 / (numColors-1)); PLBYTE *pb = (PLBYTE *) (pPal); int offset = sizeof(PLPixel32); if (PhotometricInterpretation == PHOTOMETRIC_MINISWHITE) { pb += (numColors-1) * sizeof(PLPixel32); offset = -offset; } // warning: the following ignores possible halftone hints for (int i = 0; i < numColors; ++i, pb += offset) { pb[PL_RGBA_RED] = pb[PL_RGBA_GREEN] = pb[PL_RGBA_BLUE] = static_cast<PLBYTE>(i * step); pb[PL_RGBA_ALPHA] = 255; } } //PhotometricInterpretation = 2 image is RGB //PhotometricInterpretation = 3 image has a color palette else if (PhotometricInterpretation == PHOTOMETRIC_PALETTE) { uint16* red; uint16* green; uint16* blue; int16 Palette16Bits; // we get pointers to libtiff-owned colormaps TIFFGetField(tif, TIFFTAG_COLORMAP, &red, &green, &blue); //Is the palette 16 or 8 bits ? Palette16Bits = checkcmap(1<<BitsPerSample, red, green, blue) == 16; //load the palette in the DIB for (int i = 0; i < 1<<BitsPerSample; ++i) { PLBYTE *pb = (PLBYTE *) ((pPal)+i); pb[PL_RGBA_RED ] = (PLBYTE) (Palette16Bits ? CVT( red[i]) : red[i]); pb[PL_RGBA_GREEN] = (PLBYTE) (Palette16Bits ? CVT(green[i]) : green[i]); pb[PL_RGBA_BLUE ] = (PLBYTE) (Palette16Bits ? CVT( blue[i]) : blue[i]); pb[PL_RGBA_ALPHA] = 255; } } else Trace( 2, "unexpected PhotometricInterpretation in PLTIFFDecoder::DoLoColor()" ); } // phase two: read image itself //generally, TIFF images are ordered from upper-left to bottom-right // we implicitly assume PLANARCONFIG_CONTIG PLBYTE **pLineArray = pBmp->GetLineArray(); if (BitsPerSample > 16) Trace( 2, "unexpected bit-depth in PLTIFFDecoder::DoLoColor()" ); else for ( row = 0; row < GetHeight(); ++row ) { uint16 x; int status = TIFFReadScanline( tif, pBits, row, 0 ); if (status == -1 && row < GetHeight() / 3) { delete [] pBits; // we should maybe free the BMP memory as well... raiseError (PL_ERRINTERNAL, m_szLastErr); } /* if (BitsPerSample == 1) // go ahead, waste space ;-) for (x=0; x < imageWidth; ++x) pLineArray[row][x] = pBits[x / 8] & (128 >> (x & 7)) ? 1 : 0; else */ if (BitsPerSample == 4) { for (x=0; x < GetWidth() / 2; ++x) { pLineArray[row][2*x ] = (pBits[x] & 0xf0) >> 4; pLineArray[row][2*x+1] = (pBits[x] & 0x0f); } // odd number of pixels if (GetWidth() & 1) pLineArray[row][GetWidth()-1] = (pBits[x] & 0xf0) >> 4; } else if (BitsPerSample == 16) { PLASSERT (SamplePerPixel == 1); // can't do 16-bit with alpha yet PLPixel16 **pLineArray16 = pBmp->GetLineArray16(); memcpy( pLineArray16[row], pBits, LineSize ); } else //if (BitsPerSample == 8 || BitsPerSample == 1) if (SamplePerPixel == 1) memcpy( pLineArray[row], pBits, LineSize ); else { // We've got an 8 bit image with an alpha channel. // Ignore the alpha channel. PLASSERT (BitsPerSample == 8); for (x=0; x < GetWidth(); ++x) pLineArray[row][x] = pBits[x*2]; } }
void PLTIFFDecoder::doHiColor (TIFF * tif, PLBmpBase * pBmp, uint16 SamplePerPixel) { int ok; PLULONG x, y; TIFFRGBAImage img; char emsg[1024]; PLBYTE * pBits; ok = TIFFRGBAImageBegin(&img, tif, 0, emsg); if (ok == 0) { raiseError (PL_ERRWRONG_SIGNATURE, "TIFF subformat not supported."); } //bool bHasAlpha = pBmp->HasAlpha(); PLASSERT (int(img.width) == pBmp->GetWidth()); PLASSERT (int(img.height) == pBmp->GetHeight()); PLASSERT (pBmp->GetBitsPerPixel() == 32); pBits = new PLBYTE [img.width*img.height*4]; if (pBits == NULL) raiseError (PL_ERRNO_MEMORY, "Out of memory allocating TIFF buffer."); // Hack for photoshop alpha channel support if (SamplePerPixel == 4 && img.bitspersample == 8 && img.photometric == 2) { img.put.contig = putRGBAAcontig8bittile; } ok = TIFFRGBAImageGet(&img, (uint32 *) pBits, img.width, img.height); if (!ok) { TIFFRGBAImageEnd(&img); raiseError (PL_ERRWRONG_SIGNATURE, m_szLastErr); } PLPixel32 ** pLineArray = pBmp->GetLineArray32(); // Correct the byte ordering. This could be replaced by appropriate // putRGBAcontig... routines. for (y=0; y<img.height; y++) { PLBYTE * pSrc = pBits+(img.height-y-1)*img.width*4; PLPixel32 * pPixel = pLineArray[y]; for (x=0; x<img.width; x++) { #ifdef WORDS_BIGENDIAN pPixel->Set (*(pSrc+3), *(pSrc+2), *(pSrc+1), *(pSrc)); #else pPixel->Set (*pSrc, *(pSrc+1), *(pSrc+2), *(pSrc+3)); #endif pPixel++; pSrc += 4; } } // Clean up. delete [] pBits; TIFFRGBAImageEnd(&img); }
void PLWEMFDecoder::Open (PLDataSource * pDataSrc) { PLASSERT_VALID(this); PLASSERT(m_bm == 0); PLASSERT(m_memdc == 0); PLASSERT(m_hemf == 0); SAPMFILEHEADER* pplaceablehdr = NULL; bool isadobe = false; bool isemf; // Get the type of the file (WMF or EMF) from the file name if (pDataSrc->NameIsWide()){ wchar_t* strname = _wcsdup(pDataSrc->GetNameW()); PLASSERT(strname); if (strname == NULL) { // This should never happen under 32-Bit, but who knows? PLASSERT(false); raiseError (PL_ERRNO_MEMORY,"Out of memory during strdup."); } _wcsupr(strname); isemf = wcsstr(strname,L".EMF") != NULL; free(strname); } else{ char* strname = _strdup(pDataSrc->GetName()); PLASSERT(strname); if (strname == NULL) { // This should never happen under 32-Bit, but who knows? PLASSERT(false); raiseError (PL_ERRNO_MEMORY,"Out of memory during strdup."); } _strupr(strname); bool isemf = strstr(strname,".EMF") != NULL; free(strname); } // Get a DC for the display m_dc = ::GetDC(NULL); PLASSERT(m_dc); if (m_dc == NULL) { PLASSERT(false); raiseError (PL_ERRNO_MEMORY,"Cannot allocate device context."); } if (isemf) { // We have an enhanced meta file which makes it alot easier m_hemf = SetEnhMetaFileBits(pDataSrc->GetFileSize(),pDataSrc->ReadEverything()); } else { // Buh, old 16-Bit WMF, Convert it to an enhanced metafile before proceeding. // Also, check if this is a placeable metafile with an Adobe Placeable header pplaceablehdr = (SAPMFILEHEADER*)pDataSrc->ReadEverything(); PLBYTE* p = NULL; UINT size; // If we have an adobe header, skip it to use only the real windows-conform data if (pplaceablehdr->key == ALDUSKEY) { isadobe = true; p = pDataSrc->ReadEverything()+sizeof(SAPMFILEHEADER); size = pDataSrc->GetFileSize() - sizeof(SAPMFILEHEADER); } else { // Else use the whole file contents as the metafile and assume // a native 16-Bit Windows-conform WMF p = pDataSrc->ReadEverything(); size = pDataSrc->GetFileSize(); } #ifdef _MFC_VER PLASSERT(AfxIsValidAddress(p,size,false)); #endif m_hemf = SetWinMetaFileBits(size,p,m_dc,NULL); } // If m_hemf is NULL, windows refused to load the metafile. If this is // the case, we're done. Notify the caller if (m_hemf == NULL) { raiseError (PL_ERRFORMAT_NOT_SUPPORTED,"Windows Metafile functions failed to load this image."); } // Get the header from the enhanced metafile, It contains some // useful information which will aid us during constuction of // the bitmap. // The header is of variable length. First get the amount of // memory required for the header UINT sizeneeded = GetEnhMetaFileHeader(m_hemf,0,NULL); if (sizeneeded == 0) { raiseError (PL_ERRFORMAT_UNKNOWN,"No header information in metafile"); } // Allocate storage for the header and read it in m_phdr = (LPENHMETAHEADER) new PLBYTE[sizeneeded]; if (m_phdr == NULL) { PLASSERT(false); raiseError (PL_ERRNO_MEMORY,"Out of memory during allocation of header."); } m_phdr->iType = EMR_HEADER; m_phdr->nSize = sizeneeded; #ifdef _MFC_VER PLASSERT(AfxIsValidAddress(m_phdr,sizeneeded,true)); #endif GetEnhMetaFileHeader(m_hemf,sizeneeded,m_phdr); int bpp = GetDeviceCaps(m_dc,BITSPIXEL); // Calculate the dimensions of the final bitmap. If we have // a placeable header in the WMF, we use the dimensions of // that image, else we use the calculated dimensions in the // EMF int width,height; if (isadobe) { PLASSERT(pplaceablehdr); int lpx = GetDeviceCaps(m_dc,LOGPIXELSX); int lpy = GetDeviceCaps(m_dc,LOGPIXELSY); // Calculate the absolute with and height and transform from twips to pixel width = (int) (pplaceablehdr->Right-pplaceablehdr->Left) * lpx / pplaceablehdr->inch; height = (int) (pplaceablehdr->Bottom-pplaceablehdr->Top) * lpy / pplaceablehdr->inch; } else { // Use the rclFrame of the header because it is the true device independent // information and also some applications (e.g. Corel) don't fill the // rclBounds correctly // Using: // MetaPixelsX = MetaWidthMM * MetaPixels / (MetaMM * 100); // where: // MetaWidthMM = metafile width in 0.01mm units // MetaPixels = width in pixels of the reference device // MetaMM = width in millimeters of the reference device // Same applies to the Y axis width = ((m_phdr->rclFrame.right - m_phdr->rclFrame.left) * m_phdr->szlDevice.cx) / (m_phdr->szlMillimeters.cx*100); height = ((m_phdr->rclFrame.bottom - m_phdr->rclFrame.top) * m_phdr->szlDevice.cy) / (m_phdr->szlMillimeters.cy*100); } // If this is a very old WMF without a PLACEABLE info, // we use somewhat meaningful defaults. Also, if the header was // not written correctly, we use this as a fallback if (width <= 0) { width = 320; } if (height <= 0) { height = 200; } // Create a device content for the screen, and a memory device // content to play the metafile to m_memdc = CreateCompatibleDC(m_dc); PLASSERT(m_memdc); if (m_memdc == NULL) { PLASSERT(false); raiseError (PL_ERRNO_MEMORY,"Cannot allocate device context."); } m_bm = CreateCompatibleBitmap(m_dc,width,height); if (m_bm == NULL) { PLASSERT(false); raiseError (PL_ERRNO_MEMORY,"Cannot allocate memory bitmap."); } m_holdbm = SelectObject(m_memdc,m_bm); // If the metafile has a palette, read it in UINT pe = GetEnhMetaFilePaletteEntries(m_hemf, 0, NULL); // pe is the real number of palette entries. To make the resulting // bitmap more useful, we always setup a 256 color palette if the // metafile has a palette if (pe>0 && pe<256) { SetBmpInfo (PLPoint (width, height), PLPoint(0,0), PLPixelFormat::L8); } else { SetBmpInfo (PLPoint (width, height), PLPoint(0,0), PLPixelFormat::B8G8R8A8); } }
int PLTIFFEncoder::SetBaseTags (TIFF* tif, PLBmpBase* pBmp) { PLASSERT( tif && pBmp ); uint16 ui16 = 0; uint32 ui32 = 0; ui32 = pBmp->GetWidth(); SetField( tif, TIFFTAG_IMAGEWIDTH, ui32 ); ui32 = pBmp->GetHeight(); SetField( tif, TIFFTAG_IMAGELENGTH, ui32 ); // one strip = the whole image // SetField( tif, TIFFTAG_ROWSPERSTRIP, ui32 ); ui16 = static_cast<uint16>(pBmp->GetBitsPerPixel()); if (ui16 > 8) ui16 = 8; SetField( tif, TIFFTAG_BITSPERSAMPLE, ui16 ); ui16 = static_cast<uint16>(pBmp->GetBitsPerPixel()); ui16 = ui16 <= 8 ? 1 : (pBmp->HasAlpha() ? 4 : 3); SetField( tif, TIFFTAG_SAMPLESPERPIXEL, ui16 ); if (pBmp->HasAlpha()) { // We'll default the alpha to "associated" and // assume it's pre-multiplied. Note that Photoshop // will load such a TIFF and use the alpha as the // layer's transparency. If extraType is 2, then // the alpha is unassociated, and Photoshop will // import the alpha as a fourth channel. short extraType[1] = {1}; SetField( tif, TIFFTAG_EXTRASAMPLES, 1, extraType); } ui16 = m_Compression; SetField( tif, TIFFTAG_COMPRESSION, ui16 ); ui16 = PLANARCONFIG_CONTIG; SetField( tif, TIFFTAG_PLANARCONFIG, ui16 ); /* * The following tags are supposedly mandatory, * but libtiff seems to have sensible defaults for us * ui32 = 0; SetField( TIFFTAG_SUBFILETYPE, ui32 ); ?!? SetField( TIFFTAG_STRIPOFFSETS, ui32 ); ?!? SetField( TIFFTAG_STRIPBYTECOUNT, ui32 ); * * */ float nRes = float(pBmp->GetResolution().x); SetField(tif,TIFFTAG_XRESOLUTION,nRes); nRes = float(pBmp->GetResolution().y); SetField(tif,TIFFTAG_YRESOLUTION,nRes); SetField (tif, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH); switch (pBmp->GetBitsPerPixel()) { case 1: { // look at bi-level palette... PLBYTE* p = (PLBYTE*) pBmp->GetPalette(); ui16 = p[PL_RGBA_RED] < p[PL_RGBA_RED + sizeof(PLPixel32)] && p[PL_RGBA_GREEN] < p[PL_RGBA_GREEN + sizeof(PLPixel32)] && p[PL_RGBA_BLUE] < p[PL_RGBA_BLUE + sizeof(PLPixel32)] ? PHOTOMETRIC_MINISBLACK : PHOTOMETRIC_MINISWHITE; SetField( tif, TIFFTAG_PHOTOMETRIC, ui16 ); } break; case 8: ui16 = PHOTOMETRIC_PALETTE; SetField( tif, TIFFTAG_PHOTOMETRIC, ui16 ); break; case 24: case 32: ui16 = PHOTOMETRIC_RGB; SetField( tif, TIFFTAG_PHOTOMETRIC, ui16 ); break; default: PLASSERT(false); } return 1; // should reflect the successful directory initialisation }
void PLTIFFEncoderEx::DoEncode (PLBmpBase * pBmp, PLDataSink* /* pDataSnk */) { PLASSERT( m_TiffToken ); // call base version on open tiff descriptor PLTIFFEncoder::DoTiffEncode( pBmp, m_TiffToken ); }
void PLTIFFEncoder::DoTiffEncode (PLBmpBase* pBmp, TIFF* tif) { uint32 l, c, image_length, image_width; // iterate over data PLBYTE **pla = pBmp->GetLineArray(); PLASSERT( pla ); image_length = (uint32) pBmp->GetHeight(); image_width = (uint32) pBmp->GetWidth(); switch (pBmp->GetBitsPerPixel()) { case 8: { // first, save the colormap uint16 red[256]; uint16 green[256]; uint16 blue[256]; PLPixel32 * pPal = pBmp->GetPalette(); PLASSERT( pPal ); for (int i = 0; i < pBmp->GetNumColors(); i++, pPal++) { red[i] = pPal->GetR (); green[i] = pPal->GetG (); blue[i] = pPal->GetB (); } SetField( tif, TIFFTAG_COLORMAP, red, green, blue ); } // fall-through case 1: // TODO: a bit of error checking for (l = 0; l < image_length; l++) if(TIFFWriteScanline( tif, pla[l], l, 0 ) < 1) { throw PLTextException(PL_ERRINTERNAL, "TIFFWriteScanline failed"); } break; case 24: { // TODO: check whether (r,g,b) components come in the correct order here... PLBYTE* pBuf = new PLBYTE[3*image_width]; for (l = 0; l < image_length; l++) { for (c = 0; c < image_width; c++) { pBuf[c*3 + 0] = pla[l][c*sizeof(PLPixel24) + PL_RGBA_RED]; pBuf[c*3 + 1] = pla[l][c*sizeof(PLPixel24) + PL_RGBA_GREEN]; pBuf[c*3 + 2] = pla[l][c*sizeof(PLPixel24) + PL_RGBA_BLUE]; } if(TIFFWriteScanline( tif, pBuf, l, 0 ) < 1) { throw PLTextException(PL_ERRINTERNAL, "TIFFWriteScanline failed"); } } delete [] pBuf; } break; case 32: { // TODO: check whether (r,g,b) components come in the correct order here... if (pBmp->HasAlpha()) { uint32 *plBuf = new uint32[image_width]; for (l = 0; l < image_length; l++) { for (c = 0; c < image_width; c++) { // For 32 bit, TIFFLIB wants abgr long word packed... plBuf[c] = ((uint32)(pla[l][c*sizeof(PLPixel32) + PL_RGBA_ALPHA]) << 24) | ((uint32)(pla[l][c*sizeof(PLPixel32) + PL_RGBA_BLUE]) << 16) | ((uint32)(pla[l][c*sizeof(PLPixel32) + PL_RGBA_GREEN]) << 8 ) | ((uint32)(pla[l][c*sizeof(PLPixel32) + PL_RGBA_RED])); } if(TIFFWriteScanline( tif, plBuf, l, 0 ) < 1) { throw PLTextException(PL_ERRINTERNAL, "TIFFWriteScanline failed"); } } delete [] plBuf; } else { PLBYTE* pBuf = new PLBYTE[3*image_width]; for (l = 0; l < image_length; l++) { for (c = 0; c < image_width; c++) { pBuf[c*3 + 0] = pla[l][c*sizeof(PLPixel32) + PL_RGBA_RED]; pBuf[c*3 + 1] = pla[l][c*sizeof(PLPixel32) + PL_RGBA_GREEN]; pBuf[c*3 + 2] = pla[l][c*sizeof(PLPixel32) + PL_RGBA_BLUE]; } if(TIFFWriteScanline( tif, pBuf, l, 0 ) < 1) { throw PLTextException(PL_ERRINTERNAL, "TIFFWriteScanline failed"); } } delete [] pBuf; } } break; default: PLASSERT(false); throw PLTextException(PL_ERRFORMAT_NOT_SUPPORTED, "unsupported bitsPerPixel"); } // we could flush at this point, but TIFFClose will do it anyway }
void PLWEMFDecoder::GetImage (PLBmpBase & Bmp) { HPALETTE hpal = NULL; LPLOGPALETTE plogpal (0); if (GetBitsPerPixel() == 8) { plogpal = (LPLOGPALETTE)new PLBYTE[sizeof(LOGPALETTE) + (sizeof(PALETTEENTRY) * 256)]; memset(plogpal,0x0,sizeof(LOGPALETTE) + sizeof(PALETTEENTRY)*256); plogpal->palVersion = 0x300; plogpal->palNumEntries = 256; if (plogpal == NULL) { PLASSERT(false); raiseError (PL_ERRNO_MEMORY,"Cannot allocate palette."); } UINT pe = GetEnhMetaFilePaletteEntries(m_hemf, 0, NULL); GetEnhMetaFilePaletteEntries(m_hemf, pe, plogpal->palPalEntry); } // Setup a logical palette for our memory dc and also a // paintlib compatible palette for the paintlib bitmap PLPixel32 pPal[256]; if (plogpal) { for (UINT i = 0; i < 256; i++) { pPal[i] = *(PLPixel32*)&plogpal->palPalEntry[i]; } if ((hpal = CreatePalette((LPLOGPALETTE)plogpal))) { m_holdpal = SelectPalette(m_memdc, hpal, false); RealizePalette(m_memdc); } Bmp.SetPalette(pPal); delete [] plogpal; } // Play the metafile into the device context // First, setup a bounding rectangle and fill // the memory dc with white (some metafiles only // use a black pen to draw and have no actual fill // color set, This would cause a black on black // painting which is rather useless RECT rc; rc.left = rc.top = 0; rc.bottom = GetHeight(); rc.right = GetWidth(); FillRect(m_memdc,&rc,(HBRUSH)GetStockObject(WHITE_BRUSH)); // Heeere we go.... BOOL bres = PlayEnhMetaFile(m_memdc,m_hemf,&rc); // Finally, convert the Windows bitmap into a paintlib bitmap PLWinBmp& winbmp = dynamic_cast<PLWinBmp&>(Bmp); BITMAPINFO* pBMI = (BITMAPINFO*)winbmp.GetBMI(); PLBYTE* pBits = (PLBYTE*)winbmp.GetBits(); if (GetBitsPerPixel() == 8) { GetDIBits(m_dc, m_bm, 0, GetHeight(), winbmp.GetBits(), pBMI, DIB_RGB_COLORS); } else { GetDIBits(m_dc, m_bm, 0, GetHeight(), winbmp.GetBits(), pBMI, DIB_PAL_COLORS); } }
void PLPNGDecoder::Open(PLDataSource *pDataSrc) { png_uint_32 width, height; m_png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, user_error_fn, user_warning_fn); PLASSERT(m_png_ptr); m_info_ptr = png_create_info_struct(m_png_ptr); PLASSERT(m_info_ptr); png_set_read_fn(m_png_ptr, (void*)pDataSrc, my_read_data); /* The call to png_read_info() gives us all of the information from the * PNG file before the first IDAT (image data chunk). */ png_read_info(m_png_ptr, m_info_ptr); #ifdef DUMP_PNG_DATA debugLog("%s", toString(*m_png_ptr).cstr()); #endif png_get_IHDR(m_png_ptr, m_info_ptr, &width, &height, &m_bit_depth ,&m_color_type, NULL, NULL, NULL); if( (m_color_type != PNG_COLOR_TYPE_RGB_ALPHA) && (m_color_type != PNG_COLOR_TYPE_GRAY_ALPHA) && ((m_color_type != PNG_COLOR_TYPE_RGB) || (m_bit_depth < 16)) ) { #ifdef PNG_READ_16_TO_8_SUPPORTED if(m_bit_depth == 16) { #ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED png_set_scale_16(png_ptr); #else png_set_strip_16(png_ptr); #endif } #endif if(m_color_type == PNG_COLOR_TYPE_PALETTE) { png_set_expand(m_png_ptr); } if(m_bit_depth < 8) { png_set_expand(m_png_ptr); } if(png_get_valid(m_png_ptr, m_info_ptr, PNG_INFO_tRNS)) { png_set_expand(m_png_ptr); } if((m_color_type == PNG_COLOR_TYPE_GRAY) || (m_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) { png_set_gray_to_rgb(m_png_ptr); } /* set the background color to draw transparent and alpha images over */ png_color_16 *pBackground; png_color bkgColor = {127, 127, 127}; if(png_get_bKGD(m_png_ptr, m_info_ptr, &pBackground)) { png_set_background(m_png_ptr, pBackground, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); bkgColor.red = (png_byte)pBackground->red; bkgColor.green = (png_byte)pBackground->green; bkgColor.blue = (png_byte)pBackground->blue; #ifdef DUMP_PNG_DATA debugLog(" Background : (%d,%d,%d)\n", bkgColor.red, bkgColor.green, bkgColor.blue); #endif } /* if required set gamma conversion */ double dGamma; if(png_get_gAMA(m_png_ptr, m_info_ptr, &dGamma)) { png_set_gamma(m_png_ptr, (double)2.2, dGamma); } /* after the transformations are registered, update info_ptr data */ png_read_update_info(m_png_ptr, m_info_ptr); png_get_IHDR(m_png_ptr, m_info_ptr, &width, &height, &m_bit_depth ,&m_color_type, NULL, NULL, NULL); } PLPixelFormat pf; switch(m_color_type) { case PNG_COLOR_TYPE_RGB: pf = PLPixelFormat::R8G8B8; break; case PNG_COLOR_TYPE_RGB_ALPHA: pf = PLPixelFormat::A8R8G8B8; break; case PNG_COLOR_TYPE_GRAY: pf = PLPixelFormat::L8; break; case PNG_COLOR_TYPE_GRAY_ALPHA: png_set_gray_to_rgb(m_png_ptr); png_set_expand(m_png_ptr); pf = PLPixelFormat::A8R8G8B8; break; case PNG_COLOR_TYPE_PALETTE: if(m_bit_depth != 16) { pf = PLPixelFormat::I8; } else { // 16-bit palette image png_set_expand(m_png_ptr); pf = PLPixelFormat::R8G8B8; } break; } if((pf.GetBitsPerPixel() == 32) || (pf.GetBitsPerPixel() == 24)) { png_set_bgr(m_png_ptr); } SetBmpInfo(PLPoint(width, height), PLPoint(0,0), pf); png_uint_32 XRes, YRes; int UnitType; png_get_pHYs(m_png_ptr, m_info_ptr, &XRes, &YRes, &UnitType); if(UnitType == PNG_RESOLUTION_METER) { m_Resolution = PLPoint(int (XRes/39.37f+0.5), int (YRes/39.37f+0.5)); } }
void PLIFF85Decoder::GetImage(PLBmpBase & Bmp) { Trace(2, "Decoding IFF-85 body.\n"); if (GetBitsPerPixel() == 8) { Bmp.SetPalette(&m_pal[0]); } // Decode each row into local storage, further processing depends on // form type. const int bytes_per_row = getBytesPerRow(); std::vector<PLBYTE> buf(bytes_per_row); for (int row = 0; row < m_bitmapHeader.h; ++row) { #if DETAILED_TRACE std::ostringstream strTrace; strTrace << "#Row " << row << ".\n"; Trace(3, strTrace.str().c_str()); #endif if (m_bitmapHeader.compression == PLIFF85::cmpByteRun1) { readCompressedRow(&buf[0], m_pDataSrc, bytes_per_row); } else { PLASSERT(m_bitmapHeader.compression == PLIFF85::cmpNone); readUncompressedRow(&buf[0], m_pDataSrc, bytes_per_row); } std::vector<PLBYTE> decodedBuf(m_bitmapHeader.w * GetBitsPerPixel() / 8); if (m_formType == PLIFF85::ID_PBM) { // The number of bytes we want to output may be less than the number // we have read in, as the input must have an even number of bytes per // plane (which can produce a lot of unnecessary padding for a PBM). const int bytes_per_row = m_bitmapHeader.w * GetBitsPerPixel() / 8; decodedBuf.assign(buf.begin(), buf.begin() + bytes_per_row); } else { PLASSERT(m_formType == PLIFF85::ID_ILBM); for (int bp = 0; bp < m_bitmapHeader.nPlanes; ++bp) { const int start_index = bp * bytes_per_row / m_bitmapHeader.nPlanes; for (int i = 0; i < m_bitmapHeader.w; ++i) { // Get the byte we're interested in. PLBYTE the_byte = buf[start_index + i / 8]; // Isolate the bit we're interested in. the_byte &= static_cast<PLBYTE> (1 << (7 - (i % 8))); // Now shift the bit to the correct position for this plane. if ((7 - (i % 8)) > bp) { the_byte >>= 7 - (i % 8) - bp; } else { the_byte <<= bp - (7 - (i % 8)); } decodedBuf[i] |= the_byte; } } }