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