package com.cool.store.utils;

import com.lowagie.text.Document;
import com.lowagie.text.Font;
import com.lowagie.text.Image;
import com.lowagie.text.Paragraph;
import com.lowagie.text.pdf.*;
import lombok.extern.slf4j.Slf4j;
import org.icepdf.core.exceptions.PDFException;
import org.icepdf.core.exceptions.PDFSecurityException;
import org.icepdf.core.pobjects.Page;
import org.icepdf.core.util.GraphicsRenderingHints;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import java.io.*;

/**
 * 使用 OpenPDF 封装的 pdf 工具类
 */
@Slf4j
public class PDFUtils {

    private static final int[] A4Size = {595, 842};

    /**
     * 设置 pdf 背景图片（A4）
     * 每页都需要单独设置
     */
    public static void setBackgroundImgA4(Document document, Image image) {
        //图片顶格
        image.setAbsolutePosition(0, 0);
        //填满 A4 大小的页面
        image.scaleAbsolute(A4Size[0], A4Size[1]);
        document.add(image);
    }

    /**
     * 设置 pdf 背景图片
     * 每页都需要单独设置
     */
    public static void setBackgroundImg(Document document, Image image, int width, int height) {
        //图片顶格
        image.setAbsolutePosition(0, 0);
        image.scaleAbsolute(width, height);
        document.add(image);
    }

    /**
     * 将文本放在 pdf 的绝对位置上来抠模板（不指定字体，默认为 OpenPDF 自带的 STSong-Light Normal）
     * @param reader PdfReader 流
     * @param outputStream 输出流
     * @param x 左边距
     * @param y 下边距
     * @param content 要插入的文本
     * @param fontSize 字体大小
     * @param color 文本颜色
     */
    public static void putParagraphAbsolutely(PdfReader reader, OutputStream outputStream, float x, float y, String content, float fontSize, Color color) {
        try {
            BaseFont baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
            addContent(reader, outputStream, content, x, y, baseFont, fontSize, 0, color);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 指定字体的文本绝对位置插入方法
     * @param reader PdfReader 流
     * @param outputStream 输出流
     * @param x 左边距
     * @param y 下边距
     * @param content 要插入的文本
     * @param baseFont 字体设置（如果不使用 OpenPDF 自带的字体，就需要将字体文件放在项目路径下）
     *        自定义字体方式
     *        ttf 字体
     *        1. BaseFont baseFont = BaseFont.createFont("arial.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
     *        ttc 字体（包含了两种字体，所以需要选择 0 或 1）
     *        2. BaseFont baseFont = BaseFont.createFont("simsun.ttc,0", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
     * @param fontSize 字体大小
     * @param fontStyle 字体风格（）
     *        NORMAL = 0; BOLD = 1; ITALIC = 2; UNDERLINE = 4; STRIKETHRU = 8; BOLDITALIC = BOLD | ITALIC;
     * @param color 字体颜色
     */
    public static void putParagraphAbsolutely(PdfReader reader, OutputStream outputStream, float x, float y, String content, BaseFont baseFont, float fontSize, int fontStyle, Color color) {
        addContent(reader, outputStream, content, x, y, baseFont, fontSize, fontStyle, color);
    }

    /**
     * 插入文本的 raw 方法
     * @param reader PDF 读取流
     * @param outputStream 输出流
     * @param content 插入文本
     * @param x 左边距
     * @param y 下边距
     * @param baseFont 字体和编码设置
     * @param fontSize 字体大小
     * @param fontStyle 字体风格
     * @param color 字体颜色
     */
    private static void addContent(PdfReader reader, OutputStream outputStream, String content, float x, float y, BaseFont baseFont, float fontSize, int fontStyle, Color color) {
        PdfStamper stamper = null;
        try {
            //生成 paragraph 并放在正确位置
            //抠模板
            stamper = new PdfStamper(reader, outputStream);
            PdfContentByte over = stamper.getOverContent(1);
            Font font = new Font(baseFont, fontSize, fontStyle, color);
            Paragraph insertContent = new Paragraph(content, font);

            ColumnText columnText = new ColumnText(over);
            // llx 和 urx  最小的值决定离左边的距离. lly 和 ury 最大的值决定离下边的距离
            columnText.setSimpleColumn(x, y, Float.MAX_VALUE, Float.MIN_VALUE);
            columnText.addElement(insertContent);
            columnText.go();
            stamper.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            try {
                if (stamper != null) {
                    stamper.close();
                }
            } catch (IOException ex) {
                throw new RuntimeException(ex);
            }
        }
    }

    /**
     * PDF 转图片
     * @param inputStream pdf 输入流
     * @param scale 缩放比例
     */
    //不再将通过函转为图片
    @Deprecated
    public static ByteArrayOutputStream pdf2Img(InputStream inputStream, float scale) {
        org.icepdf.core.pobjects.Document document = new org.icepdf.core.pobjects.Document();
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        try {
            document.setInputStream(inputStream, "");

            float rotation = 0f;// 旋转角度
            for (int i = 0; i < document.getNumberOfPages(); i++) {
                BufferedImage image = (BufferedImage) document.getPageImage(i,
                        GraphicsRenderingHints.SCREEN, Page.BOUNDARY_CROPBOX,
                        rotation, scale);
                RenderedImage rendImage = image;
                ImageIO.write(rendImage, "png", outputStream);
                //例子中是pdf转png格式的，也可以将上面两行改成jpg，转出jpg格式的，
                //但是从转换效果来看png的清晰度会相对较高。有个小技巧是第一行行改成jpg，
                //但第二行使用png，也就是转换成jpg格式但有png清晰度的图片。
                image.flush();
                document.dispose();
                return outputStream;
            }
        } catch (PDFException | IOException | InterruptedException | PDFSecurityException e) {
            log.error("PDF转图片异常, e{}", e.getMessage());
        } finally {
            try {
                outputStream.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        return outputStream;
    }
}
