/* * Copyright 2010-2011 ZXing 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. */ #include "ImageReaderSource.h" #include #include #include #include #include #include "lodepng.h" #include "jpgd.h" using std::string; using std::ostringstream; using zxing::Ref; using zxing::ArrayRef; using zxing::LuminanceSource; inline char ImageReaderSource::convertPixel(char const* pixel_) const { unsigned char const* pixel = (unsigned char const*)pixel_; if (comps == 1 || comps == 2) { // Gray or gray+alpha return pixel[0]; } if (comps == 3 || comps == 4) { // Red, Green, Blue, (Alpha) // We assume 16 bit values here // 0x200 = 1<<9, half an lsb of the result to force rounding return (char)((306 * (int)pixel[0] + 601 * (int)pixel[1] + 117 * (int)pixel[2] + 0x200) >> 10); } else { throw zxing::IllegalArgumentException("Unexpected image depth"); } } ImageReaderSource::ImageReaderSource(ArrayRef image_, int width, int height, int comps_) : Super(width, height), image(image_), comps(comps_) {} Ref ImageReaderSource::create(string const& filename) { string extension = filename.substr(filename.find_last_of(".") + 1); std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower); int width, height; int comps = 0; zxing::ArrayRef image; if (extension == "png") { std::vector out; { unsigned w, h; unsigned error = lodepng::decode(out, w, h, filename); if (error) { ostringstream msg; msg << "Error while loading '" << lodepng_error_text(error) << "'"; throw zxing::IllegalArgumentException(msg.str().c_str()); } width = w; height = h; } comps = 4; image = zxing::ArrayRef(4 * width * height); memcpy(&image[0], &out[0], image->size()); } else if (extension == "jpg" || extension == "jpeg") { char *buffer = reinterpret_cast(jpgd::decompress_jpeg_image_from_file( filename.c_str(), &width, &height, &comps, 4)); image = zxing::ArrayRef(buffer, 4 * width * height); } if (!image) { ostringstream msg; msg << "Loading \"" << filename << "\" failed."; throw zxing::IllegalArgumentException(msg.str().c_str()); } return Ref(new ImageReaderSource(image, width, height, comps)); } zxing::ArrayRef ImageReaderSource::getRow(int y, zxing::ArrayRef row) const { const char* pixelRow = &image[0] + y * getWidth() * 4; if (!row) { row = zxing::ArrayRef(getWidth()); } for (int x = 0; x < getWidth(); x++) { row[x] = convertPixel(pixelRow + (x * 4)); } return row; } /** This is a more efficient implementation. */ zxing::ArrayRef ImageReaderSource::getMatrix() const { const char* p = &image[0]; zxing::ArrayRef matrix(getWidth() * getHeight()); char* m = &matrix[0]; for (int y = 0; y < getHeight(); y++) { for (int x = 0; x < getWidth(); x++) { *m = convertPixel(p); m++; p += 4; } } return matrix; }