Add (very simple) PDF renderer.
Some checks failed
continuous-integration/drone/push Build is failing

This commit is contained in:
Manuel Friedli 2020-10-03 02:31:33 +02:00
parent 5d07cfe1fc
commit 93dd5a26fa
4 changed files with 209 additions and 2 deletions

View file

@ -25,6 +25,11 @@
<groupId>io.vavr</groupId> <groupId>io.vavr</groupId>
<artifactId>vavr</artifactId> <artifactId>vavr</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>2.0.20</version>
</dependency>
<dependency> <dependency>
<groupId>org.junit.jupiter</groupId> <groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId> <artifactId>junit-jupiter-api</artifactId>

View file

@ -7,8 +7,8 @@ import java.nio.file.Paths;
public class Main { public class Main {
public static void main(@NonNull final String[] args) { public static void main(@NonNull final String[] args) {
int width = 80; int width = 20;
int height = 40; int height = 20;
final Labyrinth labyrinth = new Labyrinth(width, height); final Labyrinth labyrinth = new Labyrinth(width, height);
final TextRenderer textRenderer = TextRenderer.newInstance(); final TextRenderer textRenderer = TextRenderer.newInstance();
final HTMLRenderer htmlRenderer = HTMLRenderer.newInstance(); final HTMLRenderer htmlRenderer = HTMLRenderer.newInstance();
@ -18,6 +18,8 @@ public class Main {
.setTargetSolutionFile(userHome.resolve("labyrinth-solution.txt")); .setTargetSolutionFile(userHome.resolve("labyrinth-solution.txt"));
final HTMLFileRenderer htmlFileRenderer = HTMLFileRenderer.newInstance() final HTMLFileRenderer htmlFileRenderer = HTMLFileRenderer.newInstance()
.setTargetFile(userHome.resolve("labyrinth.html")); .setTargetFile(userHome.resolve("labyrinth.html"));
final PDFFileRenderer pdfFileRenderer = PDFFileRenderer.newInstance().setTargetFile(userHome.resolve("labyrinth.pdf"));
// Render Labyrinth to stdout // Render Labyrinth to stdout
System.out.println(textRenderer.render(labyrinth)); System.out.println(textRenderer.render(labyrinth));
// Render Labyrinth solution to stdout // Render Labyrinth solution to stdout
@ -28,5 +30,7 @@ public class Main {
System.out.println(textFileRenderer.render(labyrinth)); System.out.println(textFileRenderer.render(labyrinth));
// Render HTML to file // Render HTML to file
System.out.println(htmlFileRenderer.render(labyrinth)); System.out.println(htmlFileRenderer.render(labyrinth));
// Render PDF to file
System.out.println(pdfFileRenderer.render(labyrinth));
} }
} }

View file

@ -0,0 +1,56 @@
package ch.fritteli.labyrinth;
import lombok.NonNull;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
public class PDFFileRenderer implements Renderer<Path> {
@NonNull
private static final PDFRenderer PDF_RENDERER = PDFRenderer.newInstance();
private Path targetFile;
private PDFFileRenderer() {
try {
this.targetFile = Files.createTempFile("labyrinth_", ".pdf");
} catch (IOException e) {
System.err.println("Unable to set default target file.");
e.printStackTrace();
}
}
@NonNull
public static PDFFileRenderer newInstance() {
return new PDFFileRenderer();
}
public boolean isTargetFileDefinedAndWritable() {
return this.targetFile != null && this.targetFile.toFile().canWrite();
}
@NonNull
public PDFFileRenderer setTargetFile(@NonNull final Path targetFile) {
this.targetFile = targetFile;
return this;
}
@Override
public Path render(@NonNull final Labyrinth labyrinth) {
if (!this.isTargetFileDefinedAndWritable()) {
try {
Files.createFile(this.targetFile);
} catch (IOException e) {
throw new IllegalArgumentException("Cannot write to target file.", e);
}
}
final byte[] bytes = PDF_RENDERER.render(labyrinth);
try {
Files.write(this.targetFile, bytes);
} catch (IOException e) {
System.err.println("Failed writing to file " + this.targetFile.normalize().toString());
e.printStackTrace();
}
return this.targetFile;
}
}

View file

@ -0,0 +1,142 @@
package ch.fritteli.labyrinth;
import lombok.NonNull;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import java.awt.*;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
public class PDFRenderer implements Renderer<byte[]> {
private PDFRenderer() {
}
@NonNull
public static PDFRenderer newInstance() {
return new PDFRenderer();
}
@Override
@NonNull
public byte[] render(@NonNull final Labyrinth labyrinth) {
final PDDocument pdDocument = new PDDocument();
final PDPage page = new PDPage();
pdDocument.addPage(page);
try (PDPageContentStream pdPageContentStream = new PDPageContentStream(pdDocument, page)) {
pdPageContentStream.setLineCapStyle(BasicStroke.CAP_BUTT);
pdPageContentStream.setLineJoinStyle(BasicStroke.JOIN_MITER);
pdPageContentStream.setLineWidth(1.0f);
pdPageContentStream.setStrokingColor(Color.BLACK);
pdPageContentStream.setNonStrokingColor(Color.BLACK);
final float scale = 10;
final float margin = 5;
this.drawHorizonzalLines(labyrinth, pdPageContentStream, margin, scale);
this.drawVerticalLines(labyrinth, pdPageContentStream, margin, scale);
} catch (IOException e) {
e.printStackTrace();
}
final ByteArrayOutputStream output = new ByteArrayOutputStream();
try {
pdDocument.save(output);
pdDocument.close();
} catch (IOException e) {
e.printStackTrace();
}
return output.toByteArray();
}
private void drawHorizonzalLines(@NonNull final Labyrinth labyrinth, @NonNull final PDPageContentStream pdPageContentStream, final float margin, final float scale) throws IOException {
for (int y = 0; y < labyrinth.getHeight(); y++) {
boolean isPainting = false;
for (int x = 0; x < labyrinth.getWidth(); x++) {
final Tile currentTile = labyrinth.getTileAt(x, y);
if (currentTile.hasWallAt(Direction.TOP)) {
if (!isPainting) {
pdPageContentStream.moveTo(x * scale + margin, y * scale + margin);
isPainting = true;
}
} else {
if (isPainting) {
pdPageContentStream.lineTo(x * scale + margin, y * scale + margin);
pdPageContentStream.stroke();
isPainting = false;
}
}
}
if (isPainting) {
pdPageContentStream.lineTo(labyrinth.getWidth() * scale + margin, y * scale + margin);
pdPageContentStream.stroke();
}
}
boolean isPainting = false;
int y = labyrinth.getHeight();
for (int x = 0; x < labyrinth.getWidth(); x++) {
final Tile currentTile = labyrinth.getTileAt(x, y - 1);
if (currentTile.hasWallAt(Direction.BOTTOM)) {
if (!isPainting) {
pdPageContentStream.moveTo(x * scale + margin, y * scale + margin);
isPainting = true;
}
} else {
if (isPainting) {
pdPageContentStream.lineTo(x * scale + margin, y * scale + margin);
pdPageContentStream.stroke();
isPainting = false;
}
}
}
if (isPainting) {
pdPageContentStream.lineTo(labyrinth.getWidth() * scale + margin, labyrinth.getHeight() * scale + margin);
pdPageContentStream.stroke();
}
}
private void drawVerticalLines(@NonNull final Labyrinth labyrinth, @NonNull final PDPageContentStream pdPageContentStream, final float margin, final float scale) throws IOException {
for (int x = 0; x < labyrinth.getWidth(); x++) {
boolean isPainting = false;
for (int y = 0; y < labyrinth.getHeight(); y++) {
final Tile currentTile = labyrinth.getTileAt(x, y);
if (currentTile.hasWallAt(Direction.LEFT)) {
if (!isPainting) {
pdPageContentStream.moveTo(x * scale + margin, y * scale + margin);
isPainting = true;
}
} else {
if (isPainting) {
pdPageContentStream.lineTo(x * scale + margin, y * scale + margin);
pdPageContentStream.stroke();
isPainting = false;
}
}
}
if (isPainting) {
pdPageContentStream.lineTo(x * scale + margin, labyrinth.getHeight() * scale + margin);
pdPageContentStream.stroke();
}
}
boolean isPainting = false;
int x = labyrinth.getWidth();
for (int y = 0; y < labyrinth.getHeight(); y++) {
final Tile currentTile = labyrinth.getTileAt(x - 1, y);
if (currentTile.hasWallAt(Direction.RIGHT)) {
if (!isPainting) {
pdPageContentStream.moveTo(x * scale + margin, y * scale + margin);
isPainting = true;
}
} else {
if (isPainting) {
pdPageContentStream.lineTo(x * scale + margin, y * scale + margin);
pdPageContentStream.stroke();
isPainting = false;
}
}
}
if (isPainting) {
pdPageContentStream.lineTo(labyrinth.getWidth() * scale + margin, labyrinth.getHeight() * scale + margin);
pdPageContentStream.stroke();
}
}
}