blob: 712c38842c100f2d6fc9aacdb939df8a9d9cb26d [file] [log] [blame]
// Copyright 2020 The Chromium OS 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 <fcntl.h>
#include <iostream>
#include <memory>
#include <string>
#include <utility>
#include <base/at_exit.h>
#include <base/bind.h>
#include <base/files/file_path.h>
#include <base/files/scoped_file.h>
#include <base/logging.h>
#include <base/message_loop/message_pump_type.h>
#include <base/posix/eintr_wrapper.h>
#include <base/strings/string_util.h>
#include <base/task/single_thread_task_executor.h>
#include <brillo/flag_helper.h>
#include <brillo/syslog_logging.h>
#include <mojo/public/cpp/system/handle.h>
#include <mojo/public/cpp/system/platform_handle.h>
#include "ocr/mojo/ocr_service.mojom.h"
#include "ocr/mojo_adapter/ocr_service_mojo_adapter.h"
namespace {
namespace mojo_ipc = chromeos::ocr::mojom;
mojo::ScopedHandle GetFileHandle(const base::FilePath& path, int oflag) {
base::ScopedFD fd(HANDLE_EINTR(open(path.value().c_str(), oflag, 0644)));
if (fd.get() < 0) {
PLOG(ERROR) << "Unable to open file: " << path.value();
return mojo::ScopedHandle();
}
return mojo::WrapPlatformHandle(mojo::PlatformHandle(std::move(fd)));
}
mojo::ScopedHandle GetInputFileHandle(const base::FilePath& input_filepath) {
return GetFileHandle(input_filepath,
O_RDONLY | O_NOFOLLOW | O_NOCTTY | O_CLOEXEC);
}
mojo::ScopedHandle GetOutputFileHandle(const base::FilePath& output_filepath) {
return GetFileHandle(output_filepath, O_CREAT | O_WRONLY | O_CLOEXEC);
}
} // namespace
int main(int argc, char* argv[]) {
// Parse command line flags.
DEFINE_string(
input_image_filename, "",
"Filename of input image. Supported image formats: PNG, JPEG and TIFF.");
DEFINE_string(output_pdf_filename, "", "Filename of output PDF file.");
DEFINE_string(language, "eng",
"Document language. Supported languages: eng (English).");
brillo::FlagHelper::Init(argc, argv,
"ocr_tool - Optical Character Recognition "
"command line tool.");
brillo::InitLog(brillo::kLogToSyslog | brillo::kLogToStderrIfTty);
// When the at_exit_manager object goes out of scope, all the registered
// callbacks and singleton destructors will be called.
base::AtExitManager at_exit_manager;
// Mojo requires a sequenced context.
base::SingleThreadTaskExecutor task_executor(base::MessagePumpType::IO);
// Get adapter instance to send requests to OCR service.
std::unique_ptr<ocr::OcrServiceMojoAdapter> adapter =
ocr::OcrServiceMojoAdapter::Create();
DCHECK(adapter);
// Validate input arguments.
base::FilePath input_image_filename =
base::FilePath(FLAGS_input_image_filename);
if (input_image_filename.empty()) {
LOG(ERROR) << "--input_image_filename must be specified."
" Use --help for help on usage.";
return EXIT_FAILURE;
}
base::FilePath output_pdf_filename =
base::FilePath(FLAGS_output_pdf_filename);
if (output_pdf_filename.empty())
output_pdf_filename = input_image_filename.ReplaceExtension("pdf");
if (!base::EqualsCaseInsensitiveASCII(output_pdf_filename.Extension(),
".pdf")) {
LOG(ERROR) << "--output_pdf_filename must have a .pdf extension."
" Use --help for help on usage.";
return EXIT_FAILURE;
}
if (FLAGS_language.compare("eng") != 0) {
LOG(ERROR) << "Selected language " << FLAGS_language
<< " is not supported."
" Use --help for help on usage.";
return EXIT_FAILURE;
}
// Construct request.
mojo::ScopedHandle input_fd_handle = GetInputFileHandle(input_image_filename);
if (!input_fd_handle)
return EXIT_FAILURE;
mojo::ScopedHandle output_fd_handle =
GetOutputFileHandle(output_pdf_filename);
if (!output_fd_handle)
return EXIT_FAILURE;
mojo_ipc::OcrConfigPtr ocr_config = mojo_ipc::OcrConfig::New();
ocr_config->language = FLAGS_language;
mojo_ipc::PdfRendererConfigPtr pdf_renderer_config =
mojo_ipc::PdfRendererConfig::New();
// Perform OCR.
auto response = adapter->GenerateSearchablePdfFromImage(
std::move(input_fd_handle), std::move(output_fd_handle),
std::move(ocr_config), std::move(pdf_renderer_config));
if (!response) {
LOG(ERROR) << "No response received from GenerateSearchablePdfFromImage().";
return EXIT_FAILURE;
}
bool success = response->result == mojo_ipc::OcrResultEnum::SUCCESS;
if (success) {
std::cout << "Generated searchable PDF file: " << output_pdf_filename
<< std::endl;
} else {
LOG(ERROR) << response->result_message;
}
return success ? EXIT_SUCCESS : EXIT_FAILURE;
}