blob: aa48a27bc5a6447b366f1d257fbd19a277797fb2 [file] [log] [blame]
// Copyright 2020 The Chromium Authors. All rights reserved.
// 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