/* * 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 { /// /// The base class for luminance sources which supports /// cropping and rotating based upon the luminance values. /// public abstract class BaseLuminanceSource : LuminanceSource { // the following channel weights give nearly the same // gray scale picture as the java version with BufferedImage.TYPE_BYTE_GRAY // they are used in sub classes for luminance / gray scale calculation protected const int RChannelWeight = 19562; protected const int GChannelWeight = 38550; protected const int BChannelWeight = 7424; protected const int ChannelWeight = 16; /// /// /// protected byte[] luminances; /// /// Initializes a new instance of the class. /// /// The width. /// The height. protected BaseLuminanceSource(int width, int height) : base(width, height) { luminances = new byte[width * height]; } /// /// Initializes a new instance of the class. /// /// The luminance array. /// The width. /// The height. protected BaseLuminanceSource(byte[] luminanceArray, int width, int height) : base(width, height) { luminances = new byte[width * height]; Buffer.BlockCopy(luminanceArray, 0, luminances, 0, width * height); } /// /// Fetches one row of luminance data from the underlying platform's bitmap. Values range from /// 0 (black) to 255 (white). It is preferable for implementations of this method /// to only fetch this row rather than the whole image, since no 2D Readers may be installed and /// getMatrix() may never be called. /// /// The row to fetch, 0 <= y < Height. /// An optional preallocated array. If null or too small, it will be ignored. /// Always use the returned object, and ignore the .length of the array. /// /// An array containing the luminance data. /// override public byte[] getRow(int y, byte[] row) { int width = Width; if (row == null || row.Length < width) { row = new byte[width]; } for (int i = 0; i < width; i++) row[i] = luminances[y * width + i]; return row; } public override byte[] Matrix { get { return luminances; } } /// /// Returns a new object with rotated image data by 90 degrees counterclockwise. /// Only callable if {@link #isRotateSupported()} is true. /// /// /// A rotated version of this object. /// public override LuminanceSource rotateCounterClockwise() { var rotatedLuminances = new byte[Width * Height]; var newWidth = Height; var newHeight = Width; var localLuminances = Matrix; for (var yold = 0; yold < Height; yold++) { for (var xold = 0; xold < Width; xold++) { var ynew = newHeight - xold - 1; var xnew = yold; rotatedLuminances[ynew * newWidth + xnew] = localLuminances[yold * Width + xold]; } } return CreateLuminanceSource(rotatedLuminances, newWidth, newHeight); } /// /// TODO: not implemented yet /// /// /// A rotated version of this object. /// public override LuminanceSource rotateCounterClockwise45() { // TODO: implement a good 45 degrees rotation without lost of information return base.rotateCounterClockwise45(); } /// /// /// Whether this subclass supports counter-clockwise rotation. public override bool RotateSupported { get { return true; } } /// /// Returns a new object with cropped image data. Implementations may keep a reference to the /// original data rather than a copy. Only callable if CropSupported is true. /// /// The left coordinate, 0 <= left < Width. /// The top coordinate, 0 <= top <= Height. /// The width of the rectangle to crop. /// The height of the rectangle to crop. /// /// A cropped version of this object. /// public override LuminanceSource crop(int left, int top, int width, int height) { if (left + width > Width || top + height > Height) { throw new ArgumentException("Crop rectangle does not fit within image data."); } var croppedLuminances = new byte[width * height]; var oldLuminances = Matrix; var oldWidth = Width; var oldRightBound = left + width; var oldBottomBound = top + height; for (int yold = top, ynew = 0; yold < oldBottomBound; yold++, ynew++) { for (int xold = left, xnew = 0; xold < oldRightBound; xold++, xnew++) { croppedLuminances[ynew * width + xnew] = oldLuminances[yold * oldWidth + xold]; } } return CreateLuminanceSource(croppedLuminances, width, height); } /// /// /// Whether this subclass supports cropping. public override bool CropSupported { get { return true; } } /// /// /// Whether this subclass supports invertion. public override bool InversionSupported { get { return true; } } /// /// 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 abstract LuminanceSource CreateLuminanceSource(byte[] newLuminances, int width, int height); } }