View Javadoc
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  package org.apache.commons.imaging.formats.bmp;
18  
19  import static org.apache.commons.imaging.common.BinaryFunctions.read2Bytes;
20  import static org.apache.commons.imaging.common.BinaryFunctions.read3Bytes;
21  import static org.apache.commons.imaging.common.BinaryFunctions.read4Bytes;
22  import static org.apache.commons.imaging.common.BinaryFunctions.readByte;
23  
24  import java.io.IOException;
25  import java.nio.ByteOrder;
26  
27  import org.apache.commons.imaging.ImagingException;
28  
29  final class PixelParserBitFields extends AbstractPixelParserSimple {
30  
31      private final int redShift;
32      private final int greenShift;
33      private final int blueShift;
34      private final int alphaShift;
35  
36      private final int redMask;
37      private final int greenMask;
38      private final int blueMask;
39      private final int alphaMask;
40  
41      private int byteCount;
42  
43      PixelParserBitFields(final BmpHeaderInfo bhi, final byte[] colorTable, final byte[] imageData) {
44          super(bhi, colorTable, imageData);
45  
46          redMask = bhi.redMask;
47          greenMask = bhi.greenMask;
48          blueMask = bhi.blueMask;
49          alphaMask = bhi.alphaMask;
50  
51          redShift = getMaskShift(redMask);
52          greenShift = getMaskShift(greenMask);
53          blueShift = getMaskShift(blueMask);
54          alphaShift = alphaMask != 0 ? getMaskShift(alphaMask) : 0;
55      }
56  
57      private int getMaskShift(int mask) {
58          if (mask == 0) {
59              return 0;
60          }
61  
62          int trailingZeroes = 0;
63  
64          while ((0x1 & mask) == 0) {
65              mask = 0x7fffffff & mask >> 1;
66              trailingZeroes++;
67          }
68  
69          int maskLength = 0;
70  
71          while ((0x1 & mask) == 1) {
72              mask = 0x7fffffff & mask >> 1;
73              maskLength++;
74          }
75  
76          return trailingZeroes - (8 - maskLength);
77      }
78  
79      @Override
80      public int getNextRgb() throws ImagingException, IOException {
81          int data;
82  
83          switch (bhi.bitsPerPixel) {
84          case 8:
85              data = 0xff & imageData[byteCount + 0];
86              byteCount += 1;
87              break;
88          case 24:
89              data = read3Bytes("Pixel", is, "BMP Image Data", ByteOrder.LITTLE_ENDIAN);
90              byteCount += 3;
91              break;
92          case 32:
93              data = read4Bytes("Pixel", is, "BMP Image Data", ByteOrder.LITTLE_ENDIAN);
94              byteCount += 4;
95              break;
96          case 16:
97              data = read2Bytes("Pixel", is, "BMP Image Data", ByteOrder.LITTLE_ENDIAN);
98              byteCount += 2;
99              break;
100         default:
101             throw new ImagingException("Unknown BitsPerPixel: " + bhi.bitsPerPixel);
102         }
103 
104         int red = redMask & data;
105         int green = greenMask & data;
106         int blue = blueMask & data;
107         int alpha = alphaMask != 0 ? alphaMask & data : 0xff;
108 
109         red = redShift >= 0 ? red >> redShift : red << -redShift;
110         green = greenShift >= 0 ? green >> greenShift : green << -greenShift;
111         blue = blueShift >= 0 ? blue >> blueShift : blue << -blueShift;
112         alpha = alphaShift >= 0 ? alpha >> alphaShift : alpha << -alphaShift;
113 
114         return alpha << 24 | red << 16 | green << 8 | blue << 0;
115     }
116 
117     @Override
118     public void newline() throws ImagingException, IOException {
119         while (byteCount % 4 != 0) {
120             readByte("Pixel", is, "BMP Image Data");
121             byteCount++;
122         }
123     }
124 }