---------- Forwarded message --------- From: Andreas Brzesowsky <andreas.brzesow...@dots.de> Date: Wed, Jul 24, 2019 at 11:37 AM Subject: Re: [Podofo-users] Patch for png transparency and gray scale To: Michal Sudolsky <sudols...@gmail.com>
Oh, yes, sorry. Am 24.07.2019 um 11:26 schrieb Michal Sudolsky: Hi, Seems you sent wrong patch file. On Wed, Jul 24, 2019 at 11:14 AM Andreas Brzesowsky < andreas.brzesow...@dots.de> wrote: > Hi, > > we had some problems with adding png images to pdf files with Podofo. > There are some color types not working and transparency is ignored or > replaced by black. > So I fixed the issues in Podofo and tested them with the images from the > PngSuite (http://www.libpng.org/pub/png/pngsuite.html). > To compare the differences I created the attached "testPngSuite.pdf" where > you can see one image of the PngSuite per page. > On the left the imaged added with Podofo revison 1997 and on the right > after my patch ("PdfFontCache.cpp.patch"). > > Changes: > - Handle color type gray with 1, 2 and 4 bit deepth > - If the png contains transparency, than a smask is created for the pdf > - If the png has a color palette, than the indexed color space > (ePdfColorSpace_Indexed) is used in the pdf. > - Reduced the doubled code in LoadFromPngHandle and LoadFromPngData by > having the local LoadFromPngContent function for this shared code > > So please check my changes and add them to the repository or ask questions. > > Kind regards > > Andreas > -- > > [image: dots] <http://www.dots.de/en/> > > Andreas Brzesowsky > > dots Gesellschaft für Softwareentwicklung mbH > Schlesische Str. 27, 10997 Berlin, Germany > Phone: +49 (0)30 695 799-33, Fax: +49 (0)30 695 799-55 > > andreas.brzesow...@dots.de > http://www.dots.de > > Amtsgericht (District Court): Berlin Charlottenburg HRB 65201 > Geschäftsführer (Managing Directors): Takeo Morohashi > Follow us on: [image: Twitter] <http://www.dots.de/?id=twitter> [image: > YouTube] <http://www.dots.de/?id=youtube> > [image: AccurioPro Flux] > <http://www.accuriopro-flux.com/?utm_source=email&utm_medium=banner> > > > _______________________________________________ > Podofo-users mailing list > Podofo-users@lists.sourceforge.net > https://lists.sourceforge.net/lists/listinfo/podofo-users > -- [image: dots] <http://www.dots.de/en/> Andreas Brzesowsky dots Gesellschaft für Softwareentwicklung mbH Schlesische Str. 27, 10997 Berlin, Germany Phone: +49 (0)30 695 799-33, Fax: +49 (0)30 695 799-55 andreas.brzesow...@dots.de http://www.dots.de Amtsgericht (District Court): Berlin Charlottenburg HRB 65201 Geschäftsführer (Managing Directors): Takeo Morohashi Follow us on: [image: Twitter] <http://www.dots.de/?id=twitter> [image: YouTube] <http://www.dots.de/?id=youtube> [image: AccurioPro Flux] <http://www.accuriopro-flux.com/?utm_source=email&utm_medium=banner>
Index: PdfImage.cpp =================================================================== --- PdfImage.cpp (revision 1997) +++ PdfImage.cpp (working copy) @@ -853,36 +853,7 @@ } #endif // _WIN32 -void PdfImage::LoadFromPngHandle( PdfFileInputStream* pInStream ) -{ - FILE* hFile = pInStream->GetHandle(); - png_byte header[8]; - if( fread( header, 1, 8, hFile ) != 8 || - png_sig_cmp( header, 0, 8 ) ) - { - PODOFO_RAISE_ERROR_INFO( ePdfError_UnsupportedImageFormat, "The file could not be recognized as a PNG file." ); - } - - png_structp pPng = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - if( !pPng ) - { - PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); - } - - png_infop pInfo = png_create_info_struct(pPng); - if( !pInfo ) - { - png_destroy_read_struct(&pPng, (png_infopp)NULL, (png_infopp)NULL); - PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); - } - - if( setjmp(png_jmpbuf(pPng)) ) - { - png_destroy_read_struct(&pPng, &pInfo, (png_infopp)NULL); - PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); - } - - png_init_io(pPng, hFile); +void LoadFromPngContent(png_structp pPng, png_infop pInfo, PdfImage *image) { png_set_sig_bytes(pPng, 8); png_read_info(pPng, pInfo); @@ -898,12 +869,6 @@ &color_type, &interlace, NULL, NULL); /* convert palette/gray image to rgb */ - if (color_type == PNG_COLOR_TYPE_PALETTE) - png_set_palette_to_rgb(pPng); - - if (color_type & PNG_COLOR_MASK_ALPHA) - png_set_strip_alpha(pPng); -#if 0 /* expand gray bit depth if needed */ if (color_type == PNG_COLOR_TYPE_GRAY) { #if PNG_LIBPNG_VER >= 10209 @@ -911,25 +876,17 @@ #else png_set_gray_1_2_4_to_8 (pPng); #endif + } else if (color_type != PNG_COLOR_TYPE_PALETTE && depth < 8) { + png_set_packing(pPng); } -#endif + /* transform transparency to alpha */ - if (png_get_valid (pPng, pInfo, PNG_INFO_tRNS)) + if (color_type != PNG_COLOR_TYPE_PALETTE && png_get_valid (pPng, pInfo, PNG_INFO_tRNS)) png_set_tRNS_to_alpha (pPng); if (depth == 16) png_set_strip_16(pPng); - if (depth < 8) - png_set_packing(pPng); -#if 0 - /* convert grayscale to RGB */ - if (color_type == PNG_COLOR_TYPE_GRAY || - color_type == PNG_COLOR_TYPE_GRAY_ALPHA) - { - png_set_gray_to_rgb (pPng); - } -#endif if (interlace != PNG_INTERLACE_NONE) png_set_interlace_handling(pPng); @@ -949,8 +906,8 @@ PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } - - long lLen = static_cast<long>(png_get_rowbytes(pPng, pInfo) * height); + size_t lRowLen = png_get_rowbytes(pPng, pInfo); + size_t lLen = lRowLen * height; char* pBuffer = static_cast<char*>(podofo_calloc(lLen, sizeof(char))); if (!pBuffer) { @@ -965,51 +922,133 @@ for(unsigned int y=0; y<height; y++) { - pRows[y] = reinterpret_cast<png_bytep>(pBuffer + (y * png_get_rowbytes(pPng, pInfo))); + pRows[y] = reinterpret_cast<png_bytep>(pBuffer + y * lRowLen); } png_read_image(pPng, pRows); - m_rRect.SetWidth( width ); - m_rRect.SetHeight( height ); + png_bytep paletteTrans; + int numTransColors; + if (color_type & PNG_COLOR_MASK_ALPHA || + color_type == PNG_COLOR_TYPE_PALETTE && png_get_valid(pPng, pInfo, PNG_INFO_tRNS) && png_get_tRNS(pPng, pInfo, &paletteTrans, &numTransColors, NULL)) + { + // Handle alpha channel and create smask + char *smask = static_cast<char*>(podofo_calloc(height, width)); + png_uint_32 smaskIndex = 0; + if (color_type == PNG_COLOR_TYPE_PALETTE) { + for (png_uint_32 r = 0; r < height; r++) { + png_bytep row = pRows[r]; + for (png_uint_32 c = 0; c < width; c++) { + png_byte color; + if (depth == 8) { + color = row[c]; + } else if (depth == 4) { + color = c % 2 ? row[c / 2] >> 4 : row[c / 2] & 0xF; + } else if (depth == 2) { + color = (row[c / 4] >> c % 4 * 2) & 3; + } else if (depth == 1) { + color = (row[c / 4] >> c % 8) & 1; + } + smask[smaskIndex++] = color < numTransColors ? paletteTrans[color] : 0xFF; + } + } + } else if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) { + for (png_uint_32 r = 0; r < height; r++) { + png_bytep row = pRows[r]; + for (png_uint_32 c = 0; c < width; c++) { + memmove(pBuffer + 3 * smaskIndex, row + 4 * c, 3); // 3 byte for rgb + smask[smaskIndex++] = row[c * 4 + 3]; // 4th byte for alpha + } + } + lLen = 3 * width * height; + } else if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { + for (png_uint_32 r = 0; r < height; r++) { + png_bytep row = pRows[r]; + for (png_uint_32 c = 0; c < width; c++) { + pBuffer[smaskIndex] = row[c * 2]; // 1 byte for gray + smask[smaskIndex++] = row[c * 2 + 1]; // 2nd byte for alpha + } + } + lLen = width * height; + } + PdfMemoryInputStream smaskstream(smask, width * height); + PdfImage smakeImage(image->GetObject()->GetOwner()); + smakeImage.SetImageColorSpace(ePdfColorSpace_DeviceGray); + smakeImage.SetImageData(width, height, 8, &smaskstream); + image->SetImageSoftmask(&smakeImage); + podofo_free(smask); + } - switch( png_get_channels( pPng, pInfo ) ) - { - case 3: - this->SetImageColorSpace( ePdfColorSpace_DeviceRGB ); - break; - case 4: + // Set color space + if (color_type == PNG_COLOR_TYPE_PALETTE) { + png_color *pColors; + int numColors; + png_get_PLTE(pPng, pInfo, &pColors, &numColors); + + char *datap = new char[numColors * 3]; + for (int i = 0; i < numColors; i++, pColors++) { - this->SetImageColorSpace( ePdfColorSpace_DeviceCMYK ); - // The jpeg-doc ist not specific in this point, but cmyk's seem to be stored - // in a inverted fashion. Fix by attaching a decode array - PdfArray decode; - decode.push_back( 1.0 ); - decode.push_back( 0.0 ); - decode.push_back( 1.0 ); - decode.push_back( 0.0 ); - decode.push_back( 1.0 ); - decode.push_back( 0.0 ); - decode.push_back( 1.0 ); - decode.push_back( 0.0 ); - - this->GetObject()->GetDictionary().AddKey( PdfName("Decode"), decode ); + datap[3 * i + 0] = pColors->red; + datap[3 * i + 1] = pColors->green; + datap[3 * i + 2] = pColors->blue; } - break; - default: - this->SetImageColorSpace( ePdfColorSpace_DeviceGray ); - break; + PdfMemoryInputStream stream(datap, numColors * 3); + PdfObject* pIdxObject = image->GetObject()->GetOwner()->CreateObject(); + pIdxObject->GetStream()->Set(&stream); + + PdfArray array; + array.push_back(PdfName("DeviceRGB")); + array.push_back(static_cast<pdf_int64>(numColors - 1)); + array.push_back(pIdxObject->Reference()); + image->SetImageColorSpace(ePdfColorSpace_Indexed, &array); + } else if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { + image->SetImageColorSpace(ePdfColorSpace_DeviceGray); + } else { + image->SetImageColorSpace(ePdfColorSpace_DeviceRGB); } // Set the image data and flate compress it PdfMemoryInputStream stream( pBuffer, lLen ); - this->SetImageData( width, height, depth, &stream ); + image->SetImageData( width, height, depth, &stream ); podofo_free(pBuffer); podofo_free(pRows); png_destroy_read_struct(&pPng, &pInfo, (png_infopp)NULL); +} +void PdfImage::LoadFromPngHandle( PdfFileInputStream* pInStream ) +{ + FILE* hFile = pInStream->GetHandle(); + png_byte header[8]; + if( fread( header, 1, 8, hFile ) != 8 || + png_sig_cmp( header, 0, 8 ) ) + { + PODOFO_RAISE_ERROR_INFO( ePdfError_UnsupportedImageFormat, "The file could not be recognized as a PNG file." ); + } + + png_structp pPng = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if( !pPng ) + { + PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); + } + + png_infop pInfo = png_create_info_struct(pPng); + if( !pInfo ) + { + png_destroy_read_struct(&pPng, (png_infopp)NULL, (png_infopp)NULL); + PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); + } + + if( setjmp(png_jmpbuf(pPng)) ) + { + png_destroy_read_struct(&pPng, &pInfo, (png_infopp)NULL); + PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); + } + + png_init_io(pPng, hFile); + + LoadFromPngContent(pPng, pInfo, this); } struct pngData @@ -1076,132 +1115,8 @@ } png_set_read_fn(pPng, (png_voidp)&data, pngReadData); - png_set_sig_bytes(pPng, 8); - png_read_info(pPng, pInfo); - // Begin - png_uint_32 width; - png_uint_32 height; - int depth; - int color_type; - int interlace; - - png_get_IHDR (pPng, pInfo, - &width, &height, &depth, - &color_type, &interlace, NULL, NULL); - - /* convert palette/gray image to rgb */ - if (color_type == PNG_COLOR_TYPE_PALETTE) - png_set_palette_to_rgb(pPng); - - if (color_type & PNG_COLOR_MASK_ALPHA) - png_set_strip_alpha(pPng); -#if 0 - /* expand gray bit depth if needed */ - if (color_type == PNG_COLOR_TYPE_GRAY) { -#if PNG_LIBPNG_VER >= 10209 - png_set_expand_gray_1_2_4_to_8 (pPng); -#else - png_set_gray_1_2_4_to_8 (pPng); -#endif - } -#endif - /* transform transparency to alpha */ - if (png_get_valid (pPng, pInfo, PNG_INFO_tRNS)) - png_set_tRNS_to_alpha (pPng); - - if (depth == 16) - png_set_strip_16(pPng); - - if (depth < 8) - png_set_packing(pPng); -#if 0 - /* convert grayscale to RGB */ - if (color_type == PNG_COLOR_TYPE_GRAY || - color_type == PNG_COLOR_TYPE_GRAY_ALPHA) - { - png_set_gray_to_rgb (pPng); - } -#endif - if (interlace != PNG_INTERLACE_NONE) - png_set_interlace_handling(pPng); - - //png_set_filler (pPng, 0xff, PNG_FILLER_AFTER); - - /* recheck header after setting EXPAND options */ - png_read_update_info(pPng, pInfo); - png_get_IHDR (pPng, pInfo, - &width, &height, &depth, - &color_type, &interlace, NULL, NULL); - // End // - - // Read the file - if( setjmp(png_jmpbuf(pPng)) ) - { - png_destroy_read_struct(&pPng, &pInfo, (png_infopp)NULL); - PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); - } - - - long lLen = static_cast<long>(png_get_rowbytes(pPng, pInfo) * height); - char* pBuffer = static_cast<char*>(podofo_calloc(lLen, sizeof(char))); - if (!pBuffer) - { - PODOFO_RAISE_ERROR(ePdfError_OutOfMemory); - } - - png_bytepp pRows = static_cast<png_bytepp>(podofo_calloc(height, sizeof(png_bytep))); - if (!pRows) - { - PODOFO_RAISE_ERROR(ePdfError_OutOfMemory); - } - - for(unsigned int y=0; y<height; y++) - { - pRows[y] = reinterpret_cast<png_bytep>(pBuffer + (y * png_get_rowbytes(pPng, pInfo))); - } - - png_read_image(pPng, pRows); - - m_rRect.SetWidth( width ); - m_rRect.SetHeight( height ); - - switch( png_get_channels( pPng, pInfo ) ) - { - case 3: - this->SetImageColorSpace( ePdfColorSpace_DeviceRGB ); - break; - case 4: - { - this->SetImageColorSpace( ePdfColorSpace_DeviceCMYK ); - // The jpeg-doc ist not specific in this point, but cmyk's seem to be stored - // in a inverted fashion. Fix by attaching a decode array - PdfArray decode; - decode.push_back( 1.0 ); - decode.push_back( 0.0 ); - decode.push_back( 1.0 ); - decode.push_back( 0.0 ); - decode.push_back( 1.0 ); - decode.push_back( 0.0 ); - decode.push_back( 1.0 ); - decode.push_back( 0.0 ); - - this->GetObject()->GetDictionary().AddKey( PdfName("Decode"), decode ); - } - break; - default: - this->SetImageColorSpace( ePdfColorSpace_DeviceGray ); - break; - } - - // Set the image data and flate compress it - PdfMemoryInputStream stream( pBuffer, lLen ); - this->SetImageData( width, height, depth, &stream ); - - podofo_free(pBuffer); - podofo_free(pRows); - - png_destroy_read_struct(&pPng, &pInfo, (png_infopp)NULL); + LoadFromPngContent(pPng, pInfo, this); } #endif // PODOFO_HAVE_PNG_LIB
_______________________________________________ Podofo-users mailing list Podofo-users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/podofo-users