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 import com.lightcrafts.utils.ColorScience;
11 import com.lightcrafts.utils.HSB;
12 
13 import java.awt.image.DataBuffer;
14 import java.awt.image.RenderedImage;
15 import java.awt.image.Raster;
16 import java.awt.image.WritableRaster;
17 import java.awt.*;
18 import java.awt.color.ICC_ProfileRGB;
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 FilteredGrayscaleOpImage extends PointOpImage {
30     private final float[][] toLinearsRGB;
31     private final float[] filter;
32     private final float angle;
33 
FilteredGrayscaleOpImage(RenderedImage source, float filter[], float angle, float strength, Map config)34     public FilteredGrayscaleOpImage(RenderedImage source, float filter[], float angle, float strength, Map config) {
35         super(source, new ImageLayout(source), config, true);
36         permitInPlaceOperation();
37         ICC_ProfileRGB sRGB = (ICC_ProfileRGB) JAIContext.sRGBColorProfile;
38         ICC_ProfileRGB linRGB = (ICC_ProfileRGB) JAIContext.linearProfile;
39         toLinearsRGB = new Matrix(sRGB.getMatrix()).inverse().times(new Matrix(linRGB.getMatrix())).getArrayFloat();
40 
41         this.filter = filter.clone();
42         this.angle = angle;
43     }
44 
45     @Override
computeRect(Raster[] sources, WritableRaster dest, Rectangle destRect)46     protected void computeRect(Raster[] sources,
47                                WritableRaster dest,
48                                Rectangle destRect) {
49         // Retrieve format tags.
50         RasterFormatTag[] formatTags = getFormatTags();
51 
52         RasterAccessor src = new RasterAccessor(sources[0], destRect, formatTags[0],
53                                                 getSourceImage(0).getColorModel());
54         RasterAccessor dst = new RasterAccessor(dest, destRect, formatTags[1], getColorModel());
55 
56         switch (dst.getDataType()) {
57             case DataBuffer.TYPE_USHORT:
58                 ushortLoop(src, dst);
59                 break;
60             default:
61                 throw new UnsupportedOperationException("Unsupported data type: " + dst.getDataType());
62         }
63 
64         if (dst.needsClamping()) {
65             dst.clampDataArrays();
66         }
67         dst.copyDataToRaster();
68     }
69 
angleDiff(float a, float b)70     private static float angleDiff(float a, float b) {
71         float result = Math.abs(a - b);
72         if (result > Math.PI)
73             result = (float) (2 * Math.PI - result);
74         return result;
75     }
76 
ushortLoop(RasterAccessor src, RasterAccessor dst)77     protected void ushortLoop(RasterAccessor src, RasterAccessor dst) {
78         int width = src.getWidth();
79         int height = src.getHeight();
80 
81         short dstData[] = dst.getShortDataArray(0);
82         int dstBandOffsets[] = dst.getBandOffsets();
83         int dstLineStride = dst.getScanlineStride();
84         int dstPixelStride = dst.getPixelStride();
85 
86         short srcData[] = src.getShortDataArray(0);
87         int srcBandOffsets[] = src.getBandOffsets();
88         int srcLineStride = src.getScanlineStride();
89         int srcPixelStride = src.getPixelStride();
90 
91         int srcROffset = srcBandOffsets[0];
92         int srcGOffset = srcBandOffsets[1];
93         int srcBOffset = srcBandOffsets[2];
94 
95         int dstROffset = dstBandOffsets[0];
96         int dstGOffset = dstBandOffsets[1];
97         int dstBOffset = dstBandOffsets[2];
98 
99         float filterHue, filterSat;
100         {
101             float hsb[] = new float[3];
102             HSB.fromRGB(filter, hsb);
103             filterHue = (float) (2 * Math.PI * hsb[0] - Math.PI);
104             filterSat = hsb[1];
105         }
106 
107         float rgb[] = new float[3];
108         float hsb[] = new float[3];
109 
110         for (int row = 0; row < height; row++) {
111             for (int col = 0; col < width; col++) {
112                 int srcPixOffset = srcPixelStride * col + row * srcLineStride;
113                 int r = 0xffff & srcData[srcPixOffset + srcROffset];
114                 int g = 0xffff & srcData[srcPixOffset + srcGOffset];
115                 int b = 0xffff & srcData[srcPixOffset + srcBOffset];
116 
117                 rgb[0] = toLinearsRGB[0][0] * r + toLinearsRGB[0][1] * g + toLinearsRGB[0][2] * b;
118                 rgb[1] = toLinearsRGB[1][0] * r + toLinearsRGB[1][1] * g + toLinearsRGB[1][2] * b;
119                 rgb[2] = toLinearsRGB[2][0] * r + toLinearsRGB[2][1] * g + toLinearsRGB[2][2] * b;
120 
121                 HSB.fromRGB(rgb, hsb);
122                 float hue = (float) (2 * Math.PI * hsb[0] - Math.PI);
123 
124                 float hueDiff = angleDiff(hue, filterHue);
125                 float mask = (float) Math.cos(Math.PI * hueDiff / angle);
126                 // float mask = (float) Math.abs(1 - hueDiff / angle);
127 
128                 mask = (1-filterSat) + filterSat * mask;
129 
130                 float gray = ColorScience.Wr * r + ColorScience.Wg * g + ColorScience.Wb * b;
131 
132                 int rr = (int) (gray * mask);
133                 int gg = (int) (gray * mask);
134                 int bb = (int) (gray * mask);
135 
136                 int dstPixOffset = dstPixelStride * col + row * dstLineStride;
137                 dstData[dstPixOffset + dstROffset] = (short) (rr < 0 ? 0 : rr > 0xffff ? 0xffff : rr);
138                 dstData[dstPixOffset + dstGOffset] = (short) (gg < 0 ? 0 : gg > 0xffff ? 0xffff : gg);
139                 dstData[dstPixOffset + dstBOffset] = (short) (bb < 0 ? 0 : bb > 0xffff ? 0xffff : bb);
140             }
141         }
142     }
143 }
144