1

Short version: Is there any simple way how to find out if the JPG file is CMYK or RGB in Delphi XE? Preferably without any additional libraries...

Longer version: I have a 3rd party library that accepts JPEG. But for whatever reason the library needs to know whether they are in CMYK or RGB colorspace. And what is worse it renders the CMYK ones with wrong colors (probably something with CMS or so...). Delphi itself (TJPEGImage) displays the CMYK image correctly but it seems that all the "CMYK vs RGB stuff" is hidden in jpeg.pas implementation section and is not published...

I searched a lot of stuff on the Internet but here I found only few years old posts. Also I've found Gabriel Corneanu's modified jpeg.dcu but it is all about making Delphi load the image correctly. And it seems that XE does load the CMYK JPEGs correctly.

In the end I would prefer to convert the CMYK image to RGB and even as it sounds horrible I do not mind doing it by recoding the JPEG (if there is no other better option). Basically load it to bitmap and save the bitmap as JPEG if needed...

P.S. I would like to avoid bringing another libraries to my project as much as possible and I would like to stay within "standard Delphi" as much as possible so if I ever need to move this project to Mac, iOS or Android I do not have to deal with a lot of external stuff...

mghie
  • 32,028
  • 6
  • 87
  • 129
Radek Hladík
  • 547
  • 4
  • 15
  • I've been looking into that and I've seen the CMYK detection, CMYK to RGB converison, etc... But as I said its hidden in the implementation section. But modifying that unit may be a way (just exposing one of the internal stuff) if there is no other better solution – Radek Hladík Sep 14 '14 at 11:25
  • Gabriel Corneanu's modified jpeg.dcu has a property `TJpegImage.IsCMYK`. but I'm not sure if it fits delphi-xe – kobik Sep 14 '14 at 13:20
  • @kobik, his solution is as simple (and somewhat fragile) as `Assigned(FBitmap) and (FBitmap.PixelFormat = pf32bit)`. Class helper heeded, ofc. – Free Consulting Sep 14 '14 at 15:23
  • Unfortunately exported PixelFormat in XE has only options TJPEGPixelFormat = (jf24Bit, jf8Bit); And I would really like to avoid using precompiled DCU without source code - and Gabriel Corneanu mentioned somewhere that he did not release the source code as he did not know whether it would be OK with Embarcadero (as it was based on their source code).... – Radek Hladík Sep 14 '14 at 15:56

2 Answers2

1

A simple way that will probably work nearly al the time is to search the images for the SOF (Start of Frame) marker.
If that marker has 1 component, the image is grayscale; if it has 3 components it is likely to be YCbCr; and if it has 4 components it is likely to be CMYK.

If you want a more reliable method, you would need to identify the JPEG file format. For that you would read the APPn markers. From there, the processing would depend upon the type of file found.

Jan Doggen
  • 8,799
  • 13
  • 70
  • 144
user3344003
  • 20,574
  • 3
  • 26
  • 62
  • It would be an option to - parse the JPEG file to certain level. However I have no idea how JPEG looks inside and how SOF marker looks like. Not to mention counting its fields. But if you think that it would be a not so difficult way, I can look into JPEG format specification... The sad thing is that Delphi already does all this, I have found the exact line in jpeg.pas, where the information is present and all I need is to grab it somehow :-) – Radek Hladík Sep 14 '14 at 21:16
  • There are a couple of tricks you have to watch out for. The first is that some JPEG file formats allow a thumbnail to be embedded in an APPn marker. Whenever you hit an APPn marker, you need to check the size and skip over that many bytes before resuming the scan. The next trick is that there there are 13 different Start of Frame Markers (only 3 of which you are likely to encounter). However, number of components in the frame is in a fixed structure that is the same for all SOFn markers. Remember that the lengths are encoded bigendian so you have to reverse them for Intel. – user3344003 Sep 15 '14 at 14:52
1

We've narrowed the solutions to three:

  • Parse the JPEG ourselves - this seems to be risky
  • Slightly modify Delphi's jpeg.pas (change the name of the class and expose the CMYK info) - this seems to be viable option but we are not sure if it is copyright OK and as jpeg.pas heavily uses a lot of OBJs this could prove unusable on other platforms in the future
  • Use 3rd party library, we've found NativeJPG http://www.simdesign.nl/nativejpg.html and it seems to do the job quite well and it should be written in pure Pascal so we think that there is quite a good chance it will be easy to port to other platfroms if needed.
Radek Hladík
  • 547
  • 4
  • 15
  • See the modified copy of jpeg by Andreotti in http://stackoverflow.com/questions/3143543/handling-cmyk-jpeg-files-in-delphi-7. Juse drop the files into your project source. The linker will use these instead of the Codegear ones. – Rohit Gupta Jun 10 '16 at 02:04