Friday, December 14, 2007

Images and CFDocument performance

Sometime back one of our customer reported that using png images in cfdocument makes it very very slow. I could not replicate it with any png image but it did happen with his png image.

Today, Andy reported a similar issue but this time it was for jpeg images. In both the cases, performance hit is huge and it does not happen with all the images.

I spent a significant amount of time debugging it today and it turns out that the reason for both the issues are same - there is something special about these images and that is colorspace. All these images actually had a different colorspace than what java imaging uses. Because of this, when we need the pixel values of image to print it on pdf (by calling BufferedImage.getRGB()), it tries to convert this colorspace to RGB colorspace and that is very very costly. That is where the entire time goes. So how do you fix it? I opened all the images in an image editor and saved it again. This time it got saved in standard RGB colorspace and the time taken to create the pdf got reduced from 110 sec to 1.5 seconds. That is huge!!! Isn't it? But can you control all the images over the web? NO.. right? Read on.. there is more to this story.

A little bit of looking up on web pointed me to this Sun bug which is the exact same bug which we were hitting. Thankfully it got fixed in mustang i.e JDK1.6 which ColdFusion8 uses by default. But hey wait a second.. Didn't Andy say that he is seeing it on ColdFusion 8? why do we still see this happening when it is fixed in JDK1.6? It appears that this bug was fixed only in core JDK api but not in JAI (Java advanced imaging) codecLib that ColdFusion 8 uses. So what do we do now? You can do either of these two

  1. Remove clibwrapper_jiio.jar from "lib" folder.
  2. Or, set this system property to the JVM. -Dcom.sun.media.imageio.disableCodecLib=true . You can set this in [cf-install_dir]/runtime/bin/jvm.config if you are using standalone coldfusion server.

You should keep in mind that codecLib libraries are native libraries which are meant to increase the java imaging performance. So disabling it might degrade the performance of CFImage somewhere. Also keep in mind that removing this jar or disabling codecLib will not result into any loss of functionality - it just means that all image operations will be pure java.

There is another related Sun's bug which I thought might be useful to you. Image loading might get very slow if the server is running in debug mode. Your server is running in debug mode if you see something like this in your jvm.config or VM startup option.

-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005
This bug got introduced in JDK1.6 and does not exist on 1.5. So make sure that you are not running the server in debug mode.

To summarise, you can do following to increase the performance of image loading in cfdocument.
  1. If you are on JDK1.5, there is not much you can do. The only option is to change the colorspace of images. I will try to see if we can address this in ColdFusion code.
  2. If you are on JDK1.6,
    • Disable codecLib as mentioned above.
    • Disable debug mode by removing the complete debug string mentioned above
  3. In addition to this, you might want to use 'localurl' attribute for cfdocument tag. See this for more details.

6 comments:

Unknown said...

Excellent article Rupesh!

Unknown said...

As the one who brought up this issue, I can say from the bottom of my heart, THANK YOU Rupesh. I just tried your simple fix, which was to resave the images with a different color profile and it worked like a charm. Not to mention that it also reduced the file size of all of the images used in this particular proposal from 1.35 megs to 776k. That's what you get when you let the client upload their own images.

I created an action for the client which alters the built-in color profile to sRGB. I'll push that to them and ask them to change their file saving strategy.

You rock my friend!

Rupesh Kumar said...

@Hemant, thanks !

@Creole,I am glad to know that it helped and thanks for the nice comment.
I am curious to know how do you change the color profile to sRGB programmatically on upload? Are you using cfimage for that?

webRat said...

@Rupesh, he said he created an action, so I'm assuming that means he created a Photoshop action that manipulates the color profile to sRGB.

Ben Torrey said...

I have a weird one. I developed a fairly complex cfdocument report with JPEG images. It worked fine in my test environment, producing a 185 page document in about 10 seconds.

But, as soon as I moved it over to production (CF 7.0.2 Cumulative Hotfix 3 running on Server 2003/IIS 6.0), it takes 30-60 seconds for even 5 pages of the report.

Then, I tried a funny thing. I switched the images to PNG, and the PDF created as quick in production as it did in my test environment.

My images are all RGB, but JPEG's slow down the report in my production environment.

java -version gives me the same in my test and production environments.

Unknown said...

Rupesh, I'm experiencing this issue on my live server (but not my test server).

I tried both work-arounds:

1. Remove clibwrapper_jiio.jar from "lib" folder.
2. Or, set this system property to the JVM. -Dcom.sun.media.imageio.disableCodecLib=true . You can set this in [cf-install_dir]/runtime/bin/jvm.config if you are using standalone coldfusion server.

But neither seemed to fix the issue. You also suggested re-saving my images, but I have a TON of them and would rather solve it from a server standpoint (since it works just fine on the test server).

I checked the difference between the server settings live vs. test in the CFAdmin on the Settings Summary and the only difference I can see is the following:

Test: Adobe Driver Version 3.6 (Build 0017)
Live: Adobe Driver Version 3.6 (Build 0027)

Any Ideas?

Thanks!!