1 /* Copyright (C) 2005-2011 Fabio Riccardi */
2 
3 package com.lightcrafts.jai.opimage;
4 
5 
6 import com.lightcrafts.mediax.jai.PointOpImage;
7 import com.lightcrafts.mediax.jai.ImageLayout;
8 import com.lightcrafts.mediax.jai.RasterAccessor;
9 import com.lightcrafts.mediax.jai.RasterFormatTag;
10 import com.lightcrafts.jai.JAIContext;
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 HueRotateOpImage extends PointOpImage {
30     private float angle;
31     private float toSRGB[][];
32     private float toLinearRGB[][];
33 
HueRotateOpImage(RenderedImage source, float angle, Map config)34     public HueRotateOpImage(RenderedImage source, float angle, Map config) {
35         super(source, new ImageLayout(source), config, true);
36         permitInPlaceOperation();
37         this.angle = angle;
38 
39         ICC_ProfileRGB sRGB = (ICC_ProfileRGB) JAIContext.sRGBColorProfile;
40         toSRGB = new Matrix(sRGB.getMatrix()).inverse().times(new Matrix(((ICC_ProfileRGB) JAIContext.linearProfile).getMatrix())).getArrayFloat();
41         toLinearRGB = new Matrix(sRGB.getMatrix()).inverse().times(new Matrix(((ICC_ProfileRGB) JAIContext.linearProfile).getMatrix())).inverse().getArrayFloat();
42     }
43 
44     @Override
computeRect(Raster[] sources, WritableRaster dest, Rectangle destRect)45     protected void computeRect(Raster[] sources,
46                                WritableRaster dest,
47                                Rectangle destRect) {
48         // Retrieve format tags.
49         RasterFormatTag[] formatTags = getFormatTags();
50 
51         RasterAccessor src = new RasterAccessor(sources[0], destRect, formatTags[0],
52                 getSourceImage(0).getColorModel());
53         RasterAccessor dst = new RasterAccessor(dest, destRect, formatTags[1], getColorModel());
54 
55         switch (dst.getDataType()) {
56             case DataBuffer.TYPE_USHORT:
57                 ushortLoop(src, dst);
58                 break;
59             default:
60                 throw new UnsupportedOperationException("Unsupported data type: " + dst.getDataType());
61         }
62     }
63 
ushortLoop(RasterAccessor src, RasterAccessor dst)64     protected void ushortLoop(RasterAccessor src, RasterAccessor dst) {
65         int width = src.getWidth();
66         int height = src.getHeight();
67 
68         short dstData[] = dst.getShortDataArray(0);
69         int dstBandOffsets[] = dst.getBandOffsets();
70         int dstLineStride = dst.getScanlineStride();
71         int dstPixelStride = dst.getPixelStride();
72 
73         short srcData[] = src.getShortDataArray(0);
74         int srcBandOffsets[] = src.getBandOffsets();
75         int srcLineStride = src.getScanlineStride();
76         int srcPixelStride = src.getPixelStride();
77 
78         int srcROffset = srcBandOffsets[0];
79         int srcGOffset = srcBandOffsets[1];
80         int srcBOffset = srcBandOffsets[2];
81 
82         int dstROffset = dstBandOffsets[0];
83         int dstGOffset = dstBandOffsets[1];
84         int dstBOffset = dstBandOffsets[2];
85 
86         float rgb[] = new float[3];
87         float hsi[] = new float[3];
88 
89         for (int row = 0; row < height; row++) {
90             for (int col = 0; col < width; col++) {
91                 int srcPixOffset = srcPixelStride * col + row * srcLineStride;
92                 int r = (0xffff & srcData[srcPixOffset + srcROffset]);
93                 int g = (0xffff & srcData[srcPixOffset + srcGOffset]);
94                 int b = (0xffff & srcData[srcPixOffset + srcBOffset]);
95 
96                 rgb[0] = (toSRGB[0][0] * r + toSRGB[0][1] * g + toSRGB[0][2] * b) / (float) 0xffff;
97                 rgb[1] = (toSRGB[1][0] * r + toSRGB[1][1] * g + toSRGB[1][2] * b) / (float) 0xffff;
98                 rgb[2] = (toSRGB[2][0] * r + toSRGB[2][1] * g + toSRGB[2][2] * b) / (float) 0xffff;
99 
100                 HSB.fromRGB(rgb, hsi);
101 
102                 hsi[0] += angle;
103 
104                 if (hsi[0] < 0)
105                     hsi[0] += 1;
106                 else if (hsi[0] >= 1)
107                     hsi[0] -= 1;
108 
109                 HSB.toRGB(hsi, rgb);
110 
111                 r = (int) (0xffff *(toLinearRGB[0][0] * rgb[0] + toLinearRGB[0][1] * rgb[1] + toLinearRGB[0][2] * rgb[2]));
112                 g = (int) (0xffff *(toLinearRGB[1][0] * rgb[0] + toLinearRGB[1][1] * rgb[1] + toLinearRGB[1][2] * rgb[2]));
113                 b = (int) (0xffff *(toLinearRGB[2][0] * rgb[0] + toLinearRGB[2][1] * rgb[1] + toLinearRGB[2][2] * rgb[2]));
114 
115                 int dstPixOffset = dstPixelStride * col + row * dstLineStride;
116                 dstData[dstPixOffset + dstROffset] = (short) (r < 0 ? 0 : r > 0xffff ? 0xffff : r);
117                 dstData[dstPixOffset + dstGOffset] = (short) (g < 0 ? 0 : g > 0xffff ? 0xffff : g);
118                 dstData[dstPixOffset + dstBOffset] = (short) (b < 0 ? 0 : b > 0xffff ? 0xffff : b);
119             }
120         }
121     }
122 }
123