1 /* Copyright (C) 2005-2011 Fabio Riccardi */ 2 3 package com.lightcrafts.jai.opimage; 4 5 import com.lightcrafts.mediax.jai.PointOpImage; 6 import com.lightcrafts.mediax.jai.ImageLayout; 7 import com.lightcrafts.mediax.jai.RasterFormatTag; 8 import com.lightcrafts.mediax.jai.RasterAccessor; 9 import com.lightcrafts.media.jai.util.ImageUtil; 10 import com.lightcrafts.utils.ColorScience; 11 12 import java.awt.image.*; 13 import java.awt.*; 14 import java.util.Map; 15 16 /** 17 * Copyright (C) Light Crafts, Inc. 18 * User: fabio 19 * Date: Mar 20, 2007 20 * Time: 4:32:46 PM 21 */ 22 public class HDROpImage2 extends PointOpImage { 23 private static final int div = 2; 24 private static final int c = 0x10000 / div; 25 26 private final double detail; 27 private final double shadows; 28 private final double highlights; 29 HDROpImage2(RenderedImage source, RenderedImage mask, double shadows, double highlights, double detail, Map config)30 public HDROpImage2(RenderedImage source, RenderedImage mask, double shadows, double highlights, double detail, Map config) { 31 super(source, mask, new ImageLayout(source), config, true); 32 33 int numBandsSrc = source.getSampleModel().getNumBands(); 34 int numBandsMask = mask.getSampleModel().getNumBands(); 35 int dataType = source.getSampleModel().getDataType(); 36 37 if (!(source.getSampleModel() instanceof PixelInterleavedSampleModel)) 38 throw new UnsupportedOperationException("Unsupported sample model: " + source.getSampleModel().getClass()); 39 40 if (dataType != DataBuffer.TYPE_USHORT) 41 throw new UnsupportedOperationException("Unsupported data type: " + dataType); 42 43 if (numBandsSrc != 3) 44 throw new UnsupportedOperationException("Only three-banded sources are supported: " + numBandsSrc); 45 46 if (numBandsMask != 1 && numBandsMask != 3) 47 throw new UnsupportedOperationException("Only single-banded or three-banded masks are supported: " + numBandsMask); 48 49 permitInPlaceOperation(); 50 51 this.detail = 1 + (detail - 1) / 5; 52 this.shadows = 1 + (shadows - 1) / 5; 53 this.highlights = highlights; 54 } 55 computeRect(Raster[] sources, WritableRaster dest, Rectangle destRect)56 protected void computeRect(Raster[] sources, 57 WritableRaster dest, 58 Rectangle destRect) { 59 // Retrieve format tags. 60 RasterFormatTag[] formatTags = getFormatTags(); 61 62 RasterAccessor s1 = new RasterAccessor(sources[0], destRect, 63 formatTags[0], 64 getSourceImage(0).getColorModel()); 65 RasterAccessor s2 = new RasterAccessor(sources[1], destRect, 66 formatTags[1], 67 getSourceImage(1).getColorModel()); 68 RasterAccessor d = new RasterAccessor(dest, destRect, 69 formatTags[2], getColorModel()); 70 71 switch (d.getDataType()) { 72 case DataBuffer.TYPE_USHORT: 73 computeRectUShort(s1, s2, d); 74 break; 75 default: 76 throw new UnsupportedOperationException("Unsupported data type: " + d.getDataType()); 77 } 78 79 if (d.needsClamping()) { 80 d.clampDataArrays(); 81 } 82 d.copyDataToRaster(); 83 } 84 softLightBlendPixelsIntensity(int front, int back, short intensityTable[])85 private static int softLightBlendPixelsIntensity(int front, int back, short intensityTable[]) { 86 int m = front * back / c; 87 int s = c - (c - front) * (c - back) / c; 88 int p = 0xffff & intensityTable[back]; 89 return (c - p) * m / c + (p * s) / c; 90 } 91 softLightBlendPixels(int front, int back)92 private static int softLightBlendPixels(int front, int back) { 93 int m = front * back / c; 94 int s = c - (c - front) * (c - back) / c; 95 return (c - back) * m / c + (back * s) / c; 96 } 97 softLightBlendPixels(double front, double back)98 private static double softLightBlendPixels(double front, double back) { 99 double m = front * back; 100 // double s = 1 - (1 - front) * (1 - back); 101 return (1 - back) * m * m; // + (back * s); 102 } 103 screenBlendPixels(int front, int back)104 private static int screenBlendPixels(int front, int back) { 105 return c - (c - front) * (c - back) / c; 106 } 107 screenBlendPixelsIntensity(int front, int back, short intensityTable[])108 private static int screenBlendPixelsIntensity(int front, int back, short intensityTable[]) { 109 int s = c - (c - front) * (c - back) / c; 110 int p = 0xffff & intensityTable[back]; 111 return (p * s) / c; 112 } 113 114 // int wr = (int) (0x2000 * ColorScience.Wr); 115 // int wg = (int) (0x2000 * ColorScience.Wg); 116 // int wb = (int) (0x2000 * ColorScience.Wb); 117 cBlendLoop(short[] srcData, short[] maskData, short[] dstData, int[] srcBandOffsets, int[] maskBandOffsets, int[] dstBandOffsets, int dstwidth, int dstheight, int srcLineStride, int srcPixelStride, int maskLineStride, int maskPixelStride, int dstLineStride, int dstPixelStride, float shadows, float detail, float highlights, float wr, float wg, float wb)118 private static native void cBlendLoop(short[] srcData, short[] maskData, short[] dstData, 119 int[] srcBandOffsets, int[] maskBandOffsets, int[] dstBandOffsets, 120 int dstwidth, int dstheight, int srcLineStride, int srcPixelStride, 121 int maskLineStride, int maskPixelStride, int dstLineStride, int dstPixelStride, 122 float shadows, float detail, float highlights, float wr, float wg, float wb); 123 blendLoop(short[] srcData, short[] maskData, short[] dstData, int[] srcBandOffsets, int[] maskBandOffsets, int[] dstBandOffsets, int dstwidth, int dstheight, int srcLineStride, int srcPixelStride, int maskLineStride, int maskPixelStride, int dstLineStride, int dstPixelStride, float shadows, float detail, float highlights, float wr, float wg, float wb)124 private static void blendLoop(short[] srcData, short[] maskData, short[] dstData, 125 int[] srcBandOffsets, int[] maskBandOffsets, int[] dstBandOffsets, 126 int dstwidth, int dstheight, int srcLineStride, int srcPixelStride, 127 int maskLineStride, int maskPixelStride, int dstLineStride, int dstPixelStride, 128 float shadows, float detail, float highlights, float wr, float wg, float wb) { 129 int srcROffset = srcBandOffsets[0]; 130 int srcGOffset = srcBandOffsets[1]; 131 int srcBOffset = srcBandOffsets[2]; 132 133 int maskOffset1, maskOffset2, maskOffset3; 134 135 if (maskBandOffsets.length == 3) { 136 maskOffset1 = maskBandOffsets[0]; 137 maskOffset2 = maskBandOffsets[1]; 138 maskOffset3 = maskBandOffsets[2]; 139 } else 140 maskOffset1 = maskOffset2 = maskOffset3 = maskBandOffsets[0]; 141 142 int dstROffset = dstBandOffsets[0]; 143 int dstGOffset = dstBandOffsets[1]; 144 int dstBOffset = dstBandOffsets[2]; 145 146 for (int row = 0; row < dstheight; row++) { 147 for (int col = 0; col < dstwidth; col++) { 148 int r = (0xffff & srcData[srcPixelStride * col + row * srcLineStride + srcROffset]); 149 int g = (0xffff & srcData[srcPixelStride * col + row * srcLineStride + srcGOffset]); 150 int b = (0xffff & srcData[srcPixelStride * col + row * srcLineStride + srcBOffset]); 151 152 double m = (0xffff & maskData[maskPixelStride * col + row * maskLineStride + maskOffset1])/(double) 0xffff; 153 if (maskBandOffsets.length == 3) { 154 double um = (0xffff & maskData[maskPixelStride * col + row * maskLineStride + maskOffset2])/(double) 0xffff; 155 um = Math.min(um*um, 1); 156 157 double bm = (0xffff & maskData[maskPixelStride * col + row * maskLineStride + maskOffset3])/(double) 0xffff; 158 m = um * m + (1-um) * bm; 159 } 160 161 double y = (wr * r + wg * g + wb * b) / 0xffff; 162 163 // y = (1-m) * y * highlights + (1-highlights) * y; 164 165 // double ly = Math.log(y); 166 // double lm = Math.log(m); 167 // double diff = ly - lm; 168 169 // double diff = Math.log(y/m); 170 171 // double mm = Math.exp(lm / shadows + diff * detail); 172 173 double mm = Math.pow(m, 1/shadows) * Math.pow(y/m, detail); 174 175 // double ratio = (Math.sqrt(1-m) * highlights + (1-highlights)) * mm / y; 176 177 double compressedHilights = softLightBlendPixels(1 - m, y); 178 179 double ratio = (compressedHilights * highlights + (1-highlights)) * mm / y; 180 181 r *= ratio; 182 g *= ratio; 183 b *= ratio; 184 185 dstData[dstPixelStride * col + row * dstLineStride + dstROffset] = ImageUtil.clampUShort(r); 186 dstData[dstPixelStride * col + row * dstLineStride + dstGOffset] = ImageUtil.clampUShort(g); 187 dstData[dstPixelStride * col + row * dstLineStride + dstBOffset] = ImageUtil.clampUShort(b); 188 } 189 } 190 } 191 computeRectUShort(RasterAccessor src, RasterAccessor mask, RasterAccessor dst)192 private void computeRectUShort(RasterAccessor src, 193 RasterAccessor mask, 194 RasterAccessor dst) { 195 int srcLineStride = src.getScanlineStride(); 196 int srcPixelStride = src.getPixelStride(); 197 int[] srcBandOffsets = src.getBandOffsets(); 198 short[] srcData = src.getShortDataArrays()[0]; 199 200 int maskLineStride = mask.getScanlineStride(); 201 int maskPixelStride = mask.getPixelStride(); 202 int[] maskBandOffsets = mask.getBandOffsets(); 203 short[] maskData = mask.getShortDataArrays()[0]; 204 205 int dstwidth = dst.getWidth(); 206 int dstheight = dst.getHeight(); 207 // int dstBands = dst.getNumBands(); 208 int dstLineStride = dst.getScanlineStride(); 209 int dstPixelStride = dst.getPixelStride(); 210 int[] dstBandOffsets = dst.getBandOffsets(); 211 short[] dstData = dst.getShortDataArrays()[0]; 212 213 cBlendLoop(srcData, maskData, dstData, 214 srcBandOffsets, maskBandOffsets, dstBandOffsets, 215 dstwidth, dstheight, srcLineStride, srcPixelStride, 216 maskLineStride, maskPixelStride, dstLineStride, dstPixelStride, 217 (float) shadows, (float) detail, (float) highlights, 218 ColorScience.Wr, ColorScience.Wg, ColorScience.Wb); 219 } 220 } 221