src/share/classes/sun/java2d/cmm/lcms/LCMSImageLayout.java

Print this page




   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.java2d.cmm.lcms;
  27 
  28 import java.awt.Graphics2D;
  29 import java.awt.image.BufferedImage;
  30 import java.awt.image.ComponentColorModel;
  31 import java.awt.image.Raster;
  32 import java.awt.image.WritableRaster;
  33 import java.awt.image.SinglePixelPackedSampleModel;
  34 import java.awt.image.ComponentSampleModel;
  35 import java.awt.image.DataBuffer;
  36 import java.awt.image.DataBufferByte;
  37 import java.awt.image.DataBufferUShort;
  38 import java.awt.image.DataBufferInt;
  39 import java.awt.image.ColorModel;


  40 import sun.awt.image.ByteComponentRaster;
  41 import sun.awt.image.ShortComponentRaster;
  42 import sun.awt.image.IntegerComponentRaster;
  43 
  44 
  45 class LCMSImageLayout {
  46 
  47     public static int BYTES_SH(int x) {
  48         return x;
  49     }
  50 
  51     public static int EXTRA_SH(int x) {
  52         return x<<7;
  53     }
  54 
  55     public static int CHANNELS_SH(int x) {
  56         return x<<3;
  57     }
  58 
  59     public static final int SWAPFIRST   = 1<<14;
  60 
  61     public static final int DOSWAP      = 1<<10;
  62 
  63     public static final int PT_RGB_8 =
  64         CHANNELS_SH(3) | BYTES_SH(1);
  65 
  66     public static final int PT_GRAY_8 =
  67         CHANNELS_SH(1) | BYTES_SH(1);
  68 
  69     public static final int PT_GRAY_16 =
  70         CHANNELS_SH(1) | BYTES_SH(2);
  71 
  72     public static final int PT_RGBA_8 =
  73         EXTRA_SH(1) | CHANNELS_SH(3) | BYTES_SH(1);
  74 
  75     public static final int PT_ARGB_8 =
  76         EXTRA_SH(1) | CHANNELS_SH(3) | BYTES_SH(1) | SWAPFIRST;
  77 
  78     public static final int PT_BGR_8 =
  79         DOSWAP | CHANNELS_SH(3) | BYTES_SH(1);
  80 
  81     public static final int PT_ABGR_8 =
  82         DOSWAP | EXTRA_SH(1) | CHANNELS_SH(3) | BYTES_SH(1);
  83 
  84     public static final int PT_BGRA_8 = EXTRA_SH(1) | CHANNELS_SH(3) |
  85         BYTES_SH(1) | DOSWAP | SWAPFIRST;
  86 
  87     public static final int DT_BYTE     = 0;
  88     public static final int DT_SHORT    = 1;
  89     public static final int DT_INT      = 2;
  90     public static final int DT_DOUBLE   = 3;
  91 
  92 
  93     boolean isIntPacked = false;
  94     int pixelType;
  95     int dataType;
  96     int width;
  97     int height;
  98     int nextRowOffset;
  99     int offset;
 100 





 101     Object dataArray;

 102     private LCMSImageLayout(int np, int pixelType, int pixelSize) {
 103         this.pixelType = pixelType;
 104         width = np;
 105         height = 1;
 106         nextRowOffset = np*pixelSize;
 107         offset = 0;
 108     }
 109 
 110     private LCMSImageLayout(int width, int height, int pixelType,
 111                             int pixelSize) {
 112         this.pixelType = pixelType;
 113         this.width = width;
 114         this.height = height;
 115         nextRowOffset = width*pixelSize;
 116         offset = 0;
 117     }
 118 
 119 
 120     public LCMSImageLayout(byte[] data, int np, int pixelType, int pixelSize) {
 121         this(np, pixelType, pixelSize);
 122         dataType = DT_BYTE;
 123         dataArray = data;
 124     }
 125 
 126     public LCMSImageLayout(short[] data, int np, int pixelType, int pixelSize) {
 127         this(np, pixelType, pixelSize);
 128         dataType = DT_SHORT;
 129         dataArray = data;
 130     }
 131 
 132     public LCMSImageLayout(int[] data, int np, int pixelType, int pixelSize) {
 133         this(np, pixelType, pixelSize);
 134         dataType = DT_INT;
 135         dataArray = data;
 136     }
 137 
 138     public LCMSImageLayout(double[] data, int np, int pixelType, int pixelSize)
 139     {
 140         this(np, pixelType, pixelSize);
 141         dataType = DT_DOUBLE;
 142         dataArray = data;
 143     }
 144 
 145     public LCMSImageLayout(BufferedImage image) {
 146         ShortComponentRaster shortRaster;
 147         IntegerComponentRaster intRaster;
 148         ByteComponentRaster byteRaster;





 149         switch (image.getType()) {
 150             case BufferedImage.TYPE_INT_RGB:
 151                 pixelType = PT_ARGB_8;
 152                 isIntPacked = true;
 153                 break;
 154             case BufferedImage.TYPE_INT_ARGB:
 155                 pixelType = PT_ARGB_8;
 156                 isIntPacked = true;
 157                 break;
 158             case BufferedImage.TYPE_INT_BGR:
 159                 pixelType = PT_ABGR_8;
 160                 isIntPacked = true;
 161                 break;
 162             case BufferedImage.TYPE_3BYTE_BGR:
 163                 pixelType = PT_BGR_8;
 164                 break;
 165             case BufferedImage.TYPE_4BYTE_ABGR:
 166                 pixelType = PT_ABGR_8;
 167                 break;
 168             case BufferedImage.TYPE_BYTE_GRAY:
 169                 pixelType = PT_GRAY_8;
 170                 break;
 171             case BufferedImage.TYPE_USHORT_GRAY:
 172                 pixelType = PT_GRAY_16;
 173                 break;
 174             default:
 175             // TODO: Add support for some images having
 176             // SinglePixelPackedModel and ComponentSampleModel
 177                 throw new IllegalArgumentException(
 178                     "CMMImageLayout - bad image type passed to constructor");
















 179         }
 180 
 181         width = image.getWidth();
 182         height = image.getHeight();
 183 
 184         switch (image.getType()) {
 185             case BufferedImage.TYPE_INT_RGB:
 186             case BufferedImage.TYPE_INT_ARGB:
 187             case BufferedImage.TYPE_INT_BGR:
 188                 intRaster = (IntegerComponentRaster)image.getRaster();
 189                 nextRowOffset = intRaster.getScanlineStride()*4;
 190                 offset = intRaster.getDataOffset(0)*4;
 191                 dataArray = intRaster.getDataStorage();
 192                 dataType = DT_INT;







 193                 break;
 194 
 195             case BufferedImage.TYPE_3BYTE_BGR:
 196             case BufferedImage.TYPE_4BYTE_ABGR:
 197                 byteRaster = (ByteComponentRaster)image.getRaster();
 198                 nextRowOffset = byteRaster.getScanlineStride();


 199                 int firstBand = image.getSampleModel().getNumBands() - 1;
 200                 offset = byteRaster.getDataOffset(firstBand);
 201                 dataArray = byteRaster.getDataStorage();
 202                 dataType = DT_BYTE;




 203                 break;
 204 
 205             case BufferedImage.TYPE_BYTE_GRAY:
 206                 byteRaster = (ByteComponentRaster)image.getRaster();
 207                 nextRowOffset = byteRaster.getScanlineStride();
 208                 offset = byteRaster.getDataOffset(0);
 209                 dataArray = byteRaster.getDataStorage();
 210                 dataType = DT_BYTE;







 211                 break;
 212 
 213             case BufferedImage.TYPE_USHORT_GRAY:
 214                 shortRaster = (ShortComponentRaster)image.getRaster();
 215                 nextRowOffset = shortRaster.getScanlineStride()*2;
 216                 offset = shortRaster.getDataOffset(0) * 2;
 217                 dataArray = shortRaster.getDataStorage();
 218                 dataType = DT_SHORT;







 219                 break;


 220         }

 221     }
 222 
 223     public static boolean isSupported(BufferedImage image) {
 224         switch (image.getType()) {
 225             case BufferedImage.TYPE_INT_RGB:
 226             case BufferedImage.TYPE_INT_ARGB:
 227             case BufferedImage.TYPE_INT_BGR:
 228             case BufferedImage.TYPE_3BYTE_BGR:
 229             case BufferedImage.TYPE_4BYTE_ABGR:
 230             case BufferedImage.TYPE_BYTE_GRAY:
 231             case BufferedImage.TYPE_USHORT_GRAY:
 232                 return true;


































































 233         }
 234         return false;
 235     }
 236 }


   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 package sun.java2d.cmm.lcms;
  26 

  27 import java.awt.image.BufferedImage;
  28 import java.awt.image.ComponentColorModel;



  29 import java.awt.image.ComponentSampleModel;
  30 import java.awt.image.DataBuffer;



  31 import java.awt.image.ColorModel;
  32 import java.awt.image.Raster;
  33 import java.awt.image.SampleModel;
  34 import sun.awt.image.ByteComponentRaster;
  35 import sun.awt.image.ShortComponentRaster;
  36 import sun.awt.image.IntegerComponentRaster;
  37 

  38 class LCMSImageLayout {
  39 
  40     public static int BYTES_SH(int x) {
  41         return x;
  42     }
  43 
  44     public static int EXTRA_SH(int x) {
  45         return x << 7;
  46     }
  47 
  48     public static int CHANNELS_SH(int x) {
  49         return x << 3;
  50     }
  51     public static final int SWAPFIRST = 1 << 14;
  52     public static final int DOSWAP = 1 << 10;



  53     public static final int PT_RGB_8 =
  54             CHANNELS_SH(3) | BYTES_SH(1);

  55     public static final int PT_GRAY_8 =
  56             CHANNELS_SH(1) | BYTES_SH(1);

  57     public static final int PT_GRAY_16 =
  58             CHANNELS_SH(1) | BYTES_SH(2);

  59     public static final int PT_RGBA_8 =
  60             EXTRA_SH(1) | CHANNELS_SH(3) | BYTES_SH(1);

  61     public static final int PT_ARGB_8 =
  62             EXTRA_SH(1) | CHANNELS_SH(3) | BYTES_SH(1) | SWAPFIRST;

  63     public static final int PT_BGR_8 =
  64             DOSWAP | CHANNELS_SH(3) | BYTES_SH(1);

  65     public static final int PT_ABGR_8 =
  66             DOSWAP | EXTRA_SH(1) | CHANNELS_SH(3) | BYTES_SH(1);
  67     public static final int PT_BGRA_8 = EXTRA_SH(1) | CHANNELS_SH(3)
  68             | BYTES_SH(1) | DOSWAP | SWAPFIRST;


  69     public static final int DT_BYTE = 0;
  70     public static final int DT_SHORT = 1;
  71     public static final int DT_INT = 2;
  72     public static final int DT_DOUBLE = 3;


  73     boolean isIntPacked = false;
  74     int pixelType;
  75     int dataType;
  76     int width;
  77     int height;
  78     int nextRowOffset;
  79     int offset;
  80 
  81     /* This flag indicates whether the image can be processed
  82      * at once by doTransfrom() native call. Otherwise, the
  83      * image is processed scan by scan.
  84      */
  85     private boolean imageAtOnce = false;
  86     Object dataArray;
  87 
  88     private LCMSImageLayout(int np, int pixelType, int pixelSize) {
  89         this.pixelType = pixelType;
  90         width = np;
  91         height = 1;
  92         nextRowOffset = np * pixelSize;
  93         offset = 0;
  94     }
  95 
  96     private LCMSImageLayout(int width, int height, int pixelType,
  97             int pixelSize) {
  98         this.pixelType = pixelType;
  99         this.width = width;
 100         this.height = height;
 101         nextRowOffset = width * pixelSize;
 102         offset = 0;
 103     }
 104 

 105     public LCMSImageLayout(byte[] data, int np, int pixelType, int pixelSize) {
 106         this(np, pixelType, pixelSize);
 107         dataType = DT_BYTE;
 108         dataArray = data;
 109     }
 110 
 111     public LCMSImageLayout(short[] data, int np, int pixelType, int pixelSize) {
 112         this(np, pixelType, pixelSize);
 113         dataType = DT_SHORT;
 114         dataArray = data;
 115     }
 116 
 117     public LCMSImageLayout(int[] data, int np, int pixelType, int pixelSize) {
 118         this(np, pixelType, pixelSize);
 119         dataType = DT_INT;
 120         dataArray = data;
 121     }
 122 
 123     public LCMSImageLayout(double[] data, int np, int pixelType, int pixelSize) {

 124         this(np, pixelType, pixelSize);
 125         dataType = DT_DOUBLE;
 126         dataArray = data;
 127     }
 128 
 129     private LCMSImageLayout() {
 130     }
 131 
 132     /* This method creates a layout object for given image.
 133      * Returns null if the image is not supported by current implementation.
 134      */
 135     public static LCMSImageLayout createImageLayout(BufferedImage image) {
 136         LCMSImageLayout l = new LCMSImageLayout();
 137 
 138         switch (image.getType()) {
 139             case BufferedImage.TYPE_INT_RGB:
 140                 l.pixelType = PT_ARGB_8;
 141                 l.isIntPacked = true;
 142                 break;
 143             case BufferedImage.TYPE_INT_ARGB:
 144                 l.pixelType = PT_ARGB_8;
 145                 l.isIntPacked = true;
 146                 break;
 147             case BufferedImage.TYPE_INT_BGR:
 148                 l.pixelType = PT_ABGR_8;
 149                 l.isIntPacked = true;
 150                 break;
 151             case BufferedImage.TYPE_3BYTE_BGR:
 152                 l.pixelType = PT_BGR_8;
 153                 break;
 154             case BufferedImage.TYPE_4BYTE_ABGR:
 155                 l.pixelType = PT_ABGR_8;
 156                 break;
 157             case BufferedImage.TYPE_BYTE_GRAY:
 158                 l.pixelType = PT_GRAY_8;
 159                 break;
 160             case BufferedImage.TYPE_USHORT_GRAY:
 161                 l.pixelType = PT_GRAY_16;
 162                 break;
 163             default:
 164                 /* ColorConvertOp creates component images as
 165                  * default destination, so this kind of images
 166                  * has to be supported.
 167                  */
 168                 ColorModel cm = image.getColorModel();
 169                 if (cm instanceof ComponentColorModel) {
 170                     ComponentColorModel ccm = (ComponentColorModel) cm;
 171 
 172                     // verify whether the component size is fine
 173                     int[] cs = ccm.getComponentSize();
 174                     for (int s : cs) {
 175                         if (s != 8) {
 176                             return null;
 177                         }
 178                     }
 179 
 180                     return createImageLayout(image.getRaster());
 181 
 182                 }
 183                 return null;
 184         }
 185 
 186         l.width = image.getWidth();
 187         l.height = image.getHeight();
 188 
 189         switch (image.getType()) {
 190             case BufferedImage.TYPE_INT_RGB:
 191             case BufferedImage.TYPE_INT_ARGB:
 192             case BufferedImage.TYPE_INT_BGR:
 193                 do {
 194                     IntegerComponentRaster intRaster = (IntegerComponentRaster)
 195                             image.getRaster();
 196                     l.nextRowOffset = intRaster.getScanlineStride() * 4;
 197                     l.offset = intRaster.getDataOffset(0) * 4;
 198                     l.dataArray = intRaster.getDataStorage();
 199                     l.dataType = DT_INT;
 200 
 201                     if (l.nextRowOffset == l.width * 4 * intRaster.getPixelStride()) {
 202                         l.imageAtOnce = true;
 203                     }
 204                 } while (false);
 205                 break;
 206 
 207             case BufferedImage.TYPE_3BYTE_BGR:
 208             case BufferedImage.TYPE_4BYTE_ABGR:
 209                 do {
 210                     ByteComponentRaster byteRaster = (ByteComponentRaster)
 211                             image.getRaster();
 212                     l.nextRowOffset = byteRaster.getScanlineStride();
 213                     int firstBand = image.getSampleModel().getNumBands() - 1;
 214                     l.offset = byteRaster.getDataOffset(firstBand);
 215                     l.dataArray = byteRaster.getDataStorage();
 216                     l.dataType = DT_BYTE;
 217                     if (l.nextRowOffset == l.width * byteRaster.getPixelStride()) {
 218                         l.imageAtOnce = true;
 219                     }
 220                 } while (false);
 221                 break;
 222 
 223             case BufferedImage.TYPE_BYTE_GRAY:
 224                 do {
 225                     ByteComponentRaster byteRaster = (ByteComponentRaster)
 226                             image.getRaster();
 227                     l.nextRowOffset = byteRaster.getScanlineStride();
 228                     l.offset = byteRaster.getDataOffset(0);
 229                     l.dataArray = byteRaster.getDataStorage();
 230                     l.dataType = DT_BYTE;
 231 
 232                     if (l.nextRowOffset == l.width * byteRaster.getPixelStride()) {
 233                         l.imageAtOnce = true;
 234                     }
 235                 } while (false);
 236                 break;
 237 
 238             case BufferedImage.TYPE_USHORT_GRAY:
 239                 do {
 240                     ShortComponentRaster shortRaster = (ShortComponentRaster)
 241                             image.getRaster();
 242                     l.nextRowOffset = shortRaster.getScanlineStride() * 2;
 243                     l.offset = shortRaster.getDataOffset(0) * 2;
 244                     l.dataArray = shortRaster.getDataStorage();
 245                     l.dataType = DT_SHORT;
 246 
 247                     if (l.nextRowOffset == l.width * 2 * shortRaster.getPixelStride()) {
 248                         l.imageAtOnce = true;
 249                     }
 250                 } while (false);
 251                 break;
 252             default:
 253                 return null;
 254         }
 255         return l;
 256     }
 257 
 258     private static enum BandOrder {
 259         DIRECT,
 260         INVERTED,
 261         ARBITRARY,
 262         UNKNOWN;
 263 
 264         public static BandOrder getBandOrder(int[] bandOffsets) {
 265             BandOrder order = UNKNOWN;
 266 
 267             int numBands = bandOffsets.length;
 268 
 269             for (int i = 0; (order != ARBITRARY) && (i < bandOffsets.length); i++) {
 270                 switch (order) {
 271                     case UNKNOWN:
 272                         if (bandOffsets[i] == i) {
 273                             order = DIRECT;
 274                         } else if (bandOffsets[i] == (numBands - 1 - i)) {
 275                             order = INVERTED;
 276                         } else {
 277                             order = ARBITRARY;
 278                         }
 279                         break;
 280                     case DIRECT:
 281                         if (bandOffsets[i] != i) {
 282                             order = ARBITRARY;
 283                         }
 284                         break;
 285                     case INVERTED:
 286                         if (bandOffsets[i] != (numBands - 1 - i)) {
 287                             order = ARBITRARY;
 288                         }
 289                         break;
 290                 }
 291             }
 292             return order;
 293         }
 294     }
 295 
 296     public static LCMSImageLayout createImageLayout(Raster r) {
 297         LCMSImageLayout l = new LCMSImageLayout();
 298         if (r instanceof ByteComponentRaster) {
 299             ByteComponentRaster br = (ByteComponentRaster)r;
 300 
 301             ComponentSampleModel csm = (ComponentSampleModel)r.getSampleModel();
 302 
 303             l.pixelType = CHANNELS_SH(br.getNumBands()) | BYTES_SH(1);
 304 
 305             int[] bandOffsets = csm.getBandOffsets();
 306             BandOrder order = BandOrder.getBandOrder(bandOffsets);
 307 
 308             int firstBand = 0;
 309             switch (order) {
 310                 case INVERTED:
 311                     l.pixelType |= DOSWAP;
 312                     firstBand  = csm.getNumBands() - 1;
 313                     break;
 314                 case DIRECT:
 315                     // do nothing
 316                     break;
 317                 default:
 318                     // unable to create the image layout;
 319                     return null;
 320             }
 321 
 322             l.nextRowOffset = br.getScanlineStride();
 323             l.offset = br.getDataOffset(firstBand);
 324             l.dataArray = br.getDataStorage();
 325             l.dataType = DT_BYTE;
 326 
 327             l.width = br.getWidth();
 328             l.height = br.getHeight();
 329 
 330             if (l.nextRowOffset == l.width * br.getPixelStride()) {
 331                 l.imageAtOnce = true;
 332             }
 333             return l;
 334         }
 335         return null;
 336     }
 337 }