New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

incorrect rendering of JPEG images on Windows Server 2008 x64 #1638

Closed
ashkulz opened this Issue Apr 15, 2014 · 18 comments

Comments

Projects
None yet
5 participants
@ashkulz
Member

ashkulz commented Apr 15, 2014

This was originally reported as #1512 and has been split off from it.

HTML:

<!DOCTYPE html>
<html>
<body>
<img src="bill_gates_400.jpg"/>
</body>
</html>

Image:
bill_gates_400

This results in a PDF where the image comes out as corrupt or not rendered properly:

corrupt

This testcase was originally made by @DomusMaximus and affects @boeserwolf and @denu as well.

@fjginermontagud

This comment has been minimized.

fjginermontagud commented Apr 17, 2014

Same problem for me. Server configuration, if helps:

  • Windows Server 2008 R2 Enterprise
  • DualCore 3,3GHz
  • 8GB Ram

Seems that creates two or more negative images and superimposed on the original.

@poizan42

This comment has been minimized.

Contributor

poizan42 commented May 19, 2014

I have the same issue with an image that I unfortunately can't share. I'm using the shared library and the problem is in both the mingw and the msvc versions on the same os'es. Also it doesn't seems to matter whether run as 32- or 64-bit on the affected 64-bit systems. Tested on these systems:

Present: Windows XP x86, Windows Server 2003 x86, Windows Server 2003 R2 x86, Windows Server 2008 x64, Windows Server 2008 R2 x64

Not present: Windows 7 x64, Windows 8 x64, Windows 8.1 x64, Windows Server 2012 x64

@ashkulz

This comment has been minimized.

Member

ashkulz commented May 19, 2014

I know that this is important, but it is so platform-specific that it will take me quite a bit of time to debug it -- the crash took me more than a week to debug and finding a server where you can install debugging tools is not easy at all. And the crash is easier to fix because you have to start investigation at a single point :-)

@BDvirus

This comment has been minimized.

BDvirus commented May 25, 2014

Hi ashkulz

First, thank you for your hard work,
you are doing a great work!

The incorrect rendering of JPEG images happen also on Widows 2003 Server

I installed wkhtmltox-0.11.0_rc1-installer.exe
(https://code.google.com/p/wkhtmltopdf/downloads/detail?name=wkhtmltox-0.11.0_rc1-installer.exe&can=1&q=)
That version works very fine for me (no problem at all in rendering jpeg)
the only problem for me that it's not support in Table header repeat in rendering html..

Back to v12.1(not rc) the version in http://wkhtmltopdf.org/downloads.html
PNG Files are rendering very well, my problem that I need to use jpeg.

The most Important thing That I notice is that when I Use Imagick Libary (http://www.imagemagick.org/) to write an Jpeg image it's happens.
if I will take the same Image save it in Photoshop and try again .. the problem is gone!
I think that it's relate to the way that Imagick write the file (with it's profile and etc..)

I hope it's help in something...
if need to test anything... please send..

Dvir.

@ashkulz

This comment has been minimized.

Member

ashkulz commented May 26, 2014

can you upload the files somewhere? Maybe examining the structure will give a clue as to why there is a difference.

@BDvirus

This comment has been minimized.

BDvirus commented May 26, 2014

Hi ashkulz
Thanks for quick reply

PDF Originial link:
http://esdigital.co.il/wkhtmltopdf/test.pdf

1.bad image link:
http://esdigital.co.il/wkhtmltopdf/test-bad.jpg

2.good image link:
http://esdigital.co.il/wkhtmltopdf/test-good.jpg

Step procedures:

  1. Convert PDF with Imagick to JPG format.
  2. try to render with Wkhtmltopdf
  3. bad results.
  4. open the test jpg with Windows Picture and fax viewer (builtin windows viewer)
  5. save to other name (there is an option to save as in Windows picture viewer)
  6. try again to render with Wkhtmltopdf work fine!

If need anything please let me know..

Dvir.

@ashkulz

This comment has been minimized.

Member

ashkulz commented May 27, 2014

Can you try if the following patch gives you better output?

commit 2591d7fd741cf4ae679dd495121537497eacf09d
Author: Ashish Kulkarni <kulkarni.ashish@gmail.com>
Date:   Tue May 27 15:07:56 2014 +0530

    fix jpeg issue

diff --git a/src/gui/painting/qprintengine_pdf.cpp b/src/gui/painting/qprintengine_pdf.cpp
index 78e6301..8775e2e 100644
--- a/src/gui/painting/qprintengine_pdf.cpp
+++ b/src/gui/painting/qprintengine_pdf.cpp
@@ -754,85 +754,6 @@ void QPdfEnginePrivate::convertImage(const QImage & image, QByteArray & imageDat
     }
 }

-#include <iostream>
-
-class jpg_header_reader {
-private:
-  const QByteArray * data;
-  int index;
-
-  class jpeg_exception {};
-
-  unsigned char next() {
-    if (index == data->size()) throw jpeg_exception();
-    return data->data()[index++];
-  }
-
-  void skip() {
-    int l = (next() << 8) + next();
-    if (l < 2) throw jpeg_exception();
-    for (int i=2; i < l; ++i) next();
-  }
-
-  void read_header() {
-    int l = (next() << 8) + next();
-    if (l < 2) throw jpeg_exception();
-    precision = next();
-    height = (next() << 8) + next();
-    width = (next() << 8) + next();
-    components = next();
-    if (l != 8 + components*3) throw jpeg_exception();
-  }
-
-public:
-  bool read(const QByteArray * d) {
-    index=0;
-    data=d;
-    try {
-      if (next() != 0xFF) throw jpeg_exception();
-      unsigned char marker = next();
-      if (marker != 0xD8) throw jpeg_exception();
-      while (true) {
-        marker = next();
-        while (marker != 0xFF) marker=next();
-        while (marker == 0xFF) marker=next();
-        switch(marker) {
-          case 0xC0:   // SOF0 Start Of Frame N - BaseLine
-          case 0xC1:   // SOF1 N indicates which compression process - Extended Sequential
-          case 0xC2:   // SOF2 Only SOF0-SOF2 are now in common use - Progressive
-          case 0xC3:   // SOF3 Lossless
-          case 0xC5:   // SOF5 Differential sequential
-          case 0xC6:   // SOF6 Differential progressive
-          case 0xC7:   // SOF7 Differential lossless
-          case 0xC9:   // SOF9 Extended sequential, arithmetic coding
-          case 0xCA:   // SOF10 Progressive, arithmetic coding
-          case 0xCB:   // SOF11 Lossless, arithmetic coding
-          case 0xCD:   // SOF13 Differential sequential, arithmetic coding
-          case 0xCE:   // SOF14 Differential progressive, arithmetic coding
-          case 0xCF:   // SOF15 Differential lossless, arithmetic coding
-          case 0xE1:   // EXIF/XMP Exif marker.  Also used for XMP data!
-            read_header();
-            return true;
-          case 0xDA:    // SOS Start Of Scan (begins compressed data)
-          case 0xD9:    // EOI End Of Image (end of datastream)
-            return false;
-          default:
-            skip();
-            break;
-          }
-        }
-    } catch(jpeg_exception) {
-      return false;
-    }
-    return true;
-  }
-
-  int precision, height, width, components;
-
-};
-
-
-
 /*!
  * Adds an image to the pdf and return the pdf-object id. Returns -1 if adding the image failed.
  */
