Make public to enable reuse; add convenience constructor for no cropping, or cropping...
[zxing.git] / android / src / com / google / zxing / client / android / YUVMonochromeBitmapSource.java
1 /*
2  * Copyright (C) 2008 ZXing authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package com.google.zxing.client.android;
18
19 import android.graphics.Bitmap;
20 import android.graphics.Rect;
21 import com.google.zxing.common.BaseMonochromeBitmapSource;
22
23 /**
24  * This object implements MonochromeBitmapSource around an array of YUV data, giving you the option
25  * to crop to a rectangle within the full data. This can be used to exclude superfluous pixels
26  * around the perimeter and speed up decoding.
27  *
28  * @author Sean Owen
29  * @author Daniel Switkin
30  */
31 public final class YUVMonochromeBitmapSource extends BaseMonochromeBitmapSource {
32
33   private final byte[] mYUVData;
34   private final int mDataWidth;
35   private final int mCropTop;
36   private final int mCropLeft;
37   private final int mCropBottom;
38   private final int mCropRight;
39
40   /**
41    * Builds an object around a YUV buffer from the camera. The image is not cropped.
42    *
43    * @param yuvData    A byte array of planar Y data, followed by interleaved U and V
44    * @param dataWidth  The width of the Y data
45    * @param dataHeight The height of the Y data
46    */
47   public YUVMonochromeBitmapSource(byte[] yuvData, int dataWidth, int dataHeight) {
48     this(yuvData, dataWidth, dataHeight, 0, 0, dataHeight, dataWidth);
49   }
50
51   /**
52    * Builds an object around a YUV buffer from the camera. THe image is cropped and only
53    * that part of the image is evaluated.
54    *
55    * @param yuvData    A byte array of planar Y data, followed by interleaved U and V
56    * @param dataWidth  The width of the Y data
57    * @param dataHeight The height of the Y data
58    * @param crop       The rectangle within the yuvData to expose to MonochromeBitmapSource users
59    */
60   public YUVMonochromeBitmapSource(byte[] yuvData, int dataWidth, int dataHeight, Rect crop) {
61     this(yuvData, dataWidth, dataHeight, crop.top, crop.left, crop.bottom, crop.right);
62   }
63
64   /**
65    * Builds an object around a YUV buffer from the camera. The image is cropped and only 
66    * that part of the image is evaluated.
67    *
68    * @param yuvData    A byte array of planar Y data, followed by interleaved U and V
69    * @param dataWidth  The width of the Y data
70    * @param dataHeight The height of the Y data
71    * @param cropTop    Top coordinate of rectangle to crop
72    * @param cropLeft   Left coordinate of rectangle to crop
73    * @param cropBottom Bottom coordinate of rectangle to crop
74    * @param cropRight  Right coordinate of rectangle to crop
75    */
76   public YUVMonochromeBitmapSource(byte[] yuvData,
77                                    int dataWidth,
78                                    int dataHeight,
79                                    int cropTop,
80                                    int cropLeft,
81                                    int cropBottom,
82                                    int cropRight) {
83     if (cropRight - cropLeft > dataWidth || cropBottom - cropTop > dataHeight) {
84       throw new IllegalArgumentException();
85     }
86     mYUVData = yuvData;
87     mDataWidth = dataWidth;
88     this.mCropTop = cropTop;
89     this.mCropLeft = cropLeft;
90     this.mCropBottom = cropBottom;
91     this.mCropRight = cropRight;
92   }
93
94   @Override
95   public int getHeight() {
96     return mCropBottom - mCropTop;
97   }
98
99   @Override
100   public int getWidth() {
101     return mCropRight - mCropLeft;
102   }
103
104   /**
105    * The Y channel is stored as planar data at the head of the array, so we just ignore the
106    * interleavd U and V which follow it.
107    *
108    * @param x The x coordinate to fetch within crop
109    * @param y The y coordinate to fetch within crop
110    * @return The luminance as an int, from 0-255
111    */
112   @Override
113   protected int getLuminance(int x, int y) {
114     return mYUVData[(y + mCropTop) * mDataWidth + x + mCropLeft] & 0xff;
115   }
116
117   @Override
118   protected int[] getLuminanceRow(int y, int[] row) {
119     int width = getWidth();
120     if (row == null || row.length < width) {
121       row = new int[width];
122     }
123     int offset = (y + mCropTop) * mDataWidth + mCropLeft;
124     byte[] yuvData = mYUVData;
125     for (int x = 0; x < width; x++) {
126       row[x] = yuvData[offset + x] & 0xff;
127     }
128     return row;
129   }
130
131   @Override
132   protected int[] getLuminanceColumn(int x, int[] column) {
133     int height = getHeight();
134     if (column == null || column.length < height) {
135       column = new int[height];
136     }
137     int dataWidth = mDataWidth;
138     int offset = mCropTop * dataWidth + mCropLeft + x;
139     byte[] yuvData = mYUVData;
140     for (int y = 0; y < height; y++) {
141       column[y] = yuvData[offset] & 0xff;
142       offset += dataWidth;
143     }
144     return column;
145   }
146
147   /**
148    * Create a greyscale Android Bitmap from the YUV data based on the crop rectangle.
149    *
150    * @return An 8888 bitmap.
151    */
152   public Bitmap renderToBitmap() {
153     int width = getWidth();
154     int height = getHeight();
155     int[] pixels = new int[width * height];
156     byte[] yuvData = mYUVData;
157     for (int y = 0, base = mCropTop * mDataWidth + mCropLeft; y < height; y++, base += mDataWidth) {
158       for (int x = 0; x < width; x++) {
159         int grey = yuvData[base + x] & 0xff;
160         pixels[y * width + x] = (0xff << 24) | (grey << 16) | (grey << 8) | grey;
161       }
162     }
163
164     Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
165     bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
166     return bitmap;
167   }
168
169 }