
com.craigburke.document.builder.render.ParagraphRenderer.groovy Maven / Gradle / Ivy
package com.craigburke.document.builder.render
import com.craigburke.document.builder.PdfDocument
import com.craigburke.document.core.Align
import com.craigburke.document.core.ImageType
import com.craigburke.document.core.Text
import com.craigburke.document.core.TextBlock
import org.apache.pdfbox.pdmodel.edit.PDPageContentStream
import org.apache.pdfbox.pdmodel.graphics.xobject.PDJpeg
import org.apache.pdfbox.pdmodel.graphics.xobject.PDPixelMap
import org.apache.pdfbox.pdmodel.graphics.xobject.PDXObjectImage
import javax.imageio.ImageIO
import java.awt.image.BufferedImage
/**
* Rendering element for a Paragraph node
* @author Craig Burke
*/
class ParagraphRenderer implements Renderable {
TextBlock node
List lines
private int parseStart = 0
private int parseEnd = 0
private float startX
private boolean parsedAndRendered = false
private boolean fullyRendered = false
private boolean fullyParsed = false
ParagraphRenderer(TextBlock paragraph, PdfDocument pdfDocument, float startX, float maxWidth) {
node = paragraph
this.pdfDocument = pdfDocument
this.startX = startX
lines = ParagraphParser.getLines(paragraph, maxWidth)
}
boolean getFullyParsed() {
this.fullyParsed
}
int getParseStart() {
this.parseStart
}
int getParseEnd() {
this.parseEnd
}
void parse(float height) {
if (!lines || fullyRendered) {
fullyParsed = true
return
}
if (parsedAndRendered) {
parseEnd = Math.min(lines.size() - 1, parseEnd + 1)
parseStart = parseEnd
}
else {
parseEnd = parseStart
}
boolean reachedEnd = false
float parsedHeight = 0
while (!reachedEnd) {
ParagraphLine line = lines[parseEnd]
parsedHeight += line.totalHeight
if (parsedHeight > height) {
parseEnd = Math.max(0f, parseEnd - 1)
reachedEnd = true
fullyParsed = false
}
else {
if (line == lines.last()) {
reachedEnd = true
fullyParsed = true
}
}
if (!reachedEnd) {
parseEnd = Math.min(lines.size() - 1, parseEnd + 1)
}
}
parsedAndRendered = false
}
void renderElement(float startY) {
if (fullyRendered) {
return
}
if (onFirstPage) {
pdfDocument.y += node.margin.top
}
lines[parseStart..parseEnd].each { ParagraphLine line ->
pdfDocument.x = startX
renderLine(line)
}
fullyRendered = fullyParsed
parsedAndRendered = true
}
float getTotalHeight() {
node.margin.top + lines.sum { it.totalHeight } + node.margin.bottom
}
float getParsedHeight() {
float linesHeight = lines[parseStart..parseEnd]*.totalHeight.sum() ?: 0
float parsedHeight = (onFirstPage ? node.margin.top : 0) + linesHeight + (fullyParsed ? node.margin.bottom : 0)
parsedHeight
}
private void renderLine(ParagraphLine line) {
float renderStartX = startX
switch (line.paragraph.align) {
case Align.RIGHT:
renderStartX += line.maxWidth - line.contentWidth
break
case Align.CENTER:
renderStartX += Math.round((line.maxWidth - line.contentWidth) / 2)
}
pdfDocument.x = renderStartX
pdfDocument.y += line.contentHeight
line.elements.each { element ->
switch (element.getClass()) {
case TextElement:
renderTextElement(element)
pdfDocument.x += element.width
break
case ImageElement:
renderImageElement(element)
pdfDocument.x += element.node.width
break
}
}
pdfDocument.y += line.lineSpacing
}
private void renderTextElement(TextElement element) {
Text text = element.node
PDPageContentStream contentStream = pdfDocument.contentStream
contentStream.beginText()
contentStream.moveTextPositionByAmount(pdfDocument.x, pdfDocument.translatedY)
def color = text.font.color.rgb
contentStream.setNonStrokingColor(color[0], color[1], color[2])
contentStream.setFont(element.pdfFont, text.font.size)
contentStream.drawString(element.text)
contentStream.endText()
}
private void renderImageElement(ImageElement element) {
InputStream inputStream = new ByteArrayInputStream(element.node.data)
BufferedImage bufferedImage = ImageIO.read(inputStream)
PDXObjectImage img
if (element.node.type == ImageType.PNG) {
img = new PDPixelMap(pdfDocument.pdDocument, bufferedImage)
}
else {
img = new PDJpeg(pdfDocument.pdDocument, bufferedImage)
}
int width = element.node.width
int height = element.node.height
pdfDocument.contentStream.drawXObject(img, pdfDocument.x, pdfDocument.translatedY, width, height)
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy