1 /*
2  * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package sun.awt.image;
27 import java.awt.image.ColorModel;
28 import java.awt.image.DataBuffer;
29 
30 /**
31  * This class provides utilities for converting between the standard
32  * rgb colorspace specification and the equivalent value for a pixel
33  * of a given surface type.  The class was designed for use by the
34  * SurfaceType objects, since the conversion between pixel values
35  * and rgb values is inherently tied to the type of surface we are
36  * dealing with.  Some conversions cannot be done automatically,
37  * however (for example, the AnyInt or AnyDCM surface types), so
38  * we require the caller to pass in a ColorModel object so that
39  * we can calculate the pixel values in these generic cases as well.
40  */
41 public class PixelConverter {
42 
43     /**
44      * Default object, used as a fallback for any surface types where
45      * we do not know enough about the surface to calculate the
46      * conversions directly.  We use the ColorModel object to assist
47      * us in these cases.
48      */
49     public static final PixelConverter instance = new PixelConverter();
50 
51 
52     protected int alphaMask = 0;
53 
PixelConverter()54     protected PixelConverter() {}
55 
56     @SuppressWarnings("fallthrough")
rgbToPixel(int rgb, ColorModel cm)57     public int rgbToPixel(int rgb, ColorModel cm) {
58         Object obj = cm.getDataElements(rgb, null);
59         switch (cm.getTransferType()) {
60         case DataBuffer.TYPE_BYTE:
61             byte[] bytearr = (byte[]) obj;
62             int pix = 0;
63 
64             switch(bytearr.length) {
65             default: // bytearr.length >= 4
66                 pix = bytearr[3] << 24;
67                 // FALLSTHROUGH
68             case 3:
69                 pix |= (bytearr[2] & 0xff) << 16;
70                 // FALLSTHROUGH
71             case 2:
72                 pix |= (bytearr[1] & 0xff) << 8;
73                 // FALLSTHROUGH
74             case 1:
75                 pix |= (bytearr[0] & 0xff);
76             }
77 
78             return pix;
79         case DataBuffer.TYPE_SHORT:
80         case DataBuffer.TYPE_USHORT:
81             short[] shortarr = (short[]) obj;
82 
83             return (((shortarr.length > 1) ? shortarr[1] << 16 : 0) |
84                     shortarr[0] & 0xffff);
85         case DataBuffer.TYPE_INT:
86             return ((int[]) obj)[0];
87         default:
88             return rgb;
89         }
90     }
91 
pixelToRgb(int pixel, ColorModel cm)92     public int pixelToRgb(int pixel, ColorModel cm) {
93         // REMIND: Not yet implemented
94         return pixel;
95     }
96 
getAlphaMask()97     public final int getAlphaMask() {
98         return alphaMask;
99     }
100 
101 
102     /**
103      * Subclasses of PixelConverter.  These subclasses are
104      * specific to surface types where we can definitively
105      * calculate the conversions.  Note that some conversions
106      * are lossy; that is, we cannot necessarily convert a
107      * value and then convert it back and wind up with the
108      * original value.  For example, an rgb value  that has
109      * an alpha != 1 cannot be converted to an Xrgb pixel
110      * without losing the information in the alpha component.
111      *
112      * The conversion strategies associated with the ThreeByte*
113      * and FourByte* surface types swap the components around
114      * due to the ordering used when the bytes are stored.  The
115      * low order byte of a packed-byte pixel will be the first
116      * byte stored and the high order byte will be the last byte
117      * stored.  For example, the ThreeByteBgr surface type is
118      * associated with an Xrgb conversion object because the
119      * three bytes are stored as follows:
120      *   pixels[0] = b;    // low order byte of an Xrgb pixel
121      *   pixels[1] = g;
122      *   pixels[2] = r;    // high order byte of an Xrgb pixel
123      */
124 
125     public static class Rgbx extends PixelConverter {
126         public static final PixelConverter instance = new Rgbx();
127 
Rgbx()128         private Rgbx() {}
129 
rgbToPixel(int rgb, ColorModel cm)130         public int rgbToPixel(int rgb, ColorModel cm) {
131             return (rgb << 8);
132         }
133 
pixelToRgb(int pixel, ColorModel cm)134         public int pixelToRgb(int pixel, ColorModel cm) {
135             return (0xff000000 | (pixel >> 8));
136         }
137     }
138     public static class Xrgb extends PixelConverter {
139         public static final PixelConverter instance = new Xrgb();
140 
Xrgb()141         private Xrgb() {}
142 
rgbToPixel(int rgb, ColorModel cm)143         public int rgbToPixel(int rgb, ColorModel cm) {
144             return rgb;
145         }
146 
pixelToRgb(int pixel, ColorModel cm)147         public int pixelToRgb(int pixel, ColorModel cm) {
148             return (0xff000000 | pixel);
149         }
150     }
151     public static class Argb extends PixelConverter {
152         public static final PixelConverter instance = new Argb();
153 
Argb()154         private Argb() {
155             alphaMask = 0xff000000;
156         }
157 
rgbToPixel(int rgb, ColorModel cm)158         public int rgbToPixel(int rgb, ColorModel cm) {
159             return rgb;
160         }
161 
pixelToRgb(int pixel, ColorModel cm)162         public int pixelToRgb(int pixel, ColorModel cm) {
163             return pixel;
164         }
165     }
166     public static class Ushort565Rgb extends PixelConverter {
167         public static final PixelConverter instance = new Ushort565Rgb();
168 
Ushort565Rgb()169         private Ushort565Rgb() {}
170 
rgbToPixel(int rgb, ColorModel cm)171         public int rgbToPixel(int rgb, ColorModel cm) {
172             return (((rgb >> (16 + 3 - 11)) & 0xf800) |
173                     ((rgb >> ( 8 + 2 -  5)) & 0x07e0) |
174                     ((rgb >> ( 0 + 3 -  0)) & 0x001f));
175         }
176 
pixelToRgb(int pixel, ColorModel cm)177         public int pixelToRgb(int pixel, ColorModel cm) {
178             int r, g, b;
179             r = (pixel >> 11) & 0x1f;
180             r = (r << 3) | (r >> 2);
181             g = (pixel >>  5) & 0x3f;
182             g = (g << 2) | (g >> 4);
183             b = (pixel      ) & 0x1f;
184             b = (b << 3) | (b >> 2);
185             return (0xff000000 | (r << 16) | (g << 8) | (b));
186         }
187     }
188     public static class Ushort555Rgbx extends PixelConverter {
189         public static final PixelConverter instance = new Ushort555Rgbx();
190 
Ushort555Rgbx()191         private Ushort555Rgbx() {}
192 
rgbToPixel(int rgb, ColorModel cm)193         public int rgbToPixel(int rgb, ColorModel cm) {
194             return (((rgb >> (16 + 3 - 11)) & 0xf800) |
195                     ((rgb >> ( 8 + 3 -  6)) & 0x07c0) |
196                     ((rgb >> ( 0 + 3 -  1)) & 0x003e));
197         }
198 
pixelToRgb(int pixel, ColorModel cm)199         public int pixelToRgb(int pixel, ColorModel cm) {
200             int r, g, b;
201             r = (pixel >> 11) & 0x1f;
202             r = (r << 3) | (r >> 2);
203             g = (pixel >>  6) & 0x1f;
204             g = (g << 3) | (g >> 2);
205             b = (pixel >>  1) & 0x1f;
206             b = (b << 3) | (b >> 2);
207             return (0xff000000 | (r << 16) | (g << 8) | (b));
208         }
209     }
210     public static class Ushort555Rgb extends PixelConverter {
211         public static final PixelConverter instance = new Ushort555Rgb();
212 
Ushort555Rgb()213         private Ushort555Rgb() {}
214 
rgbToPixel(int rgb, ColorModel cm)215         public int rgbToPixel(int rgb, ColorModel cm) {
216             return (((rgb >> (16 + 3 - 10)) & 0x7c00) |
217                     ((rgb >> ( 8 + 3 -  5)) & 0x03e0) |
218                     ((rgb >> ( 0 + 3 -  0)) & 0x001f));
219         }
220 
pixelToRgb(int pixel, ColorModel cm)221         public int pixelToRgb(int pixel, ColorModel cm) {
222             int r, g, b;
223             r = (pixel >> 10) & 0x1f;
224             r = (r << 3) | (r >> 2);
225             g = (pixel >>  5) & 0x1f;
226             g = (g << 3) | (g >> 2);
227             b = (pixel      ) & 0x1f;
228             b = (b << 3) | (b >> 2);
229             return (0xff000000 | (r << 16) | (g << 8) | (b));
230         }
231     }
232     public static class Ushort4444Argb extends PixelConverter {
233         public static final PixelConverter instance = new Ushort4444Argb();
234 
Ushort4444Argb()235         private Ushort4444Argb() {
236             alphaMask = 0xf000;
237         }
238 
rgbToPixel(int rgb, ColorModel cm)239         public int rgbToPixel(int rgb, ColorModel cm) {
240             // use upper 4 bits for each color
241             // 0xAaRrGgBb -> 0x0000ARGB
242             int a = (rgb >> 16) & 0xf000;
243             int r = (rgb >> 12) & 0x0f00;
244             int g = (rgb >>  8) & 0x00f0;
245             int b = (rgb >>  4) & 0x000f;
246 
247             return (a | r | g | b);
248         }
249 
pixelToRgb(int pixel, ColorModel cm)250         public int pixelToRgb(int pixel, ColorModel cm) {
251             int a, r, g, b;
252             // replicate 4 bits for each color
253             // 0xARGB -> 0xAARRGGBB
254             a = pixel & 0xf000;
255             a = ((pixel << 16) | (pixel << 12)) & 0xff000000;
256             r = pixel & 0x0f00;
257             r = ((pixel << 12) | (pixel <<  8)) & 0x00ff0000;
258             g = pixel & 0x00f0;
259             g = ((pixel <<  8) | (pixel <<  4)) & 0x0000ff00;
260             b = pixel & 0x000f;
261             b = ((pixel <<  4) | (pixel <<  0)) & 0x000000ff;
262 
263             return (a | r | g | b);
264         }
265     }
266     public static class Xbgr extends PixelConverter {
267         public static final PixelConverter instance = new Xbgr();
268 
Xbgr()269         private Xbgr() {}
270 
rgbToPixel(int rgb, ColorModel cm)271         public int rgbToPixel(int rgb, ColorModel cm) {
272             return (((rgb & 0xff) << 16) |
273                     (rgb & 0xff00) |
274                     ((rgb >> 16) & 0xff));
275         }
276 
pixelToRgb(int pixel, ColorModel cm)277         public int pixelToRgb(int pixel, ColorModel cm) {
278             return (0xff000000 |
279                     ((pixel & 0xff) << 16) |
280                     (pixel & 0xff00) |
281                     ((pixel >> 16) & 0xff));
282         }
283     }
284     public static class Bgrx extends PixelConverter {
285         public static final PixelConverter instance = new Bgrx();
286 
Bgrx()287         private Bgrx() {}
288 
rgbToPixel(int rgb, ColorModel cm)289         public int rgbToPixel(int rgb, ColorModel cm) {
290             return ((rgb << 24) |
291                     ((rgb & 0xff00) << 8) |
292                     ((rgb >> 8) & 0xff00));
293         }
294 
pixelToRgb(int pixel, ColorModel cm)295         public int pixelToRgb(int pixel, ColorModel cm) {
296             return (0xff000000                   |
297                     ((pixel & 0xff00) << 8) |
298                     ((pixel >> 8) & 0xff00) |
299                     (pixel >>> 24));
300         }
301     }
302     public static class Rgba extends PixelConverter {
303         public static final PixelConverter instance = new Rgba();
304 
Rgba()305         private Rgba() {
306             alphaMask = 0x000000ff;
307         }
308 
rgbToPixel(int rgb, ColorModel cm)309         public int rgbToPixel(int rgb, ColorModel cm) {
310             return ((rgb << 8) | (rgb >>> 24));
311         }
312 
pixelToRgb(int pixel, ColorModel cm)313         public int pixelToRgb(int pixel, ColorModel cm) {
314             return ((pixel << 24) | (pixel >>> 8));
315         }
316     }
317     public static class RgbaPre extends PixelConverter {
318         public static final PixelConverter instance = new RgbaPre();
319 
RgbaPre()320         private RgbaPre() {
321             alphaMask = 0x000000ff;
322         }
323 
rgbToPixel(int rgb, ColorModel cm)324         public int rgbToPixel(int rgb, ColorModel cm) {
325             if ((rgb >> 24) == -1) {
326                 return ((rgb << 8) | (rgb >>> 24));
327             }
328             int a = rgb >>> 24;
329             int r = (rgb >> 16) & 0xff;
330             int g = (rgb >>  8) & 0xff;
331             int b = (rgb      ) & 0xff;
332             int a2 = a + (a >> 7);
333             r = (r * a2) >> 8;
334             g = (g * a2) >> 8;
335             b = (b * a2) >> 8;
336             return ((r << 24) | (g << 16) | (b << 8) | (a));
337         }
338 
pixelToRgb(int pixel, ColorModel cm)339         public int pixelToRgb(int pixel, ColorModel cm) {
340             int a = pixel & 0xff;
341             if ((a == 0xff) || (a == 0)) {
342                 return ((pixel >>> 8) | (pixel << 24));
343             }
344             int r = pixel >>> 24;
345             int g = (pixel >> 16) & 0xff;
346             int b = (pixel >>  8) & 0xff;
347             r = ((r << 8) - r) / a;
348             g = ((g << 8) - g) / a;
349             b = ((b << 8) - b) / a;
350             return ((r << 24) | (g << 16) | (b << 8) | (a));
351         }
352     }
353     public static class ArgbPre extends PixelConverter {
354         public static final PixelConverter instance = new ArgbPre();
355 
ArgbPre()356         private ArgbPre() {
357             alphaMask = 0xff000000;
358         }
359 
rgbToPixel(int rgb, ColorModel cm)360         public int rgbToPixel(int rgb, ColorModel cm) {
361             if ((rgb >> 24) == -1) {
362                 return rgb;
363             }
364             int a = rgb >>> 24;
365             int r = (rgb >> 16) & 0xff;
366             int g = (rgb >>  8) & 0xff;
367             int b = (rgb      ) & 0xff;
368             int a2 = a + (a >> 7);
369             r = (r * a2) >> 8;
370             g = (g * a2) >> 8;
371             b = (b * a2) >> 8;
372             return ((a << 24) | (r << 16) | (g << 8) | (b));
373         }
374 
pixelToRgb(int pixel, ColorModel cm)375         public int pixelToRgb(int pixel, ColorModel cm) {
376             int a = pixel >>> 24;
377             if ((a == 0xff) || (a == 0)) {
378                 return pixel;
379             }
380             int r = (pixel >> 16) & 0xff;
381             int g = (pixel >>  8) & 0xff;
382             int b = (pixel      ) & 0xff;
383             r = ((r << 8) - r) / a;
384             g = ((g << 8) - g) / a;
385             b = ((b << 8) - b) / a;
386             return ((a << 24) | (r << 16) | (g << 8) | (b));
387         }
388     }
389     public static class ArgbBm extends PixelConverter {
390         public static final PixelConverter instance = new ArgbBm();
391 
ArgbBm()392         private ArgbBm() {}
393 
rgbToPixel(int rgb, ColorModel cm)394         public int rgbToPixel(int rgb, ColorModel cm) {
395             return (rgb | ((rgb >> 31) << 24));
396         }
397 
pixelToRgb(int pixel, ColorModel cm)398         public int pixelToRgb(int pixel, ColorModel cm) {
399             return ((pixel << 7) >> 7);
400         }
401     }
402     public static class ByteGray extends PixelConverter {
403         static final double RED_MULT = 0.299;
404         static final double GRN_MULT = 0.587;
405         static final double BLU_MULT = 0.114;
406         public static final PixelConverter instance = new ByteGray();
407 
ByteGray()408         private ByteGray() {}
409 
rgbToPixel(int rgb, ColorModel cm)410         public int rgbToPixel(int rgb, ColorModel cm) {
411             int red = (rgb >> 16) & 0xff;
412             int grn = (rgb >>  8) & 0xff;
413             int blu = (rgb      ) & 0xff;
414             return (int) (red * RED_MULT +
415                           grn * GRN_MULT +
416                           blu * BLU_MULT +
417                           0.5);
418         }
419 
pixelToRgb(int pixel, ColorModel cm)420         public int pixelToRgb(int pixel, ColorModel cm) {
421             return ((((((0xff << 8) | pixel) << 8) | pixel) << 8) | pixel);
422         }
423     }
424     public static class UshortGray extends ByteGray {
425         static final double SHORT_MULT = 257.0; // (65535.0 / 255.0);
426         static final double USHORT_RED_MULT = RED_MULT * SHORT_MULT;
427         static final double USHORT_GRN_MULT = GRN_MULT * SHORT_MULT;
428         static final double USHORT_BLU_MULT = BLU_MULT * SHORT_MULT;
429         public static final PixelConverter instance = new UshortGray();
430 
UshortGray()431         private UshortGray() {}
432 
rgbToPixel(int rgb, ColorModel cm)433         public int rgbToPixel(int rgb, ColorModel cm) {
434             int red = (rgb >> 16) & 0xff;
435             int grn = (rgb >>  8) & 0xff;
436             int blu = (rgb      ) & 0xff;
437             return (int) (red * USHORT_RED_MULT +
438                           grn * USHORT_GRN_MULT +
439                           blu * USHORT_BLU_MULT +
440                           0.5);
441         }
442 
pixelToRgb(int pixel, ColorModel cm)443         public int pixelToRgb(int pixel, ColorModel cm) {
444             pixel = pixel >> 8;
445             return ((((((0xff << 8) | pixel) << 8) | pixel) << 8) | pixel);
446         }
447     }
448 }
449