All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.ofdrw.layout.engine.render.ParagraphRender Maven / Gradle / Ivy

The newest version!
package org.ofdrw.layout.engine.render;

import org.ofdrw.core.basicStructure.pageObj.layer.block.CT_PageBlock;
import org.ofdrw.core.basicStructure.pageObj.layer.block.PathObject;
import org.ofdrw.core.basicStructure.pageObj.layer.block.TextObject;
import org.ofdrw.core.basicType.ST_Box;
import org.ofdrw.core.basicType.ST_ID;
import org.ofdrw.core.basicType.ST_Loc;
import org.ofdrw.core.graph.pathObj.AbbreviatedData;
import org.ofdrw.core.pageDescription.color.color.CT_Color;
import org.ofdrw.core.text.TextCode;
import org.ofdrw.core.text.text.Weight;
import org.ofdrw.layout.element.*;
import org.ofdrw.layout.engine.ResManager;

import java.io.IOException;
import java.util.LinkedList;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 段落渲染器
 * 

* {@link org.ofdrw.layout.element.Paragraph} 的渲染器 * * @author 权观宇 * @since 2020-03-24 04:31:37 */ public class ParagraphRender implements Processor { /** * 执行段落渲染 * * @param pageLoc 页面在虚拟容器中绝对路径。 * @param layer 图片将要放置的图层 * @param resManager 资源管理器 * @param e 段落对象 * @param maxUnitID 最大元素ID提供器 * @throws RenderException 渲染发生错误 */ @Override public void render(ST_Loc pageLoc, CT_PageBlock layer, ResManager resManager, Div e, AtomicInteger maxUnitID) throws RenderException{ if (e instanceof Paragraph) { render(layer, resManager, (Paragraph) e, maxUnitID); } } /** * 将段落渲染到图层上 * * @param layer 图层 * @param resManager 资源管理器 * @param e 段落对象 * @param maxUnitID 对象ID提供者 */ public static void render(CT_PageBlock layer, ResManager resManager, Paragraph e, AtomicInteger maxUnitID) { if (e == null) { return; } LinkedList lines = e.getLines(); // 段落中没有任何内容,那么跳过不渲染 if (lines == null || lines.isEmpty()) { // 直接加入到虚拟页面的段落对象是经过预处理的,所以此处尝试预处理。 e.doPrepare(e.getWidth() + e.widthPlus()); lines = e.getLines(); if (lines == null || lines.isEmpty()) { // 如果还是没有行,那么是个空段落,跳过 return; } } // 可容纳元素的总高度 Double containerHeight = e.getHeight(); /* 每一行左上角坐标 */ double lineTopX = e.getX() + e.getMarginLeft() + e.getBorderLeft() + e.getPaddingLeft(); double offsetY = e.getY() + e.getMarginTop() + e.getBorderTop() + e.getPaddingTop(); // 已经写入的元素高度统计 double hCount = 0; // 渲染每一行文字 for (TxtLineBlock txtLine : lines) { // 行内的X偏移量为行开头 double offsetX; // 根据浮动方式确定起始字符坐标 switch (txtLine.getTextAlign()) { case right: offsetX = lineTopX + (txtLine.getLineMaxAvailableWidth() - txtLine.getWidth()); break; case center: offsetX = lineTopX + (txtLine.getLineMaxAvailableWidth() - txtLine.getWidth()) / 2; break; case left: default: offsetX = lineTopX; break; } // 一行内的所有Span的图元高度都为行高度(最高文字高度 + 行间距) double h = txtLine.getHeight(); if (hCount + h > containerHeight) { // 如果文字内容高度大于容纳文字的容器高度,那么将该部分内容舍弃,不渲染。 break; } // 遍历行内的每个Span for (Span s : txtLine.getInlineSpans()) { // 文字图元宽度 double w = s.blockSize().getWidth(); if (w == 0) { // 空行 continue; } if (s instanceof PlaceholderSpan) { // 忽略占位符的渲染只进行坐标偏移 offsetX += w; continue; } // 将字体加入到资源中 ST_ID id = null; try { id = resManager.addFont(s.getFont()); } catch (IOException ex) { throw new RenderException("渲染异常,字体复制失败:" + ex.getMessage(), ex); } // 新建字体对象 TextObject txtObj = new TextObject(maxUnitID.incrementAndGet()); ST_Box boundary = new ST_Box(offsetX, offsetY, w, h); txtObj.setBoundary(boundary) // 设置字体ID .setFont(id.ref()) // 设置字体大小 .setSize(s.getFontSize()); // 设置字体粗细 if (s.getWeight() != null) { txtObj.setWeight(s.getWeight()); } else if (s.isBold()) { txtObj.setWeight(Weight.W_800); } // 是否是斜体 if (s.isItalic()) { txtObj.setItalic(true); } // 是否填充,默认为true表示填充 if (!s.isFill()) { txtObj.setFill(false); } // 设置字体颜色,默认颜色为黑色 int[] color = s.getColor(); if (color != null && color.length >= 3) { txtObj.setFillColor(CT_Color.rgb(color)); } // 创建OFD文字定位对象 Double offset = txtLine.getMaxSpanHeight(); TextCode tcSTTxt = new TextCode() // 定位点位于文字的左下角,文字文字Y偏移量为该行最高文字的高度 .setCoordinate(0d, offset) .setContent(s.getText()); Double[] deltaX = s.getDeltaX(); if (deltaX.length > 0) { // 如果多余一个字符那么需要设置字符偏移量 tcSTTxt.setDeltaX(deltaX); } // 加入到字符对象中 txtObj.addTextCode(tcSTTxt); if (e.getOpacity() != null) { // 图元透明度 txtObj.setAlpha((int) (e.getOpacity() * 255)); } // 将文字对象加入到图层 layer.addPageBlock(txtObj); // 是否包含下划线 if (s.isUnderline()) { ST_ID underlineId = new ST_ID(maxUnitID.incrementAndGet()); // 构造下划线 double underlineOffset = offset + s.getUnderlineOffset(); double underlineWidth = s.getUnderlineWidth(); if (underlineWidth == 0) { // 0.05 比例系数为经验值 underlineWidth = s.getFontSize() * 0.05; } PathObject underline = drawUnderline(underlineId, boundary, color, underlineOffset, underlineWidth); if (e.getOpacity() != null) { // 图元透明度 underline.setAlpha((int) (e.getOpacity() * 255)); } // 加入到文字对象的上方 layer.addPageBlock(underline); } // 计算行内下一个图元的X坐标 offsetX += w; } offsetY += h; hCount += h; } } /** * 绘制文字的下划线 * * @param id 下划线ID * @param boundary 绘制下划线的区域 * @param color 下划线颜色 [R, G, B] * @param offset 在绘制区域内Y的偏移量 * @param width 下划线线宽 * @return 路径对象 */ private static PathObject drawUnderline(ST_ID id, ST_Box boundary, int[] color, double offset, double width) { PathObject res = new PathObject(id); if (color != null && color.length >= 3) { res.setStrokeColor(CT_Color.rgb(color)); } res.setBoundary(boundary) .setAbbreviatedData(new AbbreviatedData().M(0, offset).lineTo(boundary.getWidth(), offset)) .setLineWidth(width); return res; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy