
com.uchicom.repty.Repty Maven / Gradle / Ivy
package com.uchicom.repty;
import java.awt.Color;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.fontbox.ttf.TrueTypeCollection;
import org.apache.fontbox.ttf.TrueTypeFont;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.PDResources;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDType0Font;
import org.apache.pdfbox.pdmodel.font.PDType1Font;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationWidget;
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
import org.apache.pdfbox.pdmodel.interactive.form.PDTextField;
import com.uchicom.repty.dto.Draw;
import com.uchicom.repty.dto.Font;
import com.uchicom.repty.dto.Line;
import com.uchicom.repty.dto.Meta;
import com.uchicom.repty.dto.Path;
import com.uchicom.repty.dto.Template;
import com.uchicom.repty.dto.Text;
import com.uchicom.repty.dto.Unit;
import com.uchicom.repty.dto.Value;
/**
*
* @author hex
*
*/
public class Repty implements Closeable {
Map ttcMap = new HashMap<>();
Map xImageMap = new HashMap<>();
Map ttFontMap = new HashMap<>();
Map pdFontMap = new HashMap<>();
PDDocument document;
Template template;
List draws = new ArrayList<>(1024);
List metas = new ArrayList<>(8);
public Repty(PDDocument document, Template template) throws IOException {
// フォントマップ作成
Map fontMap = template.getSpec().getFontMap();
fontMap.forEach((key, value) -> {
if (!ttcMap.containsKey(value.getTtc())) {
try {
ttcMap.put(value.getTtc(), new TrueTypeCollection(Files.newInputStream(Paths.get(value.getTtc()))));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
try {
ttFontMap.put(key, ttcMap.get(value.getTtc()).getFontByName(value.getName()));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
});
// イメージマップ作成
Map imageMap = template.getSpec().getImageMap();
imageMap.forEach((key, value) -> {
System.out.println(value.getPath());
try (ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
InputStream is = getClass().getClassLoader().getResourceAsStream(value.getPath());) {
byte[] bytes = new byte[1024 * 4 * 1024];
int length = 0;
while ((length = is.read(bytes)) > 0) {
baos.write(bytes, 0, length);
}
xImageMap.put(key, PDImageXObject.createFromByteArray(document, baos.toByteArray(), "test"));// TODO
// 画像指定検討
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
});
// addPageする前に初期状態を準備しておいて、出力内容を使いまわして保存する。
this.document = document;
this.template = template;
}
/**
* 初期化 保存時にクリアされてしまう 新バージョンで解決されるかも。
*
* @throws IOException
* 入出力エラー
*/
public void init() throws IOException {
ttFontMap.forEach((key, value) -> {
try {
pdFontMap.put(key, PDType0Font.load(document, value, true));
} catch (IOException e) {
e.printStackTrace();
}
});
}
public Repty addKey(String drawKey) {
Unit unit = template.getDrawMap().get(drawKey);
List drawList = unit.getDrawList();
if (!drawList.isEmpty()) {
draws.addAll(drawList);
}
if (unit.getMeta() != null) {
metas.add(unit.getMeta());
}
return this;
}
public Repty changeKey(String removeKey, String addKey) {
Unit unit = template.getDrawMap().get(removeKey);
List drawList = unit.getDrawList();
if (!drawList.isEmpty()) {
draws.removeAll(drawList);
}
if (unit.getMeta() != null) {
metas.remove(unit.getMeta());
}
addKey(addKey);
return this;
}
public PDPage addPage(Map paramMap) throws IOException, NoSuchFieldException, SecurityException,
IllegalArgumentException, IllegalAccessException {
PDPage page = null;
if (metas.isEmpty()) {
page = new PDPage(PDRectangle.A4);
} else {
Field field = PDRectangle.class.getDeclaredField(metas.get(metas.size() - 1).getPdRectangle());
page = new PDPage((PDRectangle) field.get(PDRectangle.A4));
}
Map colorMap = template.getSpec().getColorMap();
Map lineMap = template.getSpec().getLineMap();
Map textMap = template.getSpec().getTextMap();
Map fontMap = template.getSpec().getFontMap();
// 書き込む用のストリームを準備
try (PDPageContentStream stream = new PDPageContentStream(document, page);) {
for (Draw draw : draws) {
switch (draw.getType()) {
case "line":// 線
Line line = lineMap.get(draw.getKey());
Color color = colorMap.get(line.getColorKey());
float lineWidth = line.getWidth();
for (Value value : draw.getValues()) {
stream.setLineWidth(lineWidth);
stream.setStrokingColor(color);
stream.moveTo(value.getX1(), value.getY1());
stream.lineTo(value.getX2(), value.getY2());
stream.stroke();
}
break;
case "rectangle": // 四角形
Line line1 = lineMap.get(draw.getKey());
Color color1 = colorMap.get(line1.getColorKey());
float lineWidth1 = line1.getWidth();
for (Value value : draw.getValues()) {
// 塗りつぶしかどうか
stream.setLineWidth(lineWidth1);
stream.setStrokingColor(color1);
stream.addRect(value.getX1(), value.getY1(), value.getX2() - value.getX1(),
value.getY2() - value.getY1());
if (value.isFill()) {
stream.setNonStrokingColor(color1);
stream.fill();// 塗りつぶし
} else {
stream.stroke();
}
}
break;
case "string": // 文字列描画 // TODO 文字列左右中央寄せ、全体の幅指定、改行機能検討
Text text = textMap.get(draw.getKey());
Color color2 = colorMap.get(text.getColorKey());
Font font2 = fontMap.get(text.getFontKey());
PDFont pdFont = pdFontMap.get(text.getFontKey());
stream.setNonStrokingColor(color2);
stream.setFont(pdFont, font2.getSize());
for (Value value : draw.getValues()) {
stream.beginText();
String tempValue = value.getValue();
for (Map.Entry entry : paramMap.entrySet()) {
if (tempValue.contains("${")) {
String replace = null;
if (entry.getValue() == null) {
replace = "";
} else {
replace = entry.getValue().toString();
}
tempValue = tempValue.replaceAll("\\$\\{" + entry.getKey() + "\\}", replace);
}
}
float width = pdFont.getStringWidth(tempValue) / 1000 * font2.getSize();
//TODO 自動改行機能
float x = value.getX1();
switch (value.getAlign()) {
case 2:
//フォントの長さを見て変える
x -= width / 2;
break;
case 3:
x -= width;
break;
default:
}
stream.newLineAtOffset(x, value.getY1());
stream.showText(tempValue);
stream.endText();
}
break;
case "image":
// イメージ描画(今回は使い回し)
PDImageXObject imagex = xImageMap.get(draw.getKey());
for (Value value : draw.getValues()) {
if (value.getX1() == value.getX2()) {
stream.drawImage(imagex, value.getX1(), value.getY1());
} else {
stream.drawImage(imagex, value.getX1(), value.getY1(), value.getX2() - value.getX1(),
value.getY2() - value.getY1());
}
}
break;
case "form": // TODO 今後の課題
PDAcroForm acroForm = new PDAcroForm(document);
document.getDocumentCatalog().setAcroForm(acroForm);
PDFont font = PDType1Font.HELVETICA;
PDResources resources = new PDResources();
resources.put(COSName.getPDFName("Helv"), font);
acroForm.setDefaultResources(resources);
PDTextField field = new PDTextField(acroForm);
field.setPartialName("test");
field.setDefaultAppearance("/Helv 12 Tf 0 0 1 rg");// 12→0で自動
acroForm.getFields().add(field);
PDAnnotationWidget widget = field.getWidgets().get(0);
PDRectangle rectangle = new PDRectangle(10, 200, 50, 50);
widget.setRectangle(rectangle);
widget.setPage(page);
field.getWidgets().add(widget);
widget.setPrinted(true);
widget.setReadOnly(true);
page.getAnnotations().add(widget);
field.setValue("testtesttesttest"); // /DA is a required entry
break;
case "recordString":
Text recordText = textMap.get(draw.getKey());
Color recordColor = colorMap.get(recordText.getColorKey());
Font recordFont = fontMap.get(recordText.getFontKey());
PDFont recordPdFont = pdFontMap.get(recordText.getFontKey());
stream.setNonStrokingColor(recordColor);
stream.setFont(recordPdFont, recordFont.getSize());
for (int i = 0; i < draw.getValues().size(); i++) {
Value value = draw.getValues().get(i);
try {
drawRecordString(stream, value, paramMap);
} catch (Exception e) {
e.printStackTrace();
}
}
break;
case "recordLine":
line = lineMap.get(draw.getKey());
color = colorMap.get(line.getColorKey());
lineWidth = line.getWidth();
stream.setLineWidth(lineWidth);
stream.setStrokingColor(color);
for (int i = 0; i < draw.getValues().size(); i++) {
Value value = draw.getValues().get(i);
try {
drawRecordLine(stream, value, paramMap);
} catch (Exception e) {
e.printStackTrace();
}
}
break;
case "recordRectangle":
line = lineMap.get(draw.getKey());
color = colorMap.get(line.getColorKey());
lineWidth = line.getWidth();
stream.setLineWidth(lineWidth);
stream.setStrokingColor(color);
for (int i = 0; i < draw.getValues().size(); i++) {
Value value = draw.getValues().get(i);
try {
drawRecordRectangle(stream, value, paramMap);
} catch (Exception e) {
e.printStackTrace();
}
}
break;
default:
break;
}
}
// ストリームを閉じる
}
return page;
}
public static void drawRecordRectangle(PDPageContentStream stream, Value value, Map paramMap)
throws IOException {
int size = ((List>) paramMap.get(value.getParamName())).size();
if (size == 0)
return;
float nextX = value.getNextX();
float nextY = value.getNextY();
float x1 = value.getX1();
float y1 = value.getY1();
float x2 = value.getX2();
float y2 = value.getY2();
if (nextX < 0 && value.getX1() < value.getX2() || nextX > 0 && value.getX1() > value.getX2()) {
x2 = x1;
x1 = value.getX2();
}
if (nextY < 0 && value.getY1() < value.getY2() || nextY > 0 && value.getY1() > value.getY2()) {
y2 = y1;
y1 = value.getY2();
}
if (nextX == 0) {
y2 += nextY * size;
stream.addRect(x1, y1, x2 - x1, y2 - y1);
} else if (nextY == 0) {
x2 += nextX * size;
stream.addRect(x1, y1, x2 - x1, y2 - y1);
}
if (value.isFill()) {
stream.fill();// 塗りつぶし
} else {
stream.stroke();
}
}
public static void drawRecordLine(PDPageContentStream stream, Value value, Map paramMap)
throws IOException {
int size = ((List>) paramMap.get(value.getParamName())).size();
if (size == 0)
return;
float nextX = value.getNextX();
float nextY = value.getNextY();
float x1 = value.getX1();
float y1 = value.getY1();
float x2 = value.getX2();
float y2 = value.getY2();
if (nextX < 0 && value.getX1() < value.getX2() || nextX > 0 && value.getX1() > value.getX2()) {
x2 = x1;
x1 = value.getX2();
}
if (nextY < 0 && value.getY1() < value.getY2() || nextY > 0 && value.getY1() > value.getY2()) {
y2 = y1;
y1 = value.getY2();
}
// 延長か繰り返しかを判断する
if (x1 == x2 && nextX == 0 && !value.isRepeat()) {
y2 += nextY * (size - 1);
stream.moveTo(x1, y1);
stream.lineTo(x2, y2);
stream.stroke();
} else if (y1 == y2 && nextY == 0 && !value.isRepeat()) {
x2 += nextX * (size - 1);
stream.moveTo(x1, y1);
stream.lineTo(x2, y2);
stream.stroke();
} else {
for (int i = 0; i < size; i++) {
// x1,x2大きい方で判断、差分の+-を比較する。
// listを取得、スタートindexを取得2ページにまたがる場合の処理が難しい。list.size()
stream.moveTo(x1 + nextX * i, y1 + nextY * i);
stream.lineTo(x2 + nextX * i, y2 + nextY * i);
stream.stroke();
}
}
}
public static void drawRecordString(PDPageContentStream stream, Value value, Map paramMap)
throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException,
InvocationTargetException, IOException {
List> list = (List>) paramMap.get(value.getParamName());
if (list == null || list.isEmpty())
return;
Method method = list.get(0).getClass().getMethod(
"get" + value.getMemberName().substring(0, 1).toUpperCase() + value.getMemberName().substring(1));
for (int i = 0; i < list.size(); i++) {
String string = method.invoke(list.get(i)).toString();
// TODO listを取得、スタートindexを取得2ページにまたがる場合の処理が難しい。list.size()
stream.beginText();
stream.newLineAtOffset(value.getX1() + value.getNextX() * i, value.getY1() + value.getNextY() * i);
stream.showText(string);
stream.endText();
}
}
@Override
public void close() throws IOException {
ttcMap.forEach((key, value) -> {
try {
value.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
});
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy