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".