@@ -937,9 +858,9 @@ int QPdfEnginePrivate::addImage(const QImage &img, bool *bitmap, qint64 serial_n


         if (colorMode != QPrinter::GrayScale && noneScaled != 0 && data != 0) {
-          jpg_header_reader header;
-          if (header.read(data)) {
-            d = header.components == 3?32:8;
+          QImage jpeg;
+          if (jpeg.loadFromData(*data, "JPEG")) {
+            d = jpeg.depth();
             imageData = *data;
             target=data->size();
             dct=true;

I have uploaded a precompiled binary with MSVC 2013 for 32-bit Windows, can't test it as I don't have access to a Windows server box for the next week.

@BDvirus

This comment has been minimized.

BDvirus commented May 27, 2014

Hi thanks for the fix...

The precompiled binary not working ... :(
err: C:\Program Files\wkhtmltopdf\bin\wkhtmltopdf.exe is not a valid Win32 application.

I will try to recompile with MSVC 2010 for 32-bit and I will let you know...

Thanks.

@BDvirus

This comment has been minimized.

BDvirus commented May 27, 2014

Hi ashkulz,

I tried the patch ... same problem..
It's happened to you with the jpg that I uploaded? (can you see the problem?)

  1. Sorry for nube question but how can I pull a commit fix ? (the one that you send me for example to my folder , windows git bash)
    (I change the file manual but for sure there is faster way)
  2. I compiled with your python script - It should take that long ??(40min)

Thanks again for all your helping

Br,
Dvir.

@ashkulz

This comment has been minimized.

Member

ashkulz commented May 27, 2014

@BDvirus: does that mean it did not fix the issue i.e. still generates that weird pattern? I can't test it myself as I mentioned above:

can't test it as I don't have access to a Windows server box for the next week.

And yes, compilation can take that long on even a very fast machine.

@BDvirus

This comment has been minimized.

BDvirus commented May 27, 2014

@ashkulz: It did not fix the issue..
I dont think that it related to os. I also tried the precompiled version that you upload on Windows 7 32-bit and still generates that weird pattern..

Any suggestions?

@ashkulz ashkulz modified the milestones: 0.12.2, future Jul 2, 2014

@poizan42

This comment has been minimized.

Contributor

poizan42 commented Sep 1, 2014

I think the core of the problem is that QPdfEnginePrivate::addImage assumes that the formats of img and noneScaled are the same, which apparently they end up not being. When making a debug build i'm getting a crash at qprintengine_pdf.cpp:965. img.format() is Format_ARGB32 but noneScaled->fomat() is Format_RGB16. So for every scanline we are actually reading two rows of the image.

@poizan42

This comment has been minimized.

Contributor

poizan42 commented Sep 1, 2014

The code in question is really quite weird:

        if (format != QImage::Format_RGB32) {
            softMaskData.resize(w * h);
            uchar *sdata = (uchar *)softMaskData.data();
            for (int y = 0; y < h; ++y) {
                const QRgb *rgb = (const QRgb *)(uns?noneScaled->scanLine(y):image.scanLine(y));
                for (int x = 0; x < w; ++x) {
                    uchar alpha = qAlpha(*rgb);
                    *sdata++ = alpha;
                    hasMask |= (alpha < 255);
                    hasAlpha |= (alpha != 0 && alpha != 255);
                    ++rgb;
                }
            }
        }

The format isn't RGB32. But it's not ARGB32 either, so it doesn't make sense to just loop through QRgb pixels (which are ARGB32).

@poizan42

This comment has been minimized.

Contributor

poizan42 commented Sep 1, 2014

Try this patch:

diff --git "a/src/gui/painting/qprintengine_pdf.cpp" "b/src/gui/painting/qprintengine_pdf.cpp"
index 78e6301..1087b56 100644
--- "a/src/gui/painting/qprintengine_pdf.cpp"
+++ "b/src/gui/painting/qprintengine_pdf.cpp"
@@ -956,7 +956,7 @@ int QPdfEnginePrivate::addImage(const QImage &img, bool *bitmap, qint64 serial_n
         bool hasAlpha = false;
         bool hasMask = false;

-        if (format != QImage::Format_RGB32) {
+        if ((!uns && format == QImage::Format_ARGB32) || (uns && noneScaled->format() == QImage::Format_ARGB32)) {
             softMaskData.resize(w * h);
             uchar *sdata = (uchar *)softMaskData.data();
             for (int y = 0; y < h; ++y) {

I'm not sure if it's isn't still wrong as we are failing to handle the other formats with alpha channels - there are several:

        Format_ARGB32,
        Format_ARGB32_Premultiplied,
        Format_ARGB8565_Premultiplied,
        Format_ARGB6666_Premultiplied,
        Format_ARGB8555_Premultiplied,
        Format_ARGB4444_Premultiplied,
  • but at least it's no worse than it was before.
@ashkulz

This comment has been minimized.

Member

ashkulz commented Sep 9, 2014

@poizan42: I think that converting noneScaled to ARGB32 would be the correct thing to do. What do you think?

@ashkulz ashkulz added the Fixed label Oct 20, 2014

ashkulz added a commit that referenced this issue Oct 21, 2014

@ashkulz

This comment has been minimized.

Member

ashkulz commented Oct 22, 2014

Please test this with the latest 0.12.2 test release available from the downloads page and report back if you find any problems.

@ispir2000

This comment has been minimized.

ispir2000 commented Jan 7, 2015

Hi friends,
I m trying 0.13 Alpha and 0.12 for my project.
there is a problem with images. I created 2 pdf file both of version for same html file.
you will understand me when see image as attach.
please help me,

ekran alintisi

I can sent some code samples or more image, too.

thanks,
V.Ispir

@ashkulz

This comment has been minimized.

Member

ashkulz commented Jan 10, 2015

0.12.2 has been released, which includes changes related to this issue.

ashkulz added a commit that referenced this issue Jul 2, 2015

fix broken rendering of transparent images when converting to PDF
The fixes for #1512 and #1638 were band-aids but did not fix the
underlying problem. Updating the patched Qt should fix #2214.

DanielCeregatti added a commit to DanielCeregatti/wkhtmltopdf that referenced this issue Jul 8, 2015

fix broken rendering of transparent images when converting to PDF
The fixes for wkhtmltopdf#1512 and wkhtmltopdf#1638 were band-aids but did not fix the
underlying problem. Updating the patched Qt should fix wkhtmltopdf#2214.

poizan42 added a commit to cBrain-dk/qtbase-5-wk that referenced this issue Feb 16, 2017

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment