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
26package sun.awt.image;
27import java.awt.image.ColorModel;
28import 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 */
41public 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
54    protected PixelConverter() {}
55
56    @SuppressWarnings("fallthrough")
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
92    public int pixelToRgb(int pixel, ColorModel cm) {
93        // REMIND: Not yet implemented
94        return pixel;
95    }
96
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
128        private Rgbx() {}
129
130        public int rgbToPixel(int rgb, ColorModel cm) {
131            return (rgb << 8);
132        }
133
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
141        private Xrgb() {}
142
143        public int rgbToPixel(int rgb, ColorModel cm) {
144            return rgb;
145        }
146
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
154        private Argb() {
155            alphaMask = 0xff000000;
156        }
157
158        public int rgbToPixel(int rgb, ColorModel cm) {
159            return rgb;
160        }
161
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
169        private Ushort565Rgb() {}
170
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
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
191        private Ushort555Rgbx() {}
192
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
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
213        private Ushort555Rgb() {}
214
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
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
235        private Ushort4444Argb() {
236            alphaMask = 0xf000;
237        }
238
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
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
269        private Xbgr() {}
270
271        public int rgbToPixel(int rgb, ColorModel cm) {
272            return (((rgb & 0xff) << 16) |
273                    (rgb & 0xff00) |
274                    ((rgb >> 16) & 0xff));
275        }
276
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
287        private Bgrx() {}
288
289        public int rgbToPixel(int rgb, ColorModel cm) {
290            return ((rgb << 24) |
291                    ((rgb & 0xff00) << 8) |
292                    ((rgb >> 8) & 0xff00));
293        }
294
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
305        private Rgba() {
306            alphaMask = 0x000000ff;
307        }
308
309        public int rgbToPixel(int rgb, ColorModel cm) {
310            return ((rgb << 8) | (rgb >>> 24));
311        }
312
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
320        private RgbaPre() {
321            alphaMask = 0x000000ff;
322        }
323
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
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
356        private ArgbPre() {
357            alphaMask = 0xff000000;
358        }
359
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
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
392        private ArgbBm() {}
393
394        public int rgbToPixel(int rgb, ColorModel cm) {
395            return (rgb | ((rgb >> 31) << 24));
396        }
397
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
408        private ByteGray() {}
409
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
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
431        private UshortGray() {}
432
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
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