1 /* Copyright (C) 2005-2011 Fabio Riccardi */
2 
3 package com.lightcrafts.jai;
4 
5 import com.lightcrafts.utils.ColorScience;
6 
7 import com.lightcrafts.mediax.jai.LookupTableJAI;
8 import com.lightcrafts.mediax.jai.RasterFactory;
9 import com.lightcrafts.mediax.jai.RasterAccessor;
10 import com.lightcrafts.mediax.jai.RasterFormatTag;
11 import java.awt.image.WritableRaster;
12 import java.awt.image.Raster;
13 import java.awt.image.SampleModel;
14 import java.awt.*;
15 
16 
17 /**
18  * Special case of LookupTableJAI to apply the lookup on the lightness of the image.
19  * Only works on InterleavedSampleModel and on 16 bit images with uniform types
20  */
21 
22 public class LightnessLookupTable extends LookupTableJAI {
LightnessLookupTable(short[] shorts, boolean b)23     public LightnessLookupTable(short[] shorts, boolean b) {
24         super(shorts, b);
25     }
26 
27     @Override
lookup(Raster src, WritableRaster dst, Rectangle rect)28     public WritableRaster lookup(Raster src, WritableRaster dst, Rectangle rect) {
29         // Validate source.
30         if (src == null) {
31             throw new IllegalArgumentException("Null Source");
32         }
33 
34         if (src.getNumBands() != 3)
35             return super.lookup(src, dst, rect);
36 
37         SampleModel srcSampleModel = src.getSampleModel();
38         if (!isIntegralDataType(srcSampleModel)) {
39             throw
40               new IllegalArgumentException("Source Data Type must be an Integral Data Type");
41         }
42 
43         // Validate rectangle.
44         if (rect == null) {
45             rect = src.getBounds();
46         } else {
47             rect = rect.intersection(src.getBounds());
48         }
49 
50         if (dst != null) {
51             rect = rect.intersection(dst.getBounds());
52         }
53 
54         // Validate destination.
55         SampleModel dstSampleModel;
56         if (dst == null) {	// create dst according to table
57             dstSampleModel = getDestSampleModel(srcSampleModel,
58                                                 rect.width, rect.height);
59             dst =
60                 RasterFactory.createWritableRaster(dstSampleModel,
61                                                    new Point(rect.x, rect.y));
62         } else {
63             dstSampleModel = dst.getSampleModel();
64 
65             if (dstSampleModel.getTransferType() != getDataType() ||
66                 dstSampleModel.getNumBands() !=
67                 getDestNumBands(srcSampleModel.getNumBands())) {
68                 throw new
69                   IllegalArgumentException("Incompatible Destination Image");
70             }
71         }
72 
73         // Add bit support?
74         int sTagID = RasterAccessor.findCompatibleTag(null, srcSampleModel);
75         int dTagID = RasterAccessor.findCompatibleTag(null, dstSampleModel);
76 
77         RasterFormatTag sTag = new RasterFormatTag(srcSampleModel,sTagID);
78         RasterFormatTag dTag = new RasterFormatTag(dstSampleModel,dTagID);
79 
80         RasterAccessor s = new RasterAccessor(src, rect, sTag, null);
81         RasterAccessor d = new RasterAccessor(dst, rect, dTag, null);
82 
83         /*int srcNumBands = s.getNumBands();
84         int srcDataType = s.getDataType();
85 
86         int tblNumBands = getNumBands();
87         int tblDataType = getDataType();*/
88 
89         int width = d.getWidth();
90         int height = d.getHeight();
91         int bands = d.getNumBands();
92         // int dstDataType = d.getDataType();
93 
94         // Source information.
95         int srcLineStride = s.getScanlineStride();
96         int srcPixelStride = s.getPixelStride();
97         int[] srcBandOffsets = s.getBandOffsets();
98 
99         short[][] srcData = s.getShortDataArrays();
100 
101         // Table information.
102         int[] tblOffsets = getOffsets();
103 
104         short[][] tblData = getShortData();
105 
106         // Destination information.
107         int dstLineStride = d.getScanlineStride();
108         int dstPixelStride = d.getPixelStride();
109         int[] dstBandOffsets = d.getBandOffsets();
110 
111         short[][] dstData = d.getShortDataArrays();
112 
113         int lowBandOffset = 0;
114         for (int b = 0; b < bands; b++)
115             if (srcBandOffsets[b] < srcBandOffsets[lowBandOffset])
116                 lowBandOffset = b;
117 
118         short[] sd = srcData[lowBandOffset];
119         short[] dd = dstData[lowBandOffset];
120         short[] td = tblData[0];
121 
122         int srcLineOffset = srcBandOffsets[lowBandOffset];
123         int dstLineOffset = dstBandOffsets[lowBandOffset];
124         int tblOffset = tblOffsets[0];
125 
126         for (int h = 0; h < height; h++) {
127             int srcPixelOffset = srcLineOffset;
128             int dstPixelOffset = dstLineOffset;
129 
130             srcLineOffset += srcLineStride;
131             dstLineOffset += dstLineStride;
132 
133             final int scale = 0x4000;
134 
135             int minOffset = Math.min(srcBandOffsets[0], Math.min(srcBandOffsets[1], srcBandOffsets[2]));
136 
137             int wr = (int) (ColorScience.W[srcBandOffsets[0] - minOffset] * scale);
138             int wg = (int) (ColorScience.W[srcBandOffsets[1] - minOffset] * scale);
139             int wb = (int) (ColorScience.W[srcBandOffsets[2] - minOffset] * scale);
140 
141             for (int w = 0; w < width; w++) {
142                 int sr = sd[srcPixelOffset + 0] & 0xFFFF;
143                 int sg = sd[srcPixelOffset + 1] & 0xFFFF;
144                 int sb = sd[srcPixelOffset + 2] & 0xFFFF;
145 
146                 int lum = (wr * sr + wg * sg + wb * sb) / scale;
147 
148                 // prevent index out of bounds exceptions
149                 int index = lum - tblOffset;
150                 int val = td[index < 0 ? 0 : index >= 0xFFFF ? 0xFFFF : index] & 0xFFFF;
151 
152                 // int mul = sg > 0 ? (scale * val) / sg : scale;
153                 int mul = lum > 0 ? (scale * val) / lum : scale;
154 
155                 int prod = (mul * sr) / scale;
156                 dd[dstPixelOffset + 0] = prod > 0xFFFF ? (short) 0xFFFF : (short) prod;
157 
158                 prod = (mul * sg) / scale;
159                 dd[dstPixelOffset + 1] = prod > 0xFFFF ? (short) 0xFFFF : (short) prod;
160 
161                 prod = (mul * sb) / scale;
162                 dd[dstPixelOffset + 2] = prod > 0xFFFF ? (short) 0xFFFF : (short) prod;
163 
164                 srcPixelOffset += srcPixelStride;
165                 dstPixelOffset += dstPixelStride;
166             }
167         }
168 
169         d.copyDataToRaster();
170 
171         return dst;
172     }
173 
clamp(int in, int maxVal)174     static final int clamp(int in, int maxVal) {
175 	return (in > maxVal ? maxVal : in);
176     }
177 }
178