In message <[EMAIL PROTECTED]>
          Alexey Ushakov <[EMAIL PROTECTED]> wrote:

> Hello Mark,

> Could you please provide more info concerning your problem?  It's
> difficult to say the exact reason without having complete standalone
> testcase with appropriate input data.
> The problem that you are describing could be caused by limited precision
> of kodak color management library (16 bit fixed point) that we are using
> for color conversions. But again I cannot say anything determine without
> having complete testcase.

> Best Regards,
> Alexey

I have found a solution for my problem so posting it here in case its
useful in the future to someone.

There are some JPEGs which describe themselves as CMYK when they are
in fact encoded using a different colorspace called YCCK. The way to
process them is to convert the YCC part to CMY then add back the K and
convert CMYK to sRGB.

If you want to do this accurately you need profiles for both parts -
there are mathematical formulae but they do not get perfect colour
matches.

There are some YCC/CMYK profiles to download as part of the JAICMM
package.

MArk


===========================================================

Code from GPL JPedal PDF library to convert YCCK to sRGB with
profiles.


    /**
      * save raw CMYK data by converting to RGB using algorithm
     method -
      * pdfsages supplied the C source and I have converted -
      * This works very well on most colours but not dark shades
     which are
      * all rolled into black
      *
      * profile is a set of comma deliminated values providing YCC,
CMY and optionally CMYK from
      * -Dorg.jpedal.useICC (remember double quotes if it includes
spaces)
      * example -Dorg.jpedal.useICC="YCC=C:/profiles/ycc.pf,CMY=C:/
profiles/cmy.pf
      * (can include optional CMYK= values if you wish to change
default CMYK profile used)
      *
      *
      */
     private static ICC_ColorSpace YCC=null,CMY=null;
     private static ColorSpace CMYK=null;

     public static BufferedImage iccConvertCMYKImageToRGB(
      byte[] buffer,
      int w,
      int h,String profile) throws IOException {

         /**
          * get profile values for colorspaces for ICC colorspaces
          */
         String YCCprofile=null,CMYprofile=null,CMYKprofile=null;

         StringTokenizer profiles=new StringTokenizer(profile,",");
         while(profiles.hasMoreTokens()){
             String nextProfile=profiles.nextToken();

             //extract value
             int index=nextProfile.indexOf("=");

             if(index==-1)
             throw new RuntimeException("Wrong parameter in "+profile
+"\nPlease use comma-separated set of uses such as YCC=/desktop/
ycc.pf,CMY=/desktop/cmy.pf");

             String key=nextProfile.substring(0,index).trim();
             String value=nextProfile.substring(index+1).trim();

             if(key.equals("YCC"))
                 YCCprofile=value;
             else if(key.equals("CMY"))
                 CMYprofile=value;
             else if(key.equals("CMYK"))
                 CMYKprofile=value;
             else
                 throw new RuntimeException("Unknown parameter in
"+profile+"\nPlease use comma-separated set of uses such as YCC= CMY=

or (optional value) CMYK=");

         }

         /**
          * set colorspaces and color models using profiles ifn ot
previously initialised
          */
         if(CMYK==null){

             //optional alternative CMYK
             if(CMYKprofile==null)
                 CMYK=new DeviceCMYKColorSpace().getColorSpace();
             else{
                 try {
                     CMYK=new
ICC_ColorSpace(ICC_Profile.getInstance(new
FileInputStream(CMYKprofile)));
                 } catch (Exception e) {
                     throw new RuntimeException("Unable to create CMYK

colorspace with  "+CMYKprofile+"\nPlease check Path and file valid or

use built-in");
                 }
             }

             if(YCCprofile==null){
                 throw new RuntimeException("Mandatory YCC value not
supplied in "+profile+"\nPlease add ,YCC=yourPath/yourYCCprofile.pf");
             }else{
                 try {
                     YCC=new
ICC_ColorSpace(ICC_Profile.getInstance(new
FileInputStream(YCCprofile)));
                 } catch (Exception e) {
                     throw new RuntimeException("Unable to create YCC

colorspace with  "+YCCprofile+"\nPlease check Path and file valid");
                 }
             }

             if(CMYprofile==null){
                 throw new RuntimeException("Mandatory CMY value not
supplied in "+profile+"\nPlease add ,CMY=yourPath/yourCMYprofile.pf");
             }else{
                 try {
                     CMY=new
ICC_ColorSpace(ICC_Profile.getInstance(new
FileInputStream(CMYprofile)));
                 } catch (Exception e) {
                     throw new RuntimeException("Unable to create CMY

colorspace with  "+CMYprofile+"\nPlease check Path and file valid");
                 }
             }

             //needed for sRGB conversion
             rgbCS = new
ICC_ColorSpace(ICC_Profile.getInstance(ColorSpace.CS_sRGB));
             rgbModel = new ComponentColorModel(rgbCS, new int[] { 8,

8, 8 }, false, false, ColorModel.OPAQUE, DataBuffer.TYPE_BYTE);
             CSToRGB = new ColorConvertOp(CMYK, rgbCS,
ColorSpaces.hints);

         }

      int pixelCount = w * h*4;
         int Y,Cb,Cr,CENTER,lastY=-1,lastCb=-1,lastCr=-1,lastCENTER=-1
;
         float[] CMYvalues=new float[3],YCCvalues,CIEvalues;

         int cachedValues =0;
         Map cache =new HashMap();

         //turn YCC in Buffer to CYM using profile
         for (int i = 0; i < pixelCount; i = i + 4) {

             Y=(buffer[i] & 255);
             Cb = (buffer[i+1] & 255);
       Cr = (buffer[i+2] & 255);
       CENTER = (buffer[i+3] & 255);

             if(Y==lastY && Cb==lastCb && Cr==lastCr &&
CENTER==lastCENTER){
                 //no change so use last value
             }else{ //new value

                 //we store values to speedup operation
                 Integer key=Integer.valueOf(Y+(Cb<<8)+(Cr<<16));
                 Object cachedValue= cache.get(key);

                 if(cachedValue==null){

                     //this is the slow bit
                     YCCvalues= new float[]{(Y / 255f), (Cb / 255f),
(Cr / 255f)};
                     CIEvalues=YCC.toCIEXYZ(YCCvalues);
                     CMYvalues=CMY.fromCIEXYZ(CIEvalues);

                     //stop cache taking up too much memory by
flushing if too many values
                     if(cachedValues >1000){
                         cachedValues =0;
                         cache.clear();
                     }
                     cache.put(key,CMYvalues);

                 }else
                     CMYvalues=(float[]) cachedValue;

                 //flag so we can just reuse if next value the same
                 lastY=Y;
                 lastCb=Cb;
                 lastCr=Cr;
                 lastCENTER=CENTER;
             }

             //put back as CMY
             buffer[i]=(byte)(CMYvalues[0]*255);
             buffer[i+1]=(byte)(CMYvalues[1]*255);
             buffer[i+2]=(byte)(CMYvalues[2]*255);
         }

         /**
          * create CMYK raster from buffer
          */
         Raster raster = Raster.createInterleavedRaster(new
DataBufferByte(buffer,buffer.length), w,h,w * 4,4, new int[]{ 0, 1, 2,

3 },null);
         WritableRaster rgbRaster
=rgbModel.createCompatibleWritableRaster(w, h);

         /**
          * convert to sRGB fwith profiles (I think this is done
native as its much faster than my pure Java efforts)
          */
         CSToRGB.filter(raster, rgbRaster);

         //data now sRGB so create image
         BufferedImage image =new
BufferedImage(w,h,BufferedImage.TYPE_INT_RGB);
         image.setData(rgbRaster);

         return image;
     }

===========================================================================
To unsubscribe, send email to [EMAIL PROTECTED] and include in the body
of the message "signoff JAVA2D-INTEREST".  For general help, send email to
[EMAIL PROTECTED] and include in the body of the message "help".

Reply via email to