/* * Copyright 2012 ZXing.Net authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; namespace ZXing { /// /// Luminance source class which support different formats of images. /// public partial class RGBLuminanceSource : BaseLuminanceSource { /// /// enumeration of supported bitmap format which the RGBLuminanceSource can process /// public enum BitmapFormat { /// /// format of the byte[] isn't known. RGBLuminanceSource tries to determine the best possible value /// Unknown, /// /// grayscale array, the byte array is a luminance array with 1 byte per pixel /// Gray8, /// /// 3 bytes per pixel with the channels red, green and blue /// RGB24, /// /// 4 bytes per pixel with the channels red, green and blue /// RGB32, /// /// 4 bytes per pixel with the channels alpha, red, green and blue /// ARGB32, /// /// 3 bytes per pixel with the channels blue, green and red /// BGR24, /// /// 4 bytes per pixel with the channels blue, green and red /// BGR32, /// /// 4 bytes per pixel with the channels blue, green, red and alpha /// BGRA32, /// /// 2 bytes per pixel, 5 bit red, 6 bits green and 5 bits blue /// RGB565, /// /// 4 bytes per pixel with the channels red, green, blue and alpha /// RGBA32, } /// /// Initializes a new instance of the class. /// /// The width. /// The height. protected RGBLuminanceSource(int width, int height) : base(width, height) { } /// /// Initializes a new instance of the class. /// It supports a byte array with 3 bytes per pixel (RGB24). /// /// The RGB raw bytes. /// The width. /// The height. public RGBLuminanceSource(byte[] rgbRawBytes, int width, int height) : this(rgbRawBytes, width, height, BitmapFormat.RGB24) { } /// /// Initializes a new instance of the class. /// It supports a byte array with 1 byte per pixel (Gray8). /// That means the whole array consists of the luminance values (grayscale). /// /// The luminance array. /// The width. /// The height. /// if set to true [is8 bit]. [Obsolete("Use RGBLuminanceSource(luminanceArray, width, height, BitmapFormat.Gray8)")] public RGBLuminanceSource(byte[] luminanceArray, int width, int height, bool is8Bit) : this(luminanceArray, width, height, BitmapFormat.Gray8) { } /// /// Initializes a new instance of the class. /// It supports a byte array with 3 bytes per pixel (RGB24). /// /// The RGB raw bytes. /// The width. /// The height. /// The bitmap format. public RGBLuminanceSource(byte[] rgbRawBytes, int width, int height, BitmapFormat bitmapFormat) : base(width, height) { CalculateLuminance(rgbRawBytes, bitmapFormat); } /// /// Should create a new luminance source with the right class type. /// The method is used in methods crop and rotate. /// /// The new luminances. /// The width. /// The height. /// protected override LuminanceSource CreateLuminanceSource(byte[] newLuminances, int width, int height) { return new RGBLuminanceSource(width, height) { luminances = newLuminances }; } private static BitmapFormat DetermineBitmapFormat(byte[] rgbRawBytes, int width, int height) { var square = width*height; var byteperpixel = rgbRawBytes.Length/square; switch (byteperpixel) { case 1: return BitmapFormat.Gray8; case 2: return BitmapFormat.RGB565; case 3: return BitmapFormat.RGB24; case 4: return BitmapFormat.RGB32; default: throw new ArgumentException("The bitmap format could not be determined. Please specify the correct value."); } } protected void CalculateLuminance(byte[] rgbRawBytes, BitmapFormat bitmapFormat) { if (bitmapFormat == BitmapFormat.Unknown) { bitmapFormat = DetermineBitmapFormat(rgbRawBytes, Width, Height); } switch (bitmapFormat) { case BitmapFormat.Gray8: Buffer.BlockCopy(rgbRawBytes, 0, luminances, 0, rgbRawBytes.Length < luminances.Length ? rgbRawBytes.Length : luminances.Length); break; case BitmapFormat.RGB24: CalculateLuminanceRGB24(rgbRawBytes); break; case BitmapFormat.BGR24: CalculateLuminanceBGR24(rgbRawBytes); break; case BitmapFormat.RGB32: CalculateLuminanceRGB32(rgbRawBytes); break; case BitmapFormat.BGR32: CalculateLuminanceBGR32(rgbRawBytes); break; case BitmapFormat.RGBA32: CalculateLuminanceRGBA32(rgbRawBytes); break; case BitmapFormat.ARGB32: CalculateLuminanceARGB32(rgbRawBytes); break; case BitmapFormat.BGRA32: CalculateLuminanceBGRA32(rgbRawBytes); break; case BitmapFormat.RGB565: CalculateLuminanceRGB565(rgbRawBytes); break; default: throw new ArgumentException("The bitmap format isn't supported.", bitmapFormat.ToString()); } } private void CalculateLuminanceRGB565(byte[] rgb565RawData) { var luminanceIndex = 0; for (var index = 0; index < rgb565RawData.Length && luminanceIndex < luminances.Length; index += 2, luminanceIndex++) { var byte1 = rgb565RawData[index]; var byte2 = rgb565RawData[index + 1]; var b5 = byte1 & 0x1F; var g5 = (((byte1 & 0xE0) >> 5) | ((byte2 & 0x03) << 3)) & 0x1F; var r5 = (byte2 >> 2) & 0x1F; var r8 = (r5 * 527 + 23) >> 6; var g8 = (g5 * 527 + 23) >> 6; var b8 = (b5 * 527 + 23) >> 6; // cheap, not fully accurate conversion //var pixel = (byte2 << 8) | byte1; //b8 = (((pixel) & 0x001F) << 3); //g8 = (((pixel) & 0x07E0) >> 2) & 0xFF; //r8 = (((pixel) & 0xF800) >> 8); luminances[luminanceIndex] = (byte)((RChannelWeight * r8 + GChannelWeight * g8 + BChannelWeight * b8) >> ChannelWeight); } } private void CalculateLuminanceRGB24(byte[] rgbRawBytes) { for (int rgbIndex = 0, luminanceIndex = 0; rgbIndex < rgbRawBytes.Length && luminanceIndex < luminances.Length; luminanceIndex++) { // Calculate luminance cheaply, favoring green. int r = rgbRawBytes[rgbIndex++]; int g = rgbRawBytes[rgbIndex++]; int b = rgbRawBytes[rgbIndex++]; luminances[luminanceIndex] = (byte)((RChannelWeight * r + GChannelWeight * g + BChannelWeight * b) >> ChannelWeight); } } private void CalculateLuminanceBGR24(byte[] rgbRawBytes) { for (int rgbIndex = 0, luminanceIndex = 0; rgbIndex < rgbRawBytes.Length && luminanceIndex < luminances.Length; luminanceIndex++) { // Calculate luminance cheaply, favoring green. int b = rgbRawBytes[rgbIndex++]; int g = rgbRawBytes[rgbIndex++]; int r = rgbRawBytes[rgbIndex++]; luminances[luminanceIndex] = (byte)((RChannelWeight * r + GChannelWeight * g + BChannelWeight * b) >> ChannelWeight); } } private void CalculateLuminanceRGB32(byte[] rgbRawBytes) { for (int rgbIndex = 0, luminanceIndex = 0; rgbIndex < rgbRawBytes.Length && luminanceIndex < luminances.Length; luminanceIndex++) { // Calculate luminance cheaply, favoring green. int r = rgbRawBytes[rgbIndex++]; int g = rgbRawBytes[rgbIndex++]; int b = rgbRawBytes[rgbIndex++]; rgbIndex++; luminances[luminanceIndex] = (byte)((RChannelWeight * r + GChannelWeight * g + BChannelWeight * b) >> ChannelWeight); } } private void CalculateLuminanceBGR32(byte[] rgbRawBytes) { for (int rgbIndex = 0, luminanceIndex = 0; rgbIndex < rgbRawBytes.Length && luminanceIndex < luminances.Length; luminanceIndex++) { // Calculate luminance cheaply, favoring green. int b = rgbRawBytes[rgbIndex++]; int g = rgbRawBytes[rgbIndex++]; int r = rgbRawBytes[rgbIndex++]; rgbIndex++; luminances[luminanceIndex] = (byte)((RChannelWeight * r + GChannelWeight * g + BChannelWeight * b) >> ChannelWeight); } } private void CalculateLuminanceBGRA32(byte[] rgbRawBytes) { for (int rgbIndex = 0, luminanceIndex = 0; rgbIndex < rgbRawBytes.Length && luminanceIndex < luminances.Length; luminanceIndex++) { // Calculate luminance cheaply, favoring green. var b = rgbRawBytes[rgbIndex++]; var g = rgbRawBytes[rgbIndex++]; var r = rgbRawBytes[rgbIndex++]; var alpha = rgbRawBytes[rgbIndex++]; var luminance = (byte)((RChannelWeight * r + GChannelWeight * g + BChannelWeight * b) >> ChannelWeight); luminances[luminanceIndex] = (byte)(((luminance * alpha) >> 8) + (255 * (255 - alpha) >> 8)); } } private void CalculateLuminanceRGBA32(byte[] rgbRawBytes) { for (int rgbIndex = 0, luminanceIndex = 0; rgbIndex < rgbRawBytes.Length && luminanceIndex < luminances.Length; luminanceIndex++) { // Calculate luminance cheaply, favoring green. var r = rgbRawBytes[rgbIndex++]; var g = rgbRawBytes[rgbIndex++]; var b = rgbRawBytes[rgbIndex++]; var alpha = rgbRawBytes[rgbIndex++]; var luminance = (byte)((RChannelWeight * r + GChannelWeight * g + BChannelWeight * b) >> ChannelWeight); luminances[luminanceIndex] = (byte)(((luminance * alpha) >> 8) + (255 * (255 - alpha) >> 8)); } } private void CalculateLuminanceARGB32(byte[] rgbRawBytes) { for (int rgbIndex = 0, luminanceIndex = 0; rgbIndex < rgbRawBytes.Length && luminanceIndex < luminances.Length; luminanceIndex++) { // Calculate luminance cheaply, favoring green. var alpha = rgbRawBytes[rgbIndex++]; var r = rgbRawBytes[rgbIndex++]; var g = rgbRawBytes[rgbIndex++]; var b = rgbRawBytes[rgbIndex++]; var luminance = (byte)((RChannelWeight * r + GChannelWeight * g + BChannelWeight * b) >> ChannelWeight); luminances[luminanceIndex] = (byte)(((luminance * alpha) >> 8) + (255 * (255 - alpha) >> 8)); } } } }