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.RasterAccessor; 8 import com.lightcrafts.mediax.jai.RasterFormatTag; 9 import com.lightcrafts.jai.JAIContext; 10 11 import java.awt.image.DataBuffer; 12 import java.awt.image.RenderedImage; 13 import java.awt.image.Raster; 14 import java.awt.image.WritableRaster; 15 import java.awt.*; 16 import java.awt.color.ICC_ProfileRGB; 17 import java.awt.color.ICC_Profile; 18 import java.awt.color.ColorSpace; 19 import java.util.Map; 20 21 import Jama.Matrix; 22 23 /** 24 * Copyright (C) Light Crafts, Inc. 25 * User: fabio 26 * Date: Mar 20, 2007 27 * Time: 4:32:46 PM 28 */ 29 public class IntVibranceOpImage extends PointOpImage { 30 private final int transform[][] = new int[3][3]; 31 private final int toLinearsRGB[][] = new int[3][3]; 32 private final boolean saturationIncrease; 33 34 private static final int sMath_scale = 0x8000; 35 private static final int sMath_PI = (int) (sMath_scale * Math.PI); 36 37 /* 38 * fast integer arctan2 implementation. 39 * see: http://www.dspguru.com/comp.dsp/tricks/alg/fxdatan2.htm 40 */ 41 arctan2(int y, int x)42 static int arctan2(int y, int x) { 43 final int coeff_1 = sMath_PI / 4; 44 final int coeff_2 = 3 * coeff_1; 45 final int abs_y = Math.abs(y) + 1; // kludge to prevent 0/0 condition 46 final int angle; 47 48 if (x >= 0) { 49 int r = (sMath_scale * (x - abs_y)) / (x + abs_y); 50 angle = coeff_1 - coeff_1 * r / sMath_scale; 51 } else { 52 int r = (sMath_scale * (x + abs_y)) / (abs_y - x); 53 angle = coeff_2 - coeff_1 * r / sMath_scale; 54 } 55 56 return y < 0 ? -angle : angle; 57 } 58 IntVibranceOpImage(RenderedImage source, float transform[][], Map config)59 public IntVibranceOpImage(RenderedImage source, float transform[][], Map config) { 60 super(source, new ImageLayout(source), config, true); 61 permitInPlaceOperation(); 62 63 for (int i = 0; i < 3; i++) 64 for (int j = 0; j < 3; j++) 65 this.transform[i][j] = (int) (sMath_scale * transform[i][j]); 66 67 saturationIncrease = transform[0][0] > 1; 68 69 ICC_ProfileRGB linRGB = (ICC_ProfileRGB) ICC_Profile.getInstance(ColorSpace.CS_LINEAR_RGB); 70 Matrix XYZtoLinsRGB = new Matrix(linRGB.getMatrix()).inverse(); 71 Matrix CIERGBtoXYZ = new Matrix(((ICC_ProfileRGB) JAIContext.linearProfile).getMatrix()); 72 double CIERGBtoLinsRGB[][] = XYZtoLinsRGB.times(CIERGBtoXYZ).getArray(); 73 74 for (int i = 0; i < 3; i++) 75 for (int j = 0; j < 3; j++) 76 toLinearsRGB[i][j] = (int) (sMath_scale * CIERGBtoLinsRGB[i][j]); 77 78 } 79 computeRect(Raster[] sources, WritableRaster dest, Rectangle destRect)80 protected void computeRect(Raster[] sources, 81 WritableRaster dest, 82 Rectangle destRect) { 83 // Retrieve format tags. 84 RasterFormatTag[] formatTags = getFormatTags(); 85 86 RasterAccessor src = new RasterAccessor(sources[0], destRect, formatTags[0], 87 getSourceImage(0).getColorModel()); 88 RasterAccessor dst = new RasterAccessor(dest, destRect, formatTags[1], getColorModel()); 89 90 switch (dst.getDataType()) { 91 case DataBuffer.TYPE_USHORT: 92 ushortLoop(src, dst); 93 break; 94 default: 95 throw new UnsupportedOperationException("Unsupported data type: " + dst.getDataType()); 96 } 97 } 98 ushortLoop(RasterAccessor src, RasterAccessor dst)99 protected void ushortLoop(RasterAccessor src, RasterAccessor dst) { 100 int width = src.getWidth(); 101 int height = src.getHeight(); 102 103 short dstData[] = dst.getShortDataArray(0); 104 int dstBandOffsets[] = dst.getBandOffsets(); 105 int dstLineStride = dst.getScanlineStride(); 106 int dstPixelStride = dst.getPixelStride(); 107 108 short srcData[] = src.getShortDataArray(0); 109 int srcBandOffsets[] = src.getBandOffsets(); 110 int srcLineStride = src.getScanlineStride(); 111 int srcPixelStride = src.getPixelStride(); 112 113 int srcROffset = srcBandOffsets[0]; 114 int srcGOffset = srcBandOffsets[1]; 115 int srcBOffset = srcBandOffsets[2]; 116 117 int dstROffset = dstBandOffsets[0]; 118 int dstGOffset = dstBandOffsets[1]; 119 int dstBOffset = dstBandOffsets[2]; 120 121 final int sqrt3d2 = (int) (sMath_scale * Math.sqrt(3) / 2); // 0.866... 122 123 for (int row = 0; row < height; row++) { 124 for (int col = 0; col < width; col++) { 125 int srcPixOffset = srcPixelStride * col + row * srcLineStride; 126 int r = (0xffff & srcData[srcPixOffset + srcROffset]) / 2; 127 int g = (0xffff & srcData[srcPixOffset + srcGOffset]) / 2; 128 int b = (0xffff & srcData[srcPixOffset + srcBOffset]) / 2; 129 130 int lr = (toLinearsRGB[0][0] * r + toLinearsRGB[0][1] * g + toLinearsRGB[0][2] * b) / sMath_scale; 131 int lg = (toLinearsRGB[1][0] * r + toLinearsRGB[1][1] * g + toLinearsRGB[1][2] * b) / sMath_scale; 132 int lb = (toLinearsRGB[2][0] * r + toLinearsRGB[2][1] * g + toLinearsRGB[2][2] * b) / sMath_scale; 133 134 int x = lr - (lg+lb) / 2; 135 int y = (sqrt3d2 * (lg-lb)) / sMath_scale; 136 137 int hue = arctan2(x, y) + sMath_PI; 138 139 if (hue < 0) 140 hue += 2 * sMath_PI; 141 142 if (hue > 4 * sMath_PI / 3) 143 hue -= 4 * sMath_PI / 3; 144 else if (hue > 2 * sMath_PI / 3) 145 hue -= 2 * sMath_PI / 3; 146 147 int mask = sMath_scale / 2 + (sMath_scale - (sMath_scale * Math.abs(sMath_PI / 6 - hue)) / (sMath_PI / 3)) / 2; 148 149 if (saturationIncrease) { 150 int min = Math.min(r, Math.min(g, b)); 151 int max = Math.max(r, Math.max(g, b)); 152 153 int saturation = max != 0 ? sMath_scale - sMath_scale * min / max : 0; 154 mask = mask * (sMath_scale - saturation * saturation / sMath_scale) / sMath_scale; 155 } 156 157 int rr = (transform[0][0] * r + transform[0][1] * g + transform[0][2] * b) / sMath_scale; 158 int gg = (transform[1][0] * r + transform[1][1] * g + transform[1][2] * b) / sMath_scale; 159 int bb = (transform[2][0] * r + transform[2][1] * g + transform[2][2] * b) / sMath_scale; 160 161 rr = 2 * ((sMath_scale - mask) * r / sMath_scale + rr * mask / sMath_scale); 162 gg = 2 * ((sMath_scale - mask) * g / sMath_scale + gg * mask / sMath_scale); 163 bb = 2 * ((sMath_scale - mask) * b / sMath_scale + bb * mask / sMath_scale); 164 165 int dstPixOffset = dstPixelStride * col + row * dstLineStride; 166 dstData[dstPixOffset + dstROffset] = (short) (rr < 0 ? 0 : rr > 0xffff ? 0xffff : rr); 167 dstData[dstPixOffset + dstGOffset] = (short) (gg < 0 ? 0 : gg > 0xffff ? 0xffff : gg); 168 dstData[dstPixOffset + dstBOffset] = (short) (bb < 0 ? 0 : bb > 0xffff ? 0xffff : bb); 169 } 170 } 171 } 172 } 173