Home | History | Annotate | Download | only in image
      1 /*
      2  *  Licensed to the Apache Software Foundation (ASF) under one or more
      3  *  contributor license agreements.  See the NOTICE file distributed with
      4  *  this work for additional information regarding copyright ownership.
      5  *  The ASF licenses this file to You under the Apache License, Version 2.0
      6  *  (the "License"); you may not use this file except in compliance with
      7  *  the License.  You may obtain a copy of the License at
      8  *
      9  *     http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  *  Unless required by applicable law or agreed to in writing, software
     12  *  distributed under the License is distributed on an "AS IS" BASIS,
     13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  *  See the License for the specific language governing permissions and
     15  *  limitations under the License.
     16  */
     17 /**
     18  * @author Igor V. Stolyarov
     19  * @version $Revision$
     20  */
     21 
     22 package java.awt.image;
     23 
     24 import java.util.Arrays;
     25 
     26 import org.apache.harmony.awt.internal.nls.Messages;
     27 
     28 /**
     29  * The SinglePixelPackedSampleModel class represents pixel data where several
     30  * samples combine to create a single pixel and are stored in a single data
     31  * array element. This class supports TYPE_BYTE, TYPE_USHORT, TYPE_INT data
     32  * types.
     33  *
     34  * @since Android 1.0
     35  */
     36 public class SinglePixelPackedSampleModel extends SampleModel {
     37 
     38     /**
     39      * The bit masks.
     40      */
     41     private int bitMasks[];
     42 
     43     /**
     44      * The bit offsets.
     45      */
     46     private int bitOffsets[];
     47 
     48     /**
     49      * The bit sizes.
     50      */
     51     private int bitSizes[];
     52 
     53     /**
     54      * The scanline stride.
     55      */
     56     private int scanlineStride;
     57 
     58     /**
     59      * The max bit size.
     60      */
     61     private int maxBitSize;
     62 
     63     /**
     64      * Instantiates a new SinglePixelPackedSampleModel with the specified
     65      * parameters.
     66      *
     67      * @param dataType
     68      *            the data type of samples.
     69      * @param w
     70      *            the width of the image data.
     71      * @param h
     72      *            the height of the image data.
     73      * @param bitMasks
     74      *            the bit masks for all the bands.
     75      */
     76     public SinglePixelPackedSampleModel(int dataType, int w, int h, int bitMasks[]) {
     77         this(dataType, w, h, w, bitMasks);
     78     }
     79 
     80     /**
     81      * Instantiates a new SinglePixelPackedSampleModel with the specified
     82      * parameters.
     83      *
     84      * @param dataType
     85      *            the data type of the samples.
     86      * @param w
     87      *            the width of the image data.
     88      * @param h
     89      *            the height of the image data.
     90      * @param scanlineStride
     91      *            the scanline stride of the image data.
     92      * @param bitMasks
     93      *            the bit masks for all the bands.
     94      */
     95     public SinglePixelPackedSampleModel(int dataType, int w, int h, int scanlineStride,
     96             int bitMasks[]) {
     97 
     98         super(dataType, w, h, bitMasks.length);
     99 
    100         if (dataType != DataBuffer.TYPE_BYTE && dataType != DataBuffer.TYPE_USHORT
    101                 && dataType != DataBuffer.TYPE_INT) {
    102             // awt.61=Unsupported data type: {0}
    103             throw new IllegalArgumentException(Messages.getString("awt.61", //$NON-NLS-1$
    104                     dataType));
    105         }
    106 
    107         this.scanlineStride = scanlineStride;
    108         this.bitMasks = bitMasks.clone();
    109         this.bitOffsets = new int[this.numBands];
    110         this.bitSizes = new int[this.numBands];
    111 
    112         this.maxBitSize = 0;
    113 
    114         for (int i = 0; i < this.numBands; i++) {
    115             int offset = 0;
    116             int size = 0;
    117             int mask = bitMasks[i];
    118 
    119             if (mask != 0) {
    120                 while ((mask & 1) == 0) {
    121                     mask >>>= 1;
    122                     offset++;
    123                 }
    124 
    125                 while ((mask & 1) == 1) {
    126                     mask >>>= 1;
    127                     size++;
    128                 }
    129 
    130                 if (mask != 0) {
    131                     // awt.62=Wrong mask : {0}
    132                     throw new IllegalArgumentException(Messages.getString("awt.62", bitMasks[i])); //$NON-NLS-1$
    133                 }
    134             }
    135 
    136             this.bitOffsets[i] = offset;
    137             this.bitSizes[i] = size;
    138 
    139             if (this.maxBitSize < size) {
    140                 this.maxBitSize = size;
    141             }
    142 
    143         }
    144 
    145     }
    146 
    147     @Override
    148     public Object getDataElements(int x, int y, Object obj, DataBuffer data) {
    149         if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
    150             // awt.63=Coordinates are not in bounds
    151             throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
    152         }
    153         switch (getTransferType()) {
    154             case DataBuffer.TYPE_BYTE:
    155                 byte bdata[];
    156                 if (obj == null) {
    157                     bdata = new byte[1];
    158                 } else {
    159                     bdata = (byte[])obj;
    160                 }
    161 
    162                 bdata[0] = (byte)data.getElem(y * scanlineStride + x);
    163                 obj = bdata;
    164                 break;
    165             case DataBuffer.TYPE_USHORT:
    166                 short sdata[];
    167                 if (obj == null) {
    168                     sdata = new short[1];
    169                 } else {
    170                     sdata = (short[])obj;
    171                 }
    172 
    173                 sdata[0] = (short)data.getElem(y * scanlineStride + x);
    174                 obj = sdata;
    175                 break;
    176             case DataBuffer.TYPE_INT:
    177                 int idata[];
    178                 if (obj == null) {
    179                     idata = new int[1];
    180                 } else {
    181                     idata = (int[])obj;
    182                 }
    183 
    184                 idata[0] = data.getElem(y * scanlineStride + x);
    185                 obj = idata;
    186                 break;
    187         }
    188         return obj;
    189     }
    190 
    191     @Override
    192     public void setDataElements(int x, int y, Object obj, DataBuffer data) {
    193         if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
    194             // awt.63=Coordinates are not in bounds
    195             throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
    196         }
    197         switch (getTransferType()) {
    198             case DataBuffer.TYPE_BYTE:
    199                 data.setElem(y * scanlineStride + x, ((byte[])obj)[0] & 0xff);
    200                 break;
    201             case DataBuffer.TYPE_USHORT:
    202                 data.setElem(y * scanlineStride + x, ((short[])obj)[0] & 0xffff);
    203                 break;
    204             case DataBuffer.TYPE_INT:
    205                 data.setElem(y * scanlineStride + x, ((int[])obj)[0]);
    206                 break;
    207         }
    208     }
    209 
    210     /**
    211      * Compares this SinglePixelPackedSampleModel object with the specified
    212      * object.
    213      *
    214      * @param o
    215      *            the Object to be compared.
    216      * @return true, if this SinglePixelPackedSampleModel object is equal to the
    217      *         specified object, false otherwise.
    218      */
    219     @Override
    220     public boolean equals(Object o) {
    221         if ((o == null) || !(o instanceof SinglePixelPackedSampleModel)) {
    222             return false;
    223         }
    224 
    225         SinglePixelPackedSampleModel model = (SinglePixelPackedSampleModel)o;
    226         return this.width == model.width && this.height == model.height
    227                 && this.numBands == model.numBands && this.dataType == model.dataType
    228                 && Arrays.equals(this.bitMasks, model.bitMasks)
    229                 && Arrays.equals(this.bitOffsets, model.bitOffsets)
    230                 && Arrays.equals(this.bitSizes, model.bitSizes)
    231                 && this.scanlineStride == model.scanlineStride;
    232     }
    233 
    234     @Override
    235     public SampleModel createSubsetSampleModel(int bands[]) {
    236         if (bands.length > this.numBands) {
    237             // awt.64=The number of the bands in the subset is greater than the
    238             // number of bands in the sample model
    239             throw new RasterFormatException(Messages.getString("awt.64")); //$NON-NLS-1$
    240         }
    241 
    242         int masks[] = new int[bands.length];
    243         for (int i = 0; i < bands.length; i++) {
    244             masks[i] = this.bitMasks[bands[i]];
    245         }
    246         return new SinglePixelPackedSampleModel(this.dataType, this.width, this.height,
    247                 this.scanlineStride, masks);
    248     }
    249 
    250     @Override
    251     public SampleModel createCompatibleSampleModel(int w, int h) {
    252         return new SinglePixelPackedSampleModel(this.dataType, w, h, this.bitMasks);
    253     }
    254 
    255     @Override
    256     public int[] getPixel(int x, int y, int iArray[], DataBuffer data) {
    257         if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
    258             // awt.63=Coordinates are not in bounds
    259             throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
    260         }
    261         int pixel[];
    262         if (iArray == null) {
    263             pixel = new int[this.numBands];
    264         } else {
    265             pixel = iArray;
    266         }
    267 
    268         for (int i = 0; i < this.numBands; i++) {
    269             pixel[i] = getSample(x, y, i, data);
    270         }
    271 
    272         return pixel;
    273     }
    274 
    275     @Override
    276     public void setPixel(int x, int y, int iArray[], DataBuffer data) {
    277         if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
    278             // awt.63=Coordinates are not in bounds
    279             throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
    280         }
    281         for (int i = 0; i < this.numBands; i++) {
    282             setSample(x, y, i, iArray[i], data);
    283         }
    284     }
    285 
    286     @Override
    287     public int getSample(int x, int y, int b, DataBuffer data) {
    288         if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
    289             // awt.63=Coordinates are not in bounds
    290             throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
    291         }
    292         int sample = data.getElem(y * scanlineStride + x);
    293         return ((sample & this.bitMasks[b]) >>> this.bitOffsets[b]);
    294     }
    295 
    296     @Override
    297     public int[] getPixels(int x, int y, int w, int h, int iArray[], DataBuffer data) {
    298         if ((x < 0) || (y < 0) || ((long)x + (long)w > this.width)
    299                 || ((long)y + (long)h > this.height)) {
    300             // awt.63=Coordinates are not in bounds
    301             throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
    302         }
    303 
    304         int pixels[];
    305 
    306         if (iArray == null) {
    307             pixels = new int[w * h * this.numBands];
    308         } else {
    309             pixels = iArray;
    310         }
    311 
    312         int idx = 0;
    313 
    314         for (int i = y; i < y + h; i++) {
    315             for (int j = x; j < x + w; j++) {
    316                 for (int n = 0; n < this.numBands; n++) {
    317                     pixels[idx++] = getSample(j, i, n, data);
    318                 }
    319             }
    320         }
    321         return pixels;
    322     }
    323 
    324     @Override
    325     public void setPixels(int x, int y, int w, int h, int iArray[], DataBuffer data) {
    326         if ((x < 0) || (y < 0) || ((long)x + (long)w > this.width)
    327                 || ((long)y + (long)h > this.height)) {
    328             // awt.63=Coordinates are not in bounds
    329             throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
    330         }
    331 
    332         int idx = 0;
    333 
    334         for (int i = y; i < y + h; i++) {
    335             for (int j = x; j < x + w; j++) {
    336                 for (int n = 0; n < this.numBands; n++) {
    337                     setSample(j, i, n, iArray[idx++], data);
    338                 }
    339             }
    340         }
    341     }
    342 
    343     @Override
    344     public void setSample(int x, int y, int b, int s, DataBuffer data) {
    345         if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
    346             // awt.63=Coordinates are not in bounds
    347             throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
    348         }
    349         int tmp = data.getElem(y * scanlineStride + x);
    350         tmp &= ~this.bitMasks[b];
    351         tmp |= (s << this.bitOffsets[b]) & this.bitMasks[b];
    352         data.setElem(y * scanlineStride + x, tmp);
    353     }
    354 
    355     @Override
    356     public int[] getSamples(int x, int y, int w, int h, int b, int iArray[], DataBuffer data) {
    357         if ((x < 0) || (y < 0) || ((long)x + (long)w > this.width)
    358                 || ((long)y + (long)h > this.height)) {
    359             // awt.63=Coordinates are not in bounds
    360             throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
    361         }
    362 
    363         int samples[];
    364         int idx = 0;
    365 
    366         if (iArray == null) {
    367             samples = new int[w * h];
    368         } else {
    369             samples = iArray;
    370         }
    371 
    372         for (int i = y; i < y + h; i++) {
    373             for (int j = x; j < x + w; j++) {
    374                 samples[idx++] = getSample(j, i, b, data);
    375             }
    376         }
    377 
    378         return samples;
    379     }
    380 
    381     @Override
    382     public void setSamples(int x, int y, int w, int h, int b, int iArray[], DataBuffer data) {
    383         if ((x < 0) || (y < 0) || ((long)x + (long)w > this.width)
    384                 || ((long)y + (long)h > this.height)) {
    385             // awt.63=Coordinates are not in bounds
    386             throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
    387         }
    388 
    389         int idx = 0;
    390         for (int i = y; i < y + h; i++) {
    391             for (int j = x; j < x + w; j++) {
    392                 setSample(x + j, y + i, b, iArray[idx++], data);
    393             }
    394         }
    395     }
    396 
    397     @Override
    398     public DataBuffer createDataBuffer() {
    399         DataBuffer data = null;
    400         int size = (this.height - 1) * scanlineStride + width;
    401 
    402         switch (this.dataType) {
    403             case DataBuffer.TYPE_BYTE:
    404                 data = new DataBufferByte(size);
    405                 break;
    406             case DataBuffer.TYPE_USHORT:
    407                 data = new DataBufferUShort(size);
    408                 break;
    409             case DataBuffer.TYPE_INT:
    410                 data = new DataBufferInt(size);
    411                 break;
    412         }
    413         return data;
    414     }
    415 
    416     /**
    417      * Gets the offset of the specified pixel in the data array.
    418      *
    419      * @param x
    420      *            the X coordinate of the specified pixel.
    421      * @param y
    422      *            the Y coordinate of the specified pixel.
    423      * @return the offset of the specified pixel.
    424      */
    425     public int getOffset(int x, int y) {
    426         return (y * scanlineStride + x);
    427     }
    428 
    429     @Override
    430     public int getSampleSize(int band) {
    431         return bitSizes[band];
    432     }
    433 
    434     @Override
    435     public int[] getSampleSize() {
    436         return bitSizes.clone();
    437     }
    438 
    439     /**
    440      * Gets an array of the bit offsets of the data array elements.
    441      *
    442      * @return an array of the bit offsets.
    443      */
    444     public int[] getBitOffsets() {
    445         return bitOffsets.clone();
    446     }
    447 
    448     /**
    449      * Gets an array of the bit masks for all bands.
    450      *
    451      * @return an array of the bit masks for all bands.
    452      */
    453     public int[] getBitMasks() {
    454         return bitMasks.clone();
    455     }
    456 
    457     /**
    458      * Returns a hash code of this MultiPixelPackedSampleModel class.
    459      *
    460      * @return the hash code of this MultiPixelPackedSampleModel class.
    461      */
    462     @Override
    463     public int hashCode() {
    464         int hash = 0;
    465         int tmp = 0;
    466 
    467         hash = width;
    468         tmp = hash >>> 24;
    469         hash <<= 8;
    470         hash |= tmp;
    471         hash ^= height;
    472         tmp = hash >>> 24;
    473         hash <<= 8;
    474         hash |= tmp;
    475         hash ^= numBands;
    476         tmp = hash >>> 24;
    477         hash <<= 8;
    478         hash |= tmp;
    479         hash ^= dataType;
    480         tmp = hash >>> 24;
    481         hash <<= 8;
    482         hash |= tmp;
    483         for (int element : bitMasks) {
    484             hash ^= element;
    485             tmp = hash >>> 24;
    486             hash <<= 8;
    487             hash |= tmp;
    488         }
    489         for (int element : bitOffsets) {
    490             hash ^= element;
    491             tmp = hash >>> 24;
    492             hash <<= 8;
    493             hash |= tmp;
    494         }
    495         for (int element : bitSizes) {
    496             hash ^= element;
    497             tmp = hash >>> 24;
    498             hash <<= 8;
    499             hash |= tmp;
    500         }
    501         hash ^= scanlineStride;
    502         return hash;
    503     }
    504 
    505     /**
    506      * Gets the scanline stride.
    507      *
    508      * @return the scanline stride
    509      */
    510     public int getScanlineStride() {
    511         return this.scanlineStride;
    512     }
    513 
    514     @Override
    515     public int getNumDataElements() {
    516         return 1;
    517     }
    518 
    519 }
    520