﻿/*
    Antenna House PDF Tool API V8.0
    C++ Interface sample program

    概要：画像の入れ替え（ぼかす）

    本サンプルコードでは、画像処理ライブラリとして OpenCV を使用しています。
　　OpenCVは Apache License 2.0 に基づき配布されています。
　　ライセンス内容は「LICENSE_OpenCV.txt」をご確認ください。

    Copyright 2025- Antenna House, Inc.
*/

#include < PdfTk.h >
#include < stdio.h >
#include < string >
#include < iostream >
#include < opencv2/opencv.hpp >


using namespace std;
using namespace PdfTk;

bool replaceImage(PtlContent& content, const string& imageParh);
cv::Mat load_image(const std::string file_path);
cv::Mat blur(const cv::Mat& image);
void out_image(const std::string file_path, const cv::Mat blur);
bool replaceImageWithImage(PtlEditImage& elemImage, const string& imagePath);

int main(int argc, char* argv[])
{
    if (argc < 3) {
        printf("usage: EditElement.exe in-pdf-file out-pdf-file\n");
        return 1;
    }

    try
    {
        PtlParamInput input(argv[1]);
        PtlParamOutput output(argv[2]);

        // 一時ファイルのパスを指定します。
        const char* imagePath = "C:\\tmp\\tmp.jpg";

        PtlPDFDocument doc;

        // PDFファイルをロードします。
        doc.load(input);

        // ページコンテナの取得
        PtlPages& pages = doc.getPages();

        if (pages.isEmpty()) {
            printf("ページコンテナが空\n");
            return 1;
        }

        int pageCount = pages.getCount();
        if (pageCount >= 1)
        {
            for (int pg = 0; pg < pageCount; ++pg)
            {
                PtlPage page = pages.get(pg);

                PtlContent& content = page.getContent();

                // 画像を取得してボカシて入れ替える例
                if (replaceImage(content, imagePath))
                {
                    page.setContent(content);   // ページコンテントを置き換える

                    printf("置き換え完了!\n");
                }
            }
        }
        doc.save(output);

        printf("完了!\n");
    }
    catch (const PtlException& e)
    {
        fprintf(stderr, "Error code : %d\n %s\n", e.getErrorCode(), e.getErrorMessage().c_str());
        return 1;
    }
    return 0;
}

// 画像を取得してボカシて入れ替える例
bool replaceImage(PtlContent& content, const string& imagePath)
{
    bool ret = false;
    try
    {
        PtlEditElements& elems = content.getEditElements();

        if (elems.isEmpty()) return false;
        int elementcount = elems.getCount();
        for (int i = 0; i < elementcount; ++i)
        {
            PtlEditElement& elem = elems.get(i);
            switch (elem.getType())
            {
            case PtlEditElement::TYPE_FORMXOBJECT:
            {
                PtlEditFormXObject& elemForm = (PtlEditFormXObject&)elem;
                PtlContent& contentForm = elemForm.getContent();            // FormXObjectコンテント取得
                // FormXObjectコンテントをパースして画像を置き換える
                if (replaceImage(contentForm, imagePath))
                {
                    elemForm.setContent(contentForm);   // FormXObjectコンテントを置き換える
                }
            }
            break;
            case PtlEditElement::TYPE_MCCONTAINER:
            {
                PtlEditMCContainer& elemContainer = (PtlEditMCContainer&)elem;
                PtlContent& contentContainer = elemContainer.getContent();    // マークコンテント取得
                {
                    // マークコンテントをパースして画像を置き換える
                    if (replaceImage(contentContainer, imagePath))
                    {
                        ret = true;     // 上位のPtlPageかPtlEditFormXObjectでsetContentが必要
                    }
                }
            }
            break;
            case PtlEditElement::TYPE_IMAGE:
            {
                PtlEditImage& elemImage = (PtlEditImage&)elem;

                //const char* pathImage = "C:\\tmp\\tmp.jpg";
                PtlParamOutput output(imagePath.c_str());
				// 画像を一時ファイルとして保存する
                elemImage.writeFile(output, PtlEditImage::FORMAT_JPEG);

                // 画像を読み込む
                const cv::Mat loaded_image = load_image(imagePath.c_str());
                // 画像をぼかす
                const cv::Mat blur_image = blur(loaded_image);
                // ぼかした画像を一時ファイルとして保存する
                out_image(imagePath, blur_image);

                // PtlEditImageの画像を直接置き換える
                if (replaceImageWithImage(elemImage, imagePath))
                {
                    ret = true;
                }
            }
            break;
            default:
                break;
            }
        }
    }
    catch (PtlException e)
    {
        fprintf(stderr, "Error code : %d\n %s\n", e.getErrorCode(), e.getErrorMessage().c_str());
        return false;
    }
    return ret;
}

// 画像を読み込む
cv::Mat load_image(const std::string file_path) {
    cv::Mat loaded_image = cv::imread(file_path, 1);
    if (loaded_image.empty()) {
        throw std::runtime_error("画像を正常に読み込めませんでした。");
    }
    return loaded_image;
}

// 画像をぼかす
cv::Mat blur(const cv::Mat& image) {
    cv::Mat blur_image;
    cv::blur(image, blur_image, cv::Size(65, 65));
    return blur_image;
}

// ぼかした画像を一時ファイルとして保存する
void out_image(const std::string file_path, const cv::Mat blur) {
    bool result = cv::imwrite(file_path, blur);
    if (!result) {
        throw std::runtime_error("画像を正常に保存できませんでした。");
    }
}

// PtlEditImageの画像を直接置き換える
bool replaceImageWithImage(PtlEditImage& elemImage, const string& imagePath)
{
    try
    {
        PtlParamInput input(imagePath.c_str());
        PtlParamEditImage paramEditImage;
        {
            paramEditImage.setImageStream(input);
            paramEditImage.setUseOriginalJpegQuality(true);
            elemImage.setImage(paramEditImage); // PtlParamEditImageに設定した画像で置き換え
        }
        return true;    // Elementが所属するPtlPage若しくはPtlEditFormXObjectでsetContentが必要なのでtrueを返す
    }
    catch (PtlException e)
    {
        fprintf(stderr, "Error code : %d\n %s\n", e.getErrorCode(), e.getErrorMessage().c_str());
        return false;
    }
    return false;
}

