1 /*
   2  * Copyright (c) 2000, 2002, 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 
  54     protected PixelConverter() {}
  55 
  56     public int rgbToPixel(int rgb, ColorModel cm) {
  57         Object obj = cm.getDataElements(rgb, null);
  58         switch (cm.getTransferType()) {
  59         case DataBuffer.TYPE_BYTE:
  60             byte[] bytearr = (byte[]) obj;
  61             int pix = 0;
  62 
  63             switch(bytearr.length) {
  64             default: // bytearr.length >= 4
  65                 pix = bytearr[3] << 24;
  66                 // FALLSTHROUGH
  67             case 3:
  68                 pix |= (bytearr[2] & 0xff) << 16;
  69                 // FALLSTHROUGH
  70             case 2:
  71                 pix |= (bytearr[1] & 0xff) << 8;
  72                 // FALLSTHROUGH
  73             case 1:
  74                 pix |= (bytearr[0] & 0xff);
  75             }
  76 
  77             return pix;
  78         case DataBuffer.TYPE_SHORT:
  79         case DataBuffer.TYPE_USHORT:
  80             short[] shortarr = (short[]) obj;
  81 
  82             return (((shortarr.length > 1) ? shortarr[1] << 16 : 0) |
  83                     shortarr[0] & 0xffff);
  84         case DataBuffer.TYPE_INT:
  85             return ((int[]) obj)[0];
  86         default:
  87             return rgb;
  88         }
  89     }
  90 
  91     public int pixelToRgb(int pixel, ColorModel cm) {
  92         // REMIND: Not yet implemented
  93         return pixel;
  94     }
  95 
  96     public final int getAlphaMask() {
  97         return alphaMask;
  98     }
  99 
 100 
 101     /**
 102      * Subclasses of PixelConverter.  These subclasses are
 103      * specific to surface types where we can definitively
 104      * calculate the conversions.  Note that some conversions
 105      * are lossy; that is, we cannot necessarily convert a
 106      * value and then convert it back and wind up with the
 107      * original value.  For example, an rgb value  that has
 108      * an alpha != 1 cannot be converted to an Xrgb pixel
 109      * without losing the information in the alpha component.
 110      *
 111      * The conversion strategies associated with the ThreeByte*
 112      * and FourByte* surface types swap the components around
 113      * due to the ordering used when the bytes are stored.  The
 114      * low order byte of a packed-byte pixel will be the first
 115      * byte stored and the high order byte will be the last byte
 116      * stored.  For example, the ThreeByteBgr surface type is
 117      * associated with an Xrgb conversion object because the
 118      * three bytes are stored as follows:
 119      *   pixels[0] = b;    // low order byte of an Xrgb pixel
 120      *   pixels[1] = g;
 121      *   pixels[2] = r;    // high order byte of an Xrgb pixel
 122      */
 123 
 124     public static class Rgbx extends PixelConverter {
 125         public static final PixelConverter instance = new Rgbx();
 126 
 127         private Rgbx() {}
 128 
 129         public int rgbToPixel(int rgb, ColorModel cm) {
 130             return (rgb << 8);
 131         }
 132 
 133         public int pixelToRgb(int pixel, ColorModel cm) {
 134             return (0xff000000 | (pixel >> 8));
 135         }
 136     }
 137     public static class Xrgb extends PixelConverter {
 138         public static final PixelConverter instance = new Xrgb();
 139 
 140         private Xrgb() {}
 141 
 142         public int rgbToPixel(int rgb, ColorModel cm) {
 143             return rgb;
 144         }
 145 
 146         public int pixelToRgb(int pixel, ColorModel cm) {
 147             return (0xff000000 | pixel);
 148         }
 149     }
 150     public static class Argb extends PixelConverter {
 151         public static final PixelConverter instance = new Argb();
 152 
 153         private Argb() {
 154             alphaMask = 0xff000000;
 155         }
 156 
 157         public int rgbToPixel(int rgb, ColorModel cm) {
 158             return rgb;
 159         }
 160 
 161         public int pixelToRgb(int pixel, ColorModel cm) {
 162             return pixel;
 163         }
 164     }
 165     public static class Ushort565Rgb extends PixelConverter {
 166         public static final PixelConverter instance = new Ushort565Rgb();
 167 
 168         private Ushort565Rgb() {}
 169 
 170         public int rgbToPixel(int rgb, ColorModel cm) {
 171             return (((rgb >> (16 + 3 - 11)) & 0xf800) |
 172                     ((rgb >> ( 8 + 2 -  5)) & 0x07e0) |
 173                     ((rgb >> ( 0 + 3 -  0)) & 0x001f));
 174         }
 175 
 176         public int pixelToRgb(int pixel, ColorModel cm) {
 177             int r, g, b;
 178             r = (pixel >> 11) & 0x1f;
 179             r = (r << 3) | (r >> 2);
 180             g = (pixel >>  5) & 0x3f;
 181             g = (g << 2) | (g >> 4);
 182             b = (pixel      ) & 0x1f;
 183             b = (b << 3) | (b >> 2);
 184             return (0xff000000 | (r << 16) | (g << 8) | (b));
 185         }
 186     }
 187     public static class Ushort555Rgbx extends PixelConverter {
 188         public static final PixelConverter instance = new Ushort555Rgbx();
 189 
 190         private Ushort555Rgbx() {}
 191 
 192         public int rgbToPixel(int rgb, ColorModel cm) {
 193             return (((rgb >> (16 + 3 - 11)) & 0xf800) |
 194                     ((rgb >> ( 8 + 3 -  6)) & 0x07c0) |
 195                     ((rgb >> ( 0 + 3 -  1)) & 0x003e));
 196         }
 197 
 198         public int pixelToRgb(int pixel, ColorModel cm) {
 199             int r, g, b;
 200             r = (pixel >> 11) & 0x1f;
 201             r = (r << 3) | (r >> 2);
 202             g = (pixel >>  6) & 0x1f;
 203             g = (g << 3) | (g >> 2);
 204             b = (pixel >>  1) & 0x1f;
 205             b = (b << 3) | (b >> 2);
 206             return (0xff000000 | (r << 16) | (g << 8) | (b));
 207         }
 208     }
 209     public static class Ushort555Rgb extends PixelConverter {
 210         public static final PixelConverter instance = new Ushort555Rgb();
 211 
 212         private Ushort555Rgb() {}
 213 
 214         public int rgbToPixel(int rgb, ColorModel cm) {
 215             return (((rgb >> (16 + 3 - 10)) & 0x7c00) |
 216                     ((rgb >> ( 8 + 3 -  5)) & 0x03e0) |
 217                     ((rgb >> ( 0 + 3 -  0)) & 0x001f));
 218         }
 219 
 220         public int pixelToRgb(int pixel, ColorModel cm) {
 221             int r, g, b;
 222             r = (pixel >> 10) & 0x1f;
 223             r = (r << 3) | (r >> 2);
 224             g = (pixel >>  5) & 0x1f;
 225             g = (g << 3) | (g >> 2);
 226             b = (pixel      ) & 0x1f;
 227             b = (b << 3) | (b >> 2);
 228             return (0xff000000 | (r << 16) | (g << 8) | (b));
 229         }
 230     }
 231     public static class Ushort4444Argb extends PixelConverter {
 232         public static final PixelConverter instance = new Ushort4444Argb();
 233 
 234         private Ushort4444Argb() {
 235             alphaMask = 0xf000;
 236         }
 237 
 238         public int rgbToPixel(int rgb, ColorModel cm) {
 239             // use upper 4 bits for each color
 240             // 0xAaRrGgBb -> 0x0000ARGB
 241             int a = (rgb >> 16) & 0xf000;
 242             int r = (rgb >> 12) & 0x0f00;
 243             int g = (rgb >>  8) & 0x00f0;
 244             int b = (rgb >>  4) & 0x000f;
 245 
 246             return (a | r | g | b);
 247         }
 248 
 249         public int pixelToRgb(int pixel, ColorModel cm) {
 250             int a, r, g, b;
 251             // replicate 4 bits for each color
 252             // 0xARGB -> 0xAARRGGBB
 253             a = pixel & 0xf000;
 254             a = ((pixel << 16) | (pixel << 12)) & 0xff000000;
 255             r = pixel & 0x0f00;
 256             r = ((pixel << 12) | (pixel <<  8)) & 0x00ff0000;
 257             g = pixel & 0x00f0;
 258             g = ((pixel <<  8) | (pixel <<  4)) & 0x0000ff00;
 259             b = pixel & 0x000f;
 260             b = ((pixel <<  4) | (pixel <<  0)) & 0x000000ff;
 261 
 262             return (a | r | g | b);
 263         }
 264     }
 265     public static class Xbgr extends PixelConverter {
 266         public static final PixelConverter instance = new Xbgr();
 267 
 268         private Xbgr() {}
 269 
 270         public int rgbToPixel(int rgb, ColorModel cm) {
 271             return (((rgb & 0xff) << 16) |
 272                     (rgb & 0xff00) |
 273                     ((rgb >> 16) & 0xff));
 274         }
 275 
 276         public int pixelToRgb(int pixel, ColorModel cm) {
 277             return (0xff000000 |
 278                     ((pixel & 0xff) << 16) |
 279                     (pixel & 0xff00) |
 280                     ((pixel >> 16) & 0xff));
 281         }
 282     }
 283     public static class Bgrx extends PixelConverter {
 284         public static final PixelConverter instance = new Bgrx();
 285 
 286         private Bgrx() {}
 287 
 288         public int rgbToPixel(int rgb, ColorModel cm) {
 289             return ((rgb << 24) |
 290                     ((rgb & 0xff00) << 8) |
 291                     ((rgb >> 8) & 0xff00));
 292         }
 293 
 294         public int pixelToRgb(int pixel, ColorModel cm) {
 295             return (0xff000000                   |
 296                     ((pixel & 0xff00) << 8) |
 297                     ((pixel >> 8) & 0xff00) |
 298                     (pixel >>> 24));
 299         }
 300     }
 301     public static class Rgba extends PixelConverter {
 302         public static final PixelConverter instance = new Rgba();
 303 
 304         private Rgba() {
 305             alphaMask = 0x000000ff;
 306         }
 307 
 308         public int rgbToPixel(int rgb, ColorModel cm) {
 309             return ((rgb << 8) | (rgb >>> 24));
 310         }
 311 
 312         public int pixelToRgb(int pixel, ColorModel cm) {
 313             return ((pixel << 24) | (pixel >>> 8));
 314         }
 315     }
 316     public static class RgbaPre extends PixelConverter {
 317         public static final PixelConverter instance = new RgbaPre();
 318 
 319         private RgbaPre() {
 320             alphaMask = 0x000000ff;
 321         }
 322 
 323         public int rgbToPixel(int rgb, ColorModel cm) {
 324             if ((rgb >> 24) == -1) {
 325                 return ((rgb << 8) | (rgb >>> 24));
 326             }
 327             int a = rgb >>> 24;
 328             int r = (rgb >> 16) & 0xff;
 329             int g = (rgb >>  8) & 0xff;
 330             int b = (rgb      ) & 0xff;
 331             int a2 = a + (a >> 7);
 332             r = (r * a2) >> 8;
 333             g = (g * a2) >> 8;
 334             b = (b * a2) >> 8;
 335             return ((r << 24) | (g << 16) | (b << 8) | (a));
 336         }
 337 
 338         public int pixelToRgb(int pixel, ColorModel cm) {
 339             int a = pixel & 0xff;
 340             if ((a == 0xff) || (a == 0)) {
 341                 return ((pixel >>> 8) | (pixel << 24));
 342             }
 343             int r = pixel >>> 24;
 344             int g = (pixel >> 16) & 0xff;
 345             int b = (pixel >>  8) & 0xff;
 346             r = ((r << 8) - r) / a;
 347             g = ((g << 8) - g) / a;
 348             b = ((b << 8) - b) / a;
 349             return ((r << 24) | (g << 16) | (b << 8) | (a));
 350         }
 351     }
 352     public static class ArgbPre extends PixelConverter {
 353         public static final PixelConverter instance = new ArgbPre();
 354 
 355         private ArgbPre() {
 356             alphaMask = 0xff000000;
 357         }
 358 
 359         public int rgbToPixel(int rgb, ColorModel cm) {
 360             if ((rgb >> 24) == -1) {
 361                 return rgb;
 362             }
 363             int a = rgb >>> 24;
 364             int r = (rgb >> 16) & 0xff;
 365             int g = (rgb >>  8) & 0xff;
 366             int b = (rgb      ) & 0xff;
 367             int a2 = a + (a >> 7);
 368             r = (r * a2) >> 8;
 369             g = (g * a2) >> 8;
 370             b = (b * a2) >> 8;
 371             return ((a << 24) | (r << 16) | (g << 8) | (b));
 372         }
 373 
 374         public int pixelToRgb(int pixel, ColorModel cm) {
 375             int a = pixel >>> 24;
 376             if ((a == 0xff) || (a == 0)) {
 377                 return pixel;
 378             }
 379             int r = (pixel >> 16) & 0xff;
 380             int g = (pixel >>  8) & 0xff;
 381             int b = (pixel      ) & 0xff;
 382             r = ((r << 8) - r) / a;
 383             g = ((g << 8) - g) / a;
 384             b = ((b << 8) - b) / a;
 385             return ((a << 24) | (r << 16) | (g << 8) | (b));
 386         }
 387     }
 388     public static class ArgbBm extends PixelConverter {
 389         public static final PixelConverter instance = new ArgbBm();
 390 
 391         private ArgbBm() {}
 392 
 393         public int rgbToPixel(int rgb, ColorModel cm) {
 394             return (rgb | ((rgb >> 31) << 24));
 395         }
 396 
 397         public int pixelToRgb(int pixel, ColorModel cm) {
 398             return ((pixel << 7) >> 7);
 399         }
 400     }
 401     public static class ByteGray extends PixelConverter {
 402         static final double RED_MULT = 0.299;
 403         static final double GRN_MULT = 0.587;
 404         static final double BLU_MULT = 0.114;
 405         public static final PixelConverter instance = new ByteGray();
 406 
 407         private ByteGray() {}
 408 
 409         public int rgbToPixel(int rgb, ColorModel cm) {
 410             int red = (rgb >> 16) & 0xff;
 411             int grn = (rgb >>  8) & 0xff;
 412             int blu = (rgb      ) & 0xff;
 413             return (int) (red * RED_MULT +
 414                           grn * GRN_MULT +
 415                           blu * BLU_MULT +
 416                           0.5);
 417         }
 418 
 419         public int pixelToRgb(int pixel, ColorModel cm) {
 420             return ((((((0xff << 8) | pixel) << 8) | pixel) << 8) | pixel);
 421         }
 422     }
 423     public static class UshortGray extends ByteGray {
 424         static final double SHORT_MULT = 257.0; // (65535.0 / 255.0);
 425         static final double USHORT_RED_MULT = RED_MULT * SHORT_MULT;
 426         static final double USHORT_GRN_MULT = GRN_MULT * SHORT_MULT;
 427         static final double USHORT_BLU_MULT = BLU_MULT * SHORT_MULT;
 428         public static final PixelConverter instance = new UshortGray();
 429 
 430         private UshortGray() {}
 431 
 432         public int rgbToPixel(int rgb, ColorModel cm) {
 433             int red = (rgb >> 16) & 0xff;
 434             int grn = (rgb >>  8) & 0xff;
 435             int blu = (rgb      ) & 0xff;
 436             return (int) (red * USHORT_RED_MULT +
 437                           grn * USHORT_GRN_MULT +
 438                           blu * USHORT_BLU_MULT +
 439                           0.5);
 440         }
 441 
 442         public int pixelToRgb(int pixel, ColorModel cm) {
 443             pixel = pixel >> 8;
 444             return ((((((0xff << 8) | pixel) << 8) | pixel) << 8) | pixel);
 445         }
 446     }
 447 }