---------- Forwarded message ---------
From: Andreas Brzesowsky <[email protected]>
Date: Wed, Jul 24, 2019 at 11:37 AM
Subject: Re: [Podofo-users] Patch for png transparency and gray scale
To: Michal Sudolsky <[email protected]>
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 <
[email protected]> 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
>
> [email protected]
> 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
> [email protected]
> 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
[email protected]
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
[email protected]
https://lists.sourceforge.net/lists/listinfo/podofo-users