1 /* Copyright (C) 2005-2011 Fabio Riccardi */
2 
3 package com.lightcrafts.jai.opimage;
4 
5 import com.lightcrafts.jai.operator.LCMSColorConvertDescriptor;
6 import com.lightcrafts.mediax.jai.RasterAccessor;
7 import com.lightcrafts.mediax.jai.RasterFormatTag;
8 import com.lightcrafts.utils.LCMS;
9 import com.lightcrafts.utils.LCMS_ColorSpace;
10 
11 import com.lightcrafts.mediax.jai.PointOpImage;
12 import com.lightcrafts.mediax.jai.ImageLayout;
13 
14 import java.awt.image.*;
15 import java.awt.*;
16 import java.awt.color.ICC_ColorSpace;
17 import java.awt.color.ColorSpace;
18 import java.awt.color.ICC_Profile;
19 import java.util.Map;
20 
21 public class LCMSColorConvertOpImage extends PointOpImage {
22     private final LCMSColorConvertDescriptor.RenderingIntent intent;
23     private final LCMSColorConvertDescriptor.RenderingIntent proofIntent;
24     private final ColorModel targetColorModel;
25     private final ICC_Profile proof;
26     private LCMS.Transform transform = null;
27     final RenderedImage source;
28 
LCMSColorConvertOpImage(RenderedImage source, Map config, ImageLayout layout, ColorModel colorModel, LCMSColorConvertDescriptor.RenderingIntent intent, ICC_Profile proof, LCMSColorConvertDescriptor.RenderingIntent proofingIntent)29     LCMSColorConvertOpImage(RenderedImage source,
30                             Map config,
31                             ImageLayout layout,
32                             ColorModel colorModel,
33                             LCMSColorConvertDescriptor.RenderingIntent intent,
34                             ICC_Profile proof,
35                             LCMSColorConvertDescriptor.RenderingIntent proofingIntent) {
36         super(source, layout, config, true);
37         this.source = source;
38         targetColorModel = colorModel;
39         this.proof = proof;
40         this.intent = intent;
41         this.proofIntent = proofingIntent;
42 
43         permitInPlaceOperation();
44     }
45 
mapLCMSType(int csType, int transferType)46     static private int mapLCMSType(int csType, int transferType) {
47         if (transferType != DataBuffer.TYPE_BYTE && transferType != DataBuffer.TYPE_USHORT)
48             throw new IllegalArgumentException( "Unsupported Data Type: " + transferType );
49 
50         switch(csType) {
51             case ColorSpace.TYPE_GRAY:
52                 return transferType == DataBuffer.TYPE_BYTE ? LCMS.TYPE_GRAY_8 : LCMS.TYPE_GRAY_16;
53             case ColorSpace.TYPE_RGB:
54                 return transferType == DataBuffer.TYPE_BYTE ? LCMS.TYPE_RGB_8 : LCMS.TYPE_RGB_16;
55             case ColorSpace.TYPE_CMYK:
56                 return transferType == DataBuffer.TYPE_BYTE ? LCMS.TYPE_CMYK_8 : LCMS.TYPE_CMYK_16;
57             case ColorSpace.TYPE_Lab:
58                 return transferType == DataBuffer.TYPE_BYTE ? LCMS.TYPE_Lab_8 : LCMS.TYPE_Lab_16;
59             default:
60                 throw new IllegalArgumentException( "Unsupported Color Space Type: " + csType );
61         }
62     }
63 
64     @Override
computeRect(Raster[] sources, WritableRaster dest, Rectangle destRect)65     protected void computeRect(Raster[] sources, WritableRaster dest, Rectangle destRect) {
66         synchronized (this) {
67             if (transform == null) {
68                 int lcms_intent = intent.getValue() < 4 ? intent.getValue() : LCMS.INTENT_RELATIVE_COLORIMETRIC;
69                 int lcms_proofIntent = proofIntent.getValue() < 4 ? proofIntent.getValue() : LCMS.INTENT_RELATIVE_COLORIMETRIC;
70                 int lcms_flags = intent.getValue() == 4 || proofIntent.getValue() == 4
71                                  ? LCMS.cmsFLAGS_BLACKPOINTCOMPENSATION
72                                  : 0;
73 
74                 ColorSpace sourceCS = source.getColorModel().getColorSpace();
75                 LCMS.Profile sourceProfile = sourceCS instanceof LCMS_ColorSpace
76                                              ? ((LCMS_ColorSpace) sourceCS).getProfile()
77                                              : new LCMS.Profile(((ICC_ColorSpace)sourceCS).getProfile());
78 
79                 ColorSpace targetCS = targetColorModel.getColorSpace();
80                 LCMS.Profile targetProfile = targetCS instanceof LCMS_ColorSpace
81                                              ? ((LCMS_ColorSpace) targetCS).getProfile()
82                                              : new LCMS.Profile(((ICC_ColorSpace)targetCS).getProfile());
83 
84                 LCMS.Profile proofProfile = proof != null ? new LCMS.Profile(proof) : null;
85 
86                 int inType = mapLCMSType(sourceCS.getType(), source.getColorModel().getTransferType());
87                 int outType = mapLCMSType(targetCS.getType(), colorModel.getTransferType());
88 
89                 transform = proofProfile != null
90                             ? new LCMS.Transform(sourceProfile, inType, targetProfile, outType, proofProfile,
91                                                  lcms_proofIntent, lcms_intent, lcms_flags)
92                             : new LCMS.Transform(sourceProfile, inType, targetProfile, outType, lcms_intent, lcms_flags);
93             }
94         }
95 
96         RasterFormatTag[] formatTags = getFormatTags();
97         Rectangle srcRect = mapDestRect(destRect, 0);
98         RasterAccessor src = new RasterAccessor(sources[0], srcRect, formatTags[0], getSourceImage(0).getColorModel());
99         RasterAccessor dst = new RasterAccessor(dest, destRect, formatTags[1], this.getColorModel());
100 
101         if (src.getDataType() == dst.getDataType()) {
102             transform.doTransform(src, formatTags[0], getSourceImage(0).getColorModel(),
103                                   dst, formatTags[1], this.getColorModel());
104         }
105         else {
106             throw new IllegalArgumentException("Input and output rasters don't match!");
107         }
108     }
109 }
110