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 java.io.IOException;
20  import java.util.logging.Logger;
21  
22  import org.apache.commons.imaging.ImagingException;
23  import org.apache.commons.imaging.common.BinaryFunctions;
24  import org.apache.commons.imaging.common.ImageBuilder;
25  
26  final class PixelParserRle extends AbstractPixelParser {
27  
28      private static final Logger LOGGER = Logger.getLogger(PixelParserRle.class.getName());
29  
30      PixelParserRle(final BmpHeaderInfo bhi, final byte[] colorTable, final byte[] imageData) {
31          super(bhi, colorTable, imageData);
32      }
33  
34      private int[] convertDataToSamples(final int data) throws ImagingException {
35          int[] rgbs;
36          if (bhi.bitsPerPixel == 8) {
37              rgbs = new int[1];
38              rgbs[0] = getColorTableRgb(data);
39              // pixels_written = 1;
40          } else if (bhi.bitsPerPixel == 4) {
41              rgbs = new int[2];
42              final int sample1 = data >> 4;
43              final int sample2 = 0x0f & data;
44              rgbs[0] = getColorTableRgb(sample1);
45              rgbs[1] = getColorTableRgb(sample2);
46              // pixels_written = 2;
47          } else {
48              throw new ImagingException("BMP RLE: bad BitsPerPixel: " + bhi.bitsPerPixel);
49          }
50  
51          return rgbs;
52      }
53  
54      private int getSamplesPerByte() throws ImagingException {
55          if (bhi.bitsPerPixel == 8) {
56              return 1;
57          }
58          if (bhi.bitsPerPixel == 4) {
59              return 2;
60          }
61          throw new ImagingException("BMP RLE: bad BitsPerPixel: " + bhi.bitsPerPixel);
62      }
63  
64      private int processByteOfData(final int[] rgbs, final int repeat, int x, final int y, final int width, final int height, final ImageBuilder imageBuilder) {
65          // int rbg
66          int pixelsWritten = 0;
67          for (int i = 0; i < repeat; i++) {
68  
69              if (x >= 0 && x < width && y >= 0 && y < height) {
70                  // int rgb = 0xff000000;
71                  // rgb = getNextRGB();
72                  final int rgb = rgbs[i % rgbs.length];
73                  // bi.setRGB(x, y, rgb);
74                  imageBuilder.setRgb(x, y, rgb);
75                  // bi.setRGB(x, y, 0xff00ff00);
76              } else {
77                  LOGGER.fine("skipping bad pixel (" + x + "," + y + ")");
78              }
79  
80              x++;
81              pixelsWritten++;
82          }
83  
84          return pixelsWritten;
85      }
86  
87      @Override
88      public void processImage(final ImageBuilder imageBuilder) throws ImagingException, IOException {
89          final int width = bhi.width;
90          final int height = bhi.height;
91          int x = 0;
92          int y = height - 1;
93  
94          boolean done = false;
95          while (!done) {
96              final int a = 0xff & BinaryFunctions.readByte("RLE (" + x + "," + y + ") a", is, "BMP: Bad RLE");
97              final int b = 0xff & BinaryFunctions.readByte("RLE (" + x + "," + y + ") b", is, "BMP: Bad RLE");
98  
99              if (a == 0) {
100                 switch (b) {
101                 case 0: {
102                     // EOL
103                     y--;
104                     x = 0;
105                     break;
106                 }
107                 case 1:
108                     // EOF
109                     done = true;
110                     break;
111                 case 2: {
112                     final int deltaX = 0xff & BinaryFunctions.readByte("RLE deltaX", is, "BMP: Bad RLE");
113                     final int deltaY = 0xff & BinaryFunctions.readByte("RLE deltaY", is, "BMP: Bad RLE");
114                     x += deltaX;
115                     y -= deltaY;
116                     break;
117                 }
118                 default: {
119                     final int samplesPerByte = getSamplesPerByte();
120                     int size = b / samplesPerByte;
121                     if (b % samplesPerByte > 0) {
122                         size++;
123                     }
124                     if (size % 2 != 0) {
125                         size++;
126                     }
127 
128                     // System.out.println("b: " + b);
129                     // System.out.println("size: " + size);
130                     // System.out.println("SamplesPerByte: " + SamplesPerByte);
131 
132                     final byte[] bytes = BinaryFunctions.readBytes("bytes", is, size, "RLE: Absolute Mode");
133 
134                     int remaining = b;
135 
136                     for (int i = 0; remaining > 0; i++) {
137                         // for (int i = 0; i < bytes.length; i++)
138                         final int[] samples = convertDataToSamples(0xff & bytes[i]);
139                         final int towrite = Math.min(remaining, samplesPerByte);
140                         // System.out.println("remaining: " + remaining);
141                         // System.out.println("SamplesPerByte: "
142                         // + SamplesPerByte);
143                         // System.out.println("towrite: " + towrite);
144                         final int written = processByteOfData(samples, towrite, x, y, width, height, imageBuilder);
145                         // System.out.println("written: " + written);
146                         // System.out.println("");
147                         x += written;
148                         remaining -= written;
149                     }
150                     break;
151                 }
152                 }
153             } else {
154                 final int[] rgbs = convertDataToSamples(b);
155 
156                 x += processByteOfData(rgbs, a, x, y, width, height, imageBuilder);
157             }
158         }
159     }
160 }