| // Copyright 2020 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "services/shape_detection/barcode_detection_impl_barhopper.h" |
| |
| #include <stdint.h> |
| #include <limits> |
| #include <memory> |
| |
| #include "base/logging.h" |
| #include "services/shape_detection/public/mojom/barcodedetection.mojom-shared.h" |
| #include "third_party/barhopper/barhopper/barcode.h" |
| #include "third_party/skia/include/core/SkColor.h" |
| #include "ui/gfx/geometry/rect_f.h" |
| |
| namespace shape_detection { |
| |
| namespace { |
| |
| gfx::RectF CornerPointsToBoundingBox( |
| std::vector<barhopper::Point>& corner_points) { |
| float xmin = std::numeric_limits<float>::infinity(); |
| float ymin = std::numeric_limits<float>::infinity(); |
| float xmax = -std::numeric_limits<float>::infinity(); |
| float ymax = -std::numeric_limits<float>::infinity(); |
| for (auto& point : corner_points) { |
| xmin = std::min(xmin, point.x); |
| ymin = std::min(ymin, point.y); |
| xmax = std::max(xmax, point.x); |
| ymax = std::max(ymax, point.y); |
| } |
| return gfx::RectF(xmin, ymin, (xmax - xmin), (ymax - ymin)); |
| } |
| |
| mojom::BarcodeFormat BarhopperFormatToMojo(barhopper::BarcodeFormat format) { |
| switch (format) { |
| case barhopper::BarcodeFormat::AZTEC: |
| return mojom::BarcodeFormat::AZTEC; |
| case barhopper::BarcodeFormat::CODE_128: |
| return mojom::BarcodeFormat::CODE_128; |
| case barhopper::BarcodeFormat::CODE_39: |
| return mojom::BarcodeFormat::CODE_39; |
| case barhopper::BarcodeFormat::CODE_93: |
| return mojom::BarcodeFormat::CODE_93; |
| case barhopper::BarcodeFormat::CODABAR: |
| return mojom::BarcodeFormat::CODABAR; |
| case barhopper::BarcodeFormat::DATA_MATRIX: |
| return mojom::BarcodeFormat::DATA_MATRIX; |
| case barhopper::BarcodeFormat::EAN_13: |
| return mojom::BarcodeFormat::EAN_13; |
| case barhopper::BarcodeFormat::EAN_8: |
| return mojom::BarcodeFormat::EAN_8; |
| case barhopper::BarcodeFormat::ITF: |
| return mojom::BarcodeFormat::ITF; |
| case barhopper::BarcodeFormat::PDF417: |
| return mojom::BarcodeFormat::PDF417; |
| case barhopper::BarcodeFormat::QR_CODE: |
| return mojom::BarcodeFormat::QR_CODE; |
| case barhopper::BarcodeFormat::UPC_A: |
| return mojom::BarcodeFormat::UPC_A; |
| case barhopper::BarcodeFormat::UPC_E: |
| return mojom::BarcodeFormat::UPC_E; |
| case barhopper::BarcodeFormat::UNRECOGNIZED: |
| return mojom::BarcodeFormat::UNKNOWN; |
| default: |
| NOTREACHED() << "Invalid barcode format"; |
| return mojom::BarcodeFormat::UNKNOWN; |
| } |
| } |
| |
| barhopper::RecognitionOptions GetRecognitionOptions( |
| const shape_detection::mojom::BarcodeDetectorOptionsPtr& options) { |
| barhopper::RecognitionOptions recognition_options; |
| if (options->formats.empty()) { |
| recognition_options.barcode_formats = |
| barhopper::BarcodeFormat::AZTEC | barhopper::BarcodeFormat::CODE_128 | |
| barhopper::BarcodeFormat::CODE_39 | barhopper::BarcodeFormat::CODE_93 | |
| barhopper::BarcodeFormat::CODABAR | |
| barhopper::BarcodeFormat::DATA_MATRIX | |
| barhopper::BarcodeFormat::EAN_13 | barhopper::BarcodeFormat::EAN_8 | |
| barhopper::BarcodeFormat::ITF | barhopper::BarcodeFormat::PDF417 | |
| barhopper::BarcodeFormat::QR_CODE | barhopper::BarcodeFormat::UPC_A | |
| barhopper::BarcodeFormat::UPC_E; |
| return recognition_options; |
| } |
| |
| int recognition_formats = 0; |
| for (const auto& format : options->formats) { |
| switch (format) { |
| case mojom::BarcodeFormat::AZTEC: |
| recognition_formats |= barhopper::BarcodeFormat::AZTEC; |
| break; |
| case mojom::BarcodeFormat::CODE_128: |
| recognition_formats |= barhopper::BarcodeFormat::CODE_128; |
| break; |
| case mojom::BarcodeFormat::CODE_39: |
| recognition_formats |= barhopper::BarcodeFormat::CODE_39; |
| break; |
| case mojom::BarcodeFormat::CODE_93: |
| recognition_formats |= barhopper::BarcodeFormat::CODE_93; |
| break; |
| case mojom::BarcodeFormat::CODABAR: |
| recognition_formats |= barhopper::BarcodeFormat::CODABAR; |
| break; |
| case mojom::BarcodeFormat::DATA_MATRIX: |
| recognition_formats |= barhopper::BarcodeFormat::DATA_MATRIX; |
| break; |
| case mojom::BarcodeFormat::EAN_13: |
| recognition_formats |= barhopper::BarcodeFormat::EAN_13; |
| break; |
| case mojom::BarcodeFormat::EAN_8: |
| recognition_formats |= barhopper::BarcodeFormat::EAN_8; |
| break; |
| case mojom::BarcodeFormat::ITF: |
| recognition_formats |= barhopper::BarcodeFormat::ITF; |
| break; |
| case mojom::BarcodeFormat::PDF417: |
| recognition_formats |= barhopper::BarcodeFormat::PDF417; |
| break; |
| case mojom::BarcodeFormat::QR_CODE: |
| recognition_formats |= barhopper::BarcodeFormat::QR_CODE; |
| break; |
| case mojom::BarcodeFormat::UPC_E: |
| recognition_formats |= barhopper::BarcodeFormat::UPC_E; |
| break; |
| case mojom::BarcodeFormat::UPC_A: |
| recognition_formats |= barhopper::BarcodeFormat::UPC_A; |
| break; |
| case mojom::BarcodeFormat::UNKNOWN: |
| recognition_formats |= barhopper::BarcodeFormat::UNRECOGNIZED; |
| break; |
| } |
| } |
| recognition_options.barcode_formats = recognition_formats; |
| return recognition_options; |
| } |
| |
| } // namespace |
| |
| BarcodeDetectionImplBarhopper::BarcodeDetectionImplBarhopper( |
| mojom::BarcodeDetectorOptionsPtr options) |
| : recognition_options_(GetRecognitionOptions(options)) {} |
| |
| BarcodeDetectionImplBarhopper::~BarcodeDetectionImplBarhopper() = default; |
| |
| void BarcodeDetectionImplBarhopper::Detect( |
| const SkBitmap& bitmap, |
| shape_detection::mojom::BarcodeDetection::DetectCallback callback) { |
| int width = bitmap.width(); |
| int height = bitmap.height(); |
| auto luminances = std::make_unique<uint8_t[]>(height * width); |
| uint8_t* luminances_ptr = luminances.get(); |
| for (int y = 0; y < height; y++) { |
| for (int x = 0; x < width; x++) { |
| SkColor color = bitmap.getColor(x, y); |
| // Fast and approximate luminance calculation: (2*R + 5*G + B) / 8 |
| uint32_t luminance = |
| 2 * SkColorGetR(color) + 5 * SkColorGetG(color) + SkColorGetB(color); |
| luminances_ptr[y * width + x] = luminance / 8; |
| } |
| } |
| std::vector<barhopper::Barcode> barcodes; |
| barhopper::Barhopper::Recognize(width, height, luminances_ptr, |
| recognition_options_, &barcodes); |
| |
| std::vector<mojom::BarcodeDetectionResultPtr> results; |
| for (auto& barcode : barcodes) { |
| auto result = shape_detection::mojom::BarcodeDetectionResult::New(); |
| result->bounding_box = CornerPointsToBoundingBox(barcode.corner_point); |
| for (auto& corner_point : barcode.corner_point) { |
| result->corner_points.emplace_back(corner_point.x, corner_point.y); |
| } |
| result->raw_value = barcode.raw_value; |
| result->format = BarhopperFormatToMojo(barcode.format); |
| results.push_back(std::move(result)); |
| } |
| std::move(callback).Run(std::move(results)); |
| } |
| |
| // static |
| std::vector<mojom::BarcodeFormat> |
| BarcodeDetectionImplBarhopper::GetSupportedFormats() { |
| return {mojom::BarcodeFormat::AZTEC, mojom::BarcodeFormat::CODE_128, |
| mojom::BarcodeFormat::CODE_39, mojom::BarcodeFormat::CODE_93, |
| mojom::BarcodeFormat::CODABAR, mojom::BarcodeFormat::DATA_MATRIX, |
| mojom::BarcodeFormat::EAN_13, mojom::BarcodeFormat::EAN_8, |
| mojom::BarcodeFormat::ITF, mojom::BarcodeFormat::PDF417, |
| mojom::BarcodeFormat::QR_CODE, mojom::BarcodeFormat::UPC_A, |
| mojom::BarcodeFormat::UPC_E}; |
| } |
| |
| } // namespace shape_detection |