// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
//
// 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 "result.h"
#include <fstream>
#include <string>
#include "src/utils/utility.h"
#include "third_party/nlohmann/json.hpp"
using json = nlohmann::json;
void DocTrResult::SaveToImg(const std::string &save_path) {
absl::StatusOr<std::string> full_path;
if (predictor_result_.input_path.empty()) {
auto now = std::chrono::system_clock::now();
auto now_time = std::chrono::system_clock::to_time_t(now);
std::stringstream ss;
ss << "output_" << std::put_time(std::localtime(&now_time), "%Y%m%d_%H%M%S")
<< ".jpg";
std::string timestamp_filename = ss.str();
INFOW("Input path is empty, will use %s instead!",
timestamp_filename.c_str());
predictor_result_.input_path = timestamp_filename;
full_path =
Utility::SmartCreateDirectoryForImage(save_path, timestamp_filename);
} else {
full_path = Utility::SmartCreateDirectoryForImage(
save_path, predictor_result_.input_path);
}
bool success = cv::imwrite(full_path.value(), predictor_result_.doctr_img);
if (!success) {
INFOE("Failed to write the image %s", full_path.value().c_str());
exit(-1);
}
}
void DocTrResult::Print() const {
std::cout << "{\n \"res\": {" << std::endl;
std::cout << " \"input_path\": {" << predictor_result_.input_path << "},"
<< std::endl;
std::cout << " \"doctr_img\": {"
<< "..."
<< "}" << std::endl;
std::cout << "}" << std::endl;
}
void DocTrResult::SaveToJson(const std::string &save_path) const {
nlohmann::ordered_json j;
j["input_path"] = predictor_result_.input_path;
j["page_index"] = nullptr; //********
nlohmann::json mat_array = nlohmann::json::array();
for (int i = 0; i < predictor_result_.doctr_img.rows; ++i) {
nlohmann::json row = nlohmann::json::array();
for (int j = 0; j < predictor_result_.doctr_img.cols; ++j) {
cv::Vec3b color = predictor_result_.doctr_img.at<cv::Vec3b>(i, j);
row.push_back({color[0], color[1], color[2]});
}
mat_array.push_back(row);
}
j["doctr_img"] = mat_array;
auto full_path = Utility::SmartCreateDirectoryForJson(
save_path, predictor_result_.input_path);
if (!full_path.ok()) {
INFOE(full_path.status().ToString().c_str());
exit(-1);
}
std::ofstream file(full_path.value());
if (file.is_open()) {
file << j.dump(4);
file.close();
} else {
INFOE("Could not open file for writing: %s", save_path.c_str());
exit(-1);
}
}
int DocTrResult::getAdaptiveFontScale(const std::string &text, int imgWidth,
int maxWidth, int minFont, int maxFont,
int thickness, int &outBaseline,
int &outFontFace) {
int fontFace = cv::FONT_HERSHEY_SIMPLEX;
double fontScale = 1.0;
int baseline = 0;
int bestFontSize = minFont;
for (int fontSize = maxFont; fontSize >= minFont; --fontSize) {
fontScale = fontSize / 20.0;
int base;
cv::Size textSize =
cv::getTextSize(text, fontFace, fontScale, thickness, &base);
if (textSize.width <= maxWidth) {
bestFontSize = fontSize;
outBaseline = base;
outFontFace = fontFace;
return fontScale;
}
}
outBaseline = 0;
outFontFace = fontFace;
return minFont / 20.0;
}