// -*- mode:objc; c-basic-offset:2; indent-tabs-mode:nil -*- /* * Copyright 2011 ZXing authors All rights reserved. * * 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. */ #include #include namespace zxing { CGImageRef CGImageLuminanceSource::createImageFromBuffer (CVPixelBufferRef buffer, int left, int top, int width, int height) { int bytesPerRow = CVPixelBufferGetBytesPerRow(buffer); int dataWidth = CVPixelBufferGetWidth(buffer); int dataHeight = CVPixelBufferGetHeight(buffer); if (left + width > dataWidth || top + height > dataHeight || top < 0 || left < 0) { throw IllegalArgumentException("Crop rectangle does not fit within image data."); } int newBytesPerRow = ((width*4+0xf)>>4)<<4; CVPixelBufferLockBaseAddress(buffer,0); unsigned char* baseAddress = (unsigned char*)CVPixelBufferGetBaseAddress(buffer); int size = newBytesPerRow*height; unsigned char* bytes = (unsigned char*)malloc(size); if (newBytesPerRow == bytesPerRow) { memcpy(bytes, baseAddress+top*bytesPerRow, size); } else { for(int y=0; y dataWidth_ || top_ + height_ > dataHeight_ || top_ < 0 || left_ < 0) { throw IllegalArgumentException ("Crop rectangle does not fit within image data."); } CGColorSpaceRef space = CGImageGetColorSpace(image_); CGColorSpaceModel model = CGColorSpaceGetModel(space); if (model != kCGColorSpaceModelMonochrome || CGImageGetBitsPerComponent(image_) != 8 || CGImageGetBitsPerPixel(image_) != 8) { CGColorSpaceRef gray = CGColorSpaceCreateDeviceGray(); CGContextRef ctx = CGBitmapContextCreate(0, width, height, 8, width, gray, kCGImageAlphaNone); CGColorSpaceRelease(gray); if (top || left) { CGContextClipToRect(ctx, CGRectMake(0, 0, width, height)); } CGContextDrawImage(ctx, CGRectMake(-left, -top, width, height), image_); image_ = CGBitmapContextCreateImage(ctx); bytesPerRow_ = width; top_ = 0; left_ = 0; dataWidth_ = width; dataHeight_ = height; CGContextRelease(ctx); } else { CGImageRetain(image_); } CGDataProviderRef provider = CGImageGetDataProvider(image_); data_ = CGDataProviderCopyData(provider); } CGImageLuminanceSource::~CGImageLuminanceSource() { if (image_) { CGImageRelease(image_); } if (data_) { CFRelease(data_); } } unsigned char* CGImageLuminanceSource::getRow(int y, unsigned char* row) { if (y < 0 || y >= this->getHeight()) { throw IllegalArgumentException("Requested row is outside the image: " + y); } int width = getWidth(); // TODO(flyashi): determine if row has enough size. if (row == NULL) { row = new unsigned char[width_]; } int offset = (y + top_) * dataWidth_ + left_; CFDataGetBytes(data_, CFRangeMake(offset, width), row); return row; } unsigned char* CGImageLuminanceSource::getMatrix() { int size = width_ * height_; unsigned char* result = new unsigned char[size]; if (left_ == 0 && top_ == 0 && dataWidth_ == width_ && dataHeight_ == height_) { CFDataGetBytes(data_, CFRangeMake(0, size), result); } else { for (int row = 0; row < height_; row++) { CFDataGetBytes(data_, CFRangeMake((top_ + row) * dataWidth_ + left_, width_), result + row * width_); } } return result; } Ref CGImageLuminanceSource::rotateCounterClockwise() { return Ref(0); } }