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 11 import java.awt.image.*; 12 import java.awt.*; 13 import java.util.Map; 14 15 /** 16 * Copyright (C) Light Crafts, Inc. 17 * User: fabio 18 * Date: Mar 20, 2007 19 * Time: 4:32:46 PM 20 */ 21 public class HDROpImage extends PointOpImage { 22 private static final int div = 2; 23 private static final int c = 0x10000 / div; 24 25 private final double detail; 26 private short intensityTable[] = new short[c+1]; 27 private short gammaTable[] = new short[0x10000]; 28 private final double intensity; 29 sigmoid(double x)30 private double sigmoid(double x) { 31 return x + intensity * x * (1 - 1 / (1 + Math.exp(-6*(x - 0.01)))); 32 } 33 HDROpImage(RenderedImage source, RenderedImage mask, double intensity, double gamma, double detail, Map config)34 public HDROpImage(RenderedImage source, RenderedImage mask, double intensity, double gamma, double detail, Map config) { 35 super(source, mask, new ImageLayout(source), config, true); 36 37 int numBandsSrc = source.getSampleModel().getNumBands(); 38 int numBandsMask = mask.getSampleModel().getNumBands(); 39 int dataType = source.getSampleModel().getDataType(); 40 41 if (!(source.getSampleModel() instanceof PixelInterleavedSampleModel)) 42 throw new UnsupportedOperationException("Unsupported sample model: " + source.getSampleModel().getClass()); 43 44 if (dataType != DataBuffer.TYPE_USHORT) 45 throw new UnsupportedOperationException("Unsupported data type: " + dataType); 46 47 if (numBandsSrc != 3) 48 throw new UnsupportedOperationException("Only three-banded sources are supported: " + numBandsSrc); 49 50 if (numBandsMask != 1) 51 throw new UnsupportedOperationException("Only single-banded masks are supported: " + numBandsMask); 52 53 permitInPlaceOperation(); 54 55 this.detail = detail; 56 this.intensity = intensity; 57 58 for (int i = 0; i < c+1; i++) 59 intensityTable[i] = (short) (c * sigmoid(i/(double)c)); 60 61 for (int i = 0; i < gammaTable.length; i++) 62 gammaTable[i] = (short) (0xFFFF * Math.pow(i / (double) 0xFFFF, gamma) + 0.5); 63 } 64 computeRect(Raster[] sources, WritableRaster dest, Rectangle destRect)65 protected void computeRect(Raster[] sources, 66 WritableRaster dest, 67 Rectangle destRect) { 68 // Retrieve format tags. 69 RasterFormatTag[] formatTags = getFormatTags(); 70 71 RasterAccessor s1 = new RasterAccessor(sources[0], destRect, 72 formatTags[0], 73 getSourceImage(0).getColorModel()); 74 RasterAccessor s2 = new RasterAccessor(sources[1], destRect, 75 formatTags[1], 76 getSourceImage(1).getColorModel()); 77 RasterAccessor d = new RasterAccessor(dest, destRect, 78 formatTags[2], getColorModel()); 79 80 switch (d.getDataType()) { 81 case DataBuffer.TYPE_USHORT: 82 computeRectUShort(s1, s2, d); 83 break; 84 default: 85 throw new UnsupportedOperationException("Unsupported data type: " + d.getDataType()); 86 } 87 88 if (d.needsClamping()) { 89 d.clampDataArrays(); 90 } 91 d.copyDataToRaster(); 92 } 93 softLightBlendPixelsIntensity(int front, int back, short intensityTable[])94 private static int softLightBlendPixelsIntensity(int front, int back, short intensityTable[]) { 95 int m = front * back / c; 96 int s = c - (c - front) * (c - back) / c; 97 int p = 0xffff & intensityTable[back]; 98 return (c - p) * m / c + (p * s) / c; 99 } 100 softLightBlendPixels(int front, int back)101 private static int softLightBlendPixels(int front, int back) { 102 int m = front * back / c; 103 int s = c - (c - front) * (c - back) / c; 104 return (c - back) * m / c + (back * s) / c; 105 } 106 computeRectUShort(RasterAccessor src, RasterAccessor mask, RasterAccessor dst)107 private void computeRectUShort(RasterAccessor src, 108 RasterAccessor mask, 109 RasterAccessor dst) { 110 int srcLineStride = src.getScanlineStride(); 111 int srcPixelStride = src.getPixelStride(); 112 int[] srcBandOffsets = src.getBandOffsets(); 113 short[] srcData = src.getShortDataArrays()[0]; 114 115 int srcROffset = srcBandOffsets[0]; 116 int srcGOffset = srcBandOffsets[1]; 117 int srcBOffset = srcBandOffsets[2]; 118 119 int maskLineStride = mask.getScanlineStride(); 120 int maskPixelStride = mask.getPixelStride(); 121 int[] maskBandOffsets = mask.getBandOffsets(); 122 short[] maskData = mask.getShortDataArrays()[0]; 123 124 int maskOffset = maskBandOffsets[0]; 125 126 int dstwidth = dst.getWidth(); 127 int dstheight = dst.getHeight(); 128 // int dstBands = dst.getNumBands(); 129 int dstLineStride = dst.getScanlineStride(); 130 int dstPixelStride = dst.getPixelStride(); 131 int[] dstBandOffsets = dst.getBandOffsets(); 132 short[] dstData = dst.getShortDataArrays()[0]; 133 134 int dstROffset = dstBandOffsets[0]; 135 int dstGOffset = dstBandOffsets[1]; 136 int dstBOffset = dstBandOffsets[2]; 137 138 int overlays = (int) Math.floor(detail); 139 int alpha = (int) (c * (detail - Math.floor(detail))); 140 141 for (int row = 0; row < dstheight; row++) { 142 for (int col = 0; col < dstwidth; col++) { 143 int r = (0xffff & srcData[srcPixelStride * col + row * srcLineStride + srcROffset]) / div; 144 int g = (0xffff & srcData[srcPixelStride * col + row * srcLineStride + srcGOffset]) / div; 145 int b = (0xffff & srcData[srcPixelStride * col + row * srcLineStride + srcBOffset]) / div; 146 147 int m = 0xffff & maskData[maskPixelStride * col + row * maskLineStride + maskOffset]; 148 149 m = (0xffff & gammaTable[0xffff - m]) / div; 150 151 for (int i = 0; i < overlays; i++) 152 m = softLightBlendPixels(g, m); 153 154 if (alpha > 0) 155 m = softLightBlendPixels(g, m) * alpha / c + m * (c - alpha) / c; 156 157 int rr = div * softLightBlendPixelsIntensity(m, r, intensityTable); 158 int gg = div * softLightBlendPixelsIntensity(m, g, intensityTable); 159 int bb = div * softLightBlendPixelsIntensity(m, b, intensityTable); 160 161 dstData[dstPixelStride * col + row * dstLineStride + dstROffset] = ImageUtil.clampUShort(rr); 162 dstData[dstPixelStride * col + row * dstLineStride + dstGOffset] = ImageUtil.clampUShort(gg); 163 dstData[dstPixelStride * col + row * dstLineStride + dstBOffset] = ImageUtil.clampUShort(bb); 164 } 165 } 166 } 167 } 168