Use geometry classes in pdfium_searchify code
Now that the pdfium_searchify code uses floats and not doubles, it can start using geometry classes like gfx::PointF and gfx::SizeF. Make the switch and reduce the number of parameters / variables. Change-Id: Ie078e477644e59c3a9ff6d59d04be9edadd1b723 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5693626 Commit-Queue: Lei Zhang <thestig@chromium.org> Reviewed-by: Chu-Hsuan Yang <chuhsuan@chromium.org> Code-Coverage: findit-for-me@appspot.gserviceaccount.com <findit-for-me@appspot.gserviceaccount.com> Cr-Commit-Position: refs/heads/main@{#1326883}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
052877a696
commit
3cf9e6483d
@ -32,6 +32,10 @@
|
||||
#include "third_party/skia/include/core/SkImageInfo.h"
|
||||
#include "third_party/skia/include/core/SkPixmap.h"
|
||||
#include "ui/gfx/codec/jpeg_codec.h"
|
||||
#include "ui/gfx/geometry/point_f.h"
|
||||
#include "ui/gfx/geometry/rect.h"
|
||||
#include "ui/gfx/geometry/size.h"
|
||||
#include "ui/gfx/geometry/size_f.h"
|
||||
|
||||
namespace chrome_pdf {
|
||||
|
||||
@ -49,15 +53,14 @@ std::vector<uint32_t> Utf8ToCharcodes(const std::string& string) {
|
||||
|
||||
// The coordinate systems between OCR and PDF are different. OCR's origin is at
|
||||
// top-left, so we need to convert them to PDF's bottom-left.
|
||||
SearchifyBoundingBoxOrigin ConvertToPdfOrigin(int x,
|
||||
int y,
|
||||
int height,
|
||||
SearchifyBoundingBoxOrigin ConvertToPdfOrigin(const gfx::Rect& rect,
|
||||
float angle,
|
||||
float coordinate_system_height) {
|
||||
const float theta = base::DegToRad(angle);
|
||||
return {.x = x - (sinf(theta) * height),
|
||||
.y = coordinate_system_height - (y + cosf(theta) * height),
|
||||
.theta = -theta};
|
||||
const float x = rect.x() - (sinf(theta) * rect.height());
|
||||
const float y =
|
||||
coordinate_system_height - (rect.y() + cosf(theta) * rect.height());
|
||||
return {.point = {x, y}, .theta = -theta};
|
||||
}
|
||||
|
||||
// Project the text object's origin to the baseline's origin.
|
||||
@ -65,10 +68,14 @@ SearchifyBoundingBoxOrigin ProjectToBaseline(
|
||||
const SearchifyBoundingBoxOrigin& origin,
|
||||
const SearchifyBoundingBoxOrigin& baseline_origin) {
|
||||
// The length between `origin` and `baseline_origin`.
|
||||
float length = (origin.x - baseline_origin.x) * cosf(baseline_origin.theta) +
|
||||
(origin.y - baseline_origin.y) * sinf(baseline_origin.theta);
|
||||
return {.x = baseline_origin.x + length * cosf(baseline_origin.theta),
|
||||
.y = baseline_origin.y + length * sinf(baseline_origin.theta),
|
||||
const float length = (origin.point.x() - baseline_origin.point.x()) *
|
||||
cosf(baseline_origin.theta) +
|
||||
(origin.point.y() - baseline_origin.point.y()) *
|
||||
sinf(baseline_origin.theta);
|
||||
return {.point = {baseline_origin.point.x() +
|
||||
length * cosf(baseline_origin.theta),
|
||||
baseline_origin.point.y() +
|
||||
length * sinf(baseline_origin.theta)},
|
||||
.theta = baseline_origin.theta};
|
||||
}
|
||||
|
||||
@ -83,10 +90,9 @@ void AddTextOnImage(FPDF_DOCUMENT document,
|
||||
return;
|
||||
}
|
||||
|
||||
float image_rendered_width =
|
||||
hypotf(quadpoints.x1 - quadpoints.x2, quadpoints.y1 - quadpoints.y2);
|
||||
float image_rendered_height =
|
||||
hypotf(quadpoints.x2 - quadpoints.x3, quadpoints.y2 - quadpoints.y3);
|
||||
const gfx::SizeF image_rendered_size(
|
||||
hypotf(quadpoints.x1 - quadpoints.x2, quadpoints.y1 - quadpoints.y2),
|
||||
hypotf(quadpoints.x2 - quadpoints.x3, quadpoints.y2 - quadpoints.y3));
|
||||
unsigned int image_pixel_width;
|
||||
unsigned int image_pixel_height;
|
||||
if (!FPDFImageObj_GetImagePixelSize(image, &image_pixel_width,
|
||||
@ -94,6 +100,8 @@ void AddTextOnImage(FPDF_DOCUMENT document,
|
||||
DLOG(ERROR) << "Failed to get image dimensions";
|
||||
return;
|
||||
}
|
||||
const gfx::Size image_pixel_size(image_pixel_width, image_pixel_height);
|
||||
|
||||
FS_MATRIX image_matrix;
|
||||
if (!FPDFPageObj_GetMatrix(image, &image_matrix)) {
|
||||
DLOG(ERROR) << "Failed to get image matrix";
|
||||
@ -102,20 +110,16 @@ void AddTextOnImage(FPDF_DOCUMENT document,
|
||||
|
||||
for (const auto& line : annotation->lines) {
|
||||
SearchifyBoundingBoxOrigin baseline_origin =
|
||||
ConvertToPdfOrigin(line->baseline_box.x(), line->baseline_box.y(),
|
||||
line->baseline_box.height(),
|
||||
line->baseline_box_angle, image_rendered_height);
|
||||
ConvertToPdfOrigin(line->baseline_box, line->baseline_box_angle,
|
||||
image_rendered_size.height());
|
||||
|
||||
for (const auto& word : line->words) {
|
||||
float width = word->bounding_box.width();
|
||||
float height = word->bounding_box.height();
|
||||
|
||||
if (width == 0 || height == 0) {
|
||||
if (word->bounding_box.IsEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ScopedFPDFPageObject text(
|
||||
FPDFPageObj_CreateTextObj(document, font, height));
|
||||
ScopedFPDFPageObject text(FPDFPageObj_CreateTextObj(
|
||||
document, font, word->bounding_box.height()));
|
||||
CHECK(text);
|
||||
|
||||
std::string word_string = word->word;
|
||||
@ -149,48 +153,50 @@ void AddTextOnImage(FPDF_DOCUMENT document,
|
||||
float right;
|
||||
float top;
|
||||
if (!FPDFPageObj_GetBounds(text.get(), &left, &bottom, &right, &top)) {
|
||||
DLOG(ERROR) << "Failed to get the bounding box of original text object";
|
||||
DLOG(ERROR) << "Failed to get the bounding box of text object";
|
||||
continue;
|
||||
}
|
||||
float original_text_object_width = right - left;
|
||||
float original_text_object_height = top - bottom;
|
||||
CHECK_GT(original_text_object_width, 0);
|
||||
CHECK_GT(original_text_object_height, 0);
|
||||
float width_scale = width / original_text_object_width;
|
||||
float height_scale = height / original_text_object_height;
|
||||
|
||||
const gfx::SizeF text_object_size(right - left, top - bottom);
|
||||
CHECK_GT(text_object_size.width(), 0);
|
||||
CHECK_GT(text_object_size.height(), 0);
|
||||
float width_scale = word->bounding_box.width() / text_object_size.width();
|
||||
float height_scale =
|
||||
word->bounding_box.height() / text_object_size.height();
|
||||
FPDFPageObj_Transform(text.get(), width_scale, 0, 0, height_scale, 0, 0);
|
||||
|
||||
// Move text object to the corresponding text position on the full image.
|
||||
SearchifyBoundingBoxOrigin origin = ConvertToPdfOrigin(
|
||||
word->bounding_box.x(), word->bounding_box.y(), height,
|
||||
word->bounding_box_angle, image_rendered_height);
|
||||
SearchifyBoundingBoxOrigin origin =
|
||||
ConvertToPdfOrigin(word->bounding_box, word->bounding_box_angle,
|
||||
image_rendered_size.height());
|
||||
origin = ProjectToBaseline(origin, baseline_origin);
|
||||
float a = cosf(origin.theta);
|
||||
float b = sinf(origin.theta);
|
||||
float c = -sinf(origin.theta);
|
||||
float d = cosf(origin.theta);
|
||||
float e = origin.x;
|
||||
float f = origin.y;
|
||||
float e = origin.point.x();
|
||||
float f = origin.point.y();
|
||||
if (word->direction ==
|
||||
screen_ai::mojom::Direction::DIRECTION_RIGHT_TO_LEFT) {
|
||||
a = -a;
|
||||
b = -b;
|
||||
e += cosf(origin.theta) * width;
|
||||
f += sinf(origin.theta) * width;
|
||||
e += cosf(origin.theta) * word->bounding_box.width();
|
||||
f += sinf(origin.theta) * word->bounding_box.width();
|
||||
}
|
||||
FPDFPageObj_Transform(text.get(), a, b, c, d, e, f);
|
||||
|
||||
// Scale from full image size to rendered image size on the PDF.
|
||||
FPDFPageObj_Transform(text.get(),
|
||||
image_rendered_width / image_pixel_width, 0, 0,
|
||||
image_rendered_height / image_pixel_height, 0, 0);
|
||||
FPDFPageObj_Transform(
|
||||
text.get(), image_rendered_size.width() / image_pixel_size.width(), 0,
|
||||
0, image_rendered_size.height() / image_pixel_size.height(), 0, 0);
|
||||
|
||||
// Apply the image's transformation matrix on the PDF page without the
|
||||
// scaling matrix.
|
||||
FPDFPageObj_Transform(text.get(), image_matrix.a / image_rendered_width,
|
||||
image_matrix.b / image_rendered_width,
|
||||
image_matrix.c / image_rendered_height,
|
||||
image_matrix.d / image_rendered_height,
|
||||
FPDFPageObj_Transform(text.get(),
|
||||
image_matrix.a / image_rendered_size.width(),
|
||||
image_matrix.b / image_rendered_size.width(),
|
||||
image_matrix.c / image_rendered_size.height(),
|
||||
image_matrix.d / image_rendered_size.height(),
|
||||
image_matrix.e, image_matrix.f);
|
||||
|
||||
FPDFPage_InsertObject(page, text.release());
|
||||
@ -275,12 +281,10 @@ std::vector<uint8_t> PDFiumSearchify(
|
||||
}
|
||||
|
||||
SearchifyBoundingBoxOrigin ConvertToPdfOriginForTesting(
|
||||
int x,
|
||||
int y,
|
||||
int height,
|
||||
const gfx::Rect& rect,
|
||||
float angle,
|
||||
float coordinate_system_height) {
|
||||
return ConvertToPdfOrigin(x, y, height, angle, coordinate_system_height);
|
||||
return ConvertToPdfOrigin(rect, angle, coordinate_system_height);
|
||||
}
|
||||
|
||||
PdfiumProgressiveSearchifier::ScopedSdkInitializer::ScopedSdkInitializer() {
|
||||
|
@ -15,12 +15,16 @@
|
||||
#include "third_party/pdfium/public/cpp/fpdf_scopers.h"
|
||||
#include "third_party/pdfium/public/fpdfview.h"
|
||||
#include "third_party/skia/include/core/SkBitmap.h"
|
||||
#include "ui/gfx/geometry/point_f.h"
|
||||
|
||||
namespace gfx {
|
||||
class Rect;
|
||||
} // namespace gfx
|
||||
|
||||
namespace chrome_pdf {
|
||||
|
||||
struct SearchifyBoundingBoxOrigin {
|
||||
float x;
|
||||
float y;
|
||||
gfx::PointF point;
|
||||
float theta;
|
||||
};
|
||||
|
||||
@ -31,9 +35,7 @@ std::vector<uint8_t> PDFiumSearchify(
|
||||
|
||||
// Internal function exposed for testing.
|
||||
SearchifyBoundingBoxOrigin ConvertToPdfOriginForTesting(
|
||||
int x,
|
||||
int y,
|
||||
int height,
|
||||
const gfx::Rect& rect,
|
||||
float angle,
|
||||
float coordinate_system_height);
|
||||
|
||||
|
@ -7,65 +7,53 @@
|
||||
#include <numbers>
|
||||
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
#include "ui/gfx/geometry/point_f.h"
|
||||
#include "ui/gfx/geometry/rect.h"
|
||||
|
||||
namespace chrome_pdf {
|
||||
|
||||
TEST(PdfiumSearchifyTest, ConvertToPdfOrigin) {
|
||||
constexpr gfx::Rect kRect(100, 50, 20, 30);
|
||||
{
|
||||
SearchifyBoundingBoxOrigin result = ConvertToPdfOriginForTesting(
|
||||
/*x=*/100,
|
||||
/*y=*/50,
|
||||
/*height=*/30,
|
||||
/*rect=*/kRect,
|
||||
/*angle=*/0,
|
||||
/*coordinate_system_height=*/792);
|
||||
EXPECT_FLOAT_EQ(100, result.x);
|
||||
EXPECT_FLOAT_EQ(712, result.y);
|
||||
EXPECT_EQ(gfx::PointF(100, 712), result.point);
|
||||
EXPECT_FLOAT_EQ(0, result.theta);
|
||||
}
|
||||
|
||||
{
|
||||
SearchifyBoundingBoxOrigin result = ConvertToPdfOriginForTesting(
|
||||
/*x=*/100,
|
||||
/*y=*/50,
|
||||
/*height=*/30,
|
||||
/*rect=*/kRect,
|
||||
/*angle=*/45,
|
||||
/*coordinate_system_height=*/792);
|
||||
EXPECT_FLOAT_EQ(78.786796f, result.x);
|
||||
EXPECT_FLOAT_EQ(720.786796f, result.y);
|
||||
EXPECT_EQ(gfx::PointF(78.786796f, 720.786796f), result.point);
|
||||
EXPECT_FLOAT_EQ(-std::numbers::pi_v<float> / 4, result.theta);
|
||||
}
|
||||
|
||||
{
|
||||
SearchifyBoundingBoxOrigin result = ConvertToPdfOriginForTesting(
|
||||
/*x=*/100,
|
||||
/*y=*/50,
|
||||
/*height=*/30,
|
||||
/*rect=*/kRect,
|
||||
/*angle=*/90,
|
||||
/*coordinate_system_height=*/792);
|
||||
EXPECT_FLOAT_EQ(70, result.x);
|
||||
EXPECT_FLOAT_EQ(742, result.y);
|
||||
EXPECT_EQ(gfx::PointF(70, 742), result.point);
|
||||
EXPECT_FLOAT_EQ(-std::numbers::pi_v<float> / 2, result.theta);
|
||||
}
|
||||
{
|
||||
SearchifyBoundingBoxOrigin result = ConvertToPdfOriginForTesting(
|
||||
/*x=*/100,
|
||||
/*y=*/50,
|
||||
/*height=*/30,
|
||||
/*rect=*/kRect,
|
||||
/*angle=*/180,
|
||||
/*coordinate_system_height=*/792);
|
||||
EXPECT_FLOAT_EQ(100, result.x);
|
||||
EXPECT_FLOAT_EQ(772, result.y);
|
||||
EXPECT_EQ(gfx::PointF(100, 772), result.point);
|
||||
EXPECT_FLOAT_EQ(-std::numbers::pi_v<float>, result.theta);
|
||||
}
|
||||
{
|
||||
SearchifyBoundingBoxOrigin result = ConvertToPdfOriginForTesting(
|
||||
/*x=*/100,
|
||||
/*y=*/50,
|
||||
/*height=*/30,
|
||||
/*rect=*/kRect,
|
||||
/*angle=*/-90,
|
||||
/*coordinate_system_height=*/792);
|
||||
EXPECT_FLOAT_EQ(130, result.x);
|
||||
EXPECT_FLOAT_EQ(742, result.y);
|
||||
EXPECT_EQ(gfx::PointF(130, 742), result.point);
|
||||
EXPECT_FLOAT_EQ(std::numbers::pi_v<float> / 2, result.theta);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user