重构代码,抽象成range,完成段落的重构
This commit is contained in:
parent
61001c9a46
commit
007da049a3
593
TSDocxToPdf.tsf
593
TSDocxToPdf.tsf
|
|
@ -1,418 +1,255 @@
|
||||||
type TSDocxToPdf = class
|
type TSDocxToPdf = class
|
||||||
uses TSColorToolKit, TSPdfEnumerations;
|
|
||||||
|
|
||||||
public
|
public
|
||||||
function Create(alias, file);
|
function Create(alias: string; file: string);
|
||||||
function SaveToFile(alias, file);
|
function Destroy();
|
||||||
function Transform();
|
function SaveToFile(alias: string; file: string): integer;
|
||||||
|
function Transform();
|
||||||
|
|
||||||
property Font read ReadFont;
|
function GetCurrentPage(): PdfPage;
|
||||||
function ReadFont();
|
function GetCurrentPoint(): Point;
|
||||||
|
function GetTempPath(image_path: string): string;
|
||||||
|
function GetPdf(): PdfFile;
|
||||||
|
function AddPage(sect_ware: TSSectWare): PdfPage;
|
||||||
|
|
||||||
|
property Font read ReadFont;
|
||||||
|
function ReadFont();
|
||||||
|
|
||||||
private
|
private
|
||||||
function Init();
|
function InitDocxComponents(alias: string; file: string);
|
||||||
function InitSectPr();
|
function InitTempPath(file: string);
|
||||||
function InitEncoder();
|
function InitPdfEncoder();
|
||||||
function InitPoint();
|
function InitSectWare();
|
||||||
function InitStyles();
|
function AllocateElementsToSectWare();
|
||||||
|
|
||||||
function TransformParagraph(paragraph);
|
function ResetCoordinates(sect_ware: TSSectWare);
|
||||||
function TransformDrawing(drawing);
|
function TransformParagraph(sect_ware: TSSectWare; paragraph: P);
|
||||||
function TransformTable(table);
|
function TransformTable(sect_ware: TSSectWare; table: Tbl);
|
||||||
|
|
||||||
function AddPage();
|
function PrintGrid(page: PdfPage; sect_ware: TSSectWare); // test
|
||||||
function CheckAndAddPage(offset);
|
|
||||||
function ResetCoordinates();
|
|
||||||
function CalcPagragraphPt(size, line);
|
|
||||||
function FloatN(R, N);
|
|
||||||
function ParagraphWordsToLine(ware);
|
|
||||||
function GetElementType(element);
|
|
||||||
function SetPageItalic(page, x, y); // 模拟倾斜[废弃]
|
|
||||||
|
|
||||||
// test用
|
|
||||||
function PrintGrid();
|
|
||||||
|
|
||||||
private
|
private
|
||||||
docx_components_; // Components@DOCX
|
pdf_: PdfFile;
|
||||||
styles_adapter_; // StylesAdapter@Docx
|
docx_components_: Components; // Components@DOCX
|
||||||
|
temp_path_: string; // 临时目录,用来存放临时文件
|
||||||
pdf_; // PdfFile
|
sect_ware_array_: array of TSSectWare; // 页面布局组件数组
|
||||||
point_; // Point
|
font_ware_: TSFontWare; // 字体部件
|
||||||
sect_;
|
current_page_: PdfPage;
|
||||||
base_size_; // 基准字体大小
|
page_array_: array of PdfPage;
|
||||||
font_ware_;
|
point_: TSPoint; // 定位坐标点
|
||||||
current_page_; // 当前page
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
type Point = class // 定位当前的位置
|
function TSDocxToPdf.Create(alias: string; file: string);
|
||||||
public
|
|
||||||
X;
|
|
||||||
Y;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TSDocxToPdf.Create(alias, file);
|
|
||||||
begin
|
begin
|
||||||
NameSpace "DOCX";
|
pdf_ := new PdfFile();
|
||||||
docx_components_ := new Components();
|
self.InitPdfEncoder();
|
||||||
[err, msg] := docx_components_.OpenFile(alias, file, nil);
|
self.InitDocxComponents(alias, file);
|
||||||
if err then raise "Create obejct 'TSDocxFile' failed.";
|
self.InitTempPath(file);
|
||||||
self.Init();
|
self.InitSectWare();
|
||||||
|
font_ware_ := new TSFontWare(pdf_);
|
||||||
|
current_page_ := nil;
|
||||||
|
page_array_ := array();
|
||||||
|
point_ := new TSPoint();
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TSDocxToPdf.Init();
|
function TSDocxToPdf.Destroy();
|
||||||
begin
|
begin
|
||||||
pdf_ := new PdfFile();
|
removeDir("", temp_path_);
|
||||||
self.InitStyles();
|
|
||||||
self.InitEncoder();
|
|
||||||
self.InitSectPr();
|
|
||||||
self.InitPoint();
|
|
||||||
self.AddPage();
|
|
||||||
base_size_ := integer(sect_.DocGrid.LinePitch / 1.38, 2);
|
|
||||||
font_ware_ := new TSFontWare(pdf_);
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TSDocxToPdf.InitEncoder();
|
function TSDocxToPdf.SaveToFile(alias: string; file: string): integer;
|
||||||
begin
|
begin
|
||||||
pdf_.UseCNSFonts();
|
return pdf_.SaveToFile(alias, file);
|
||||||
pdf_.UseCNSEncodings();
|
|
||||||
// pdf_.UseUTFEncodings();
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TSDocxToPdf.InitSectPr();
|
|
||||||
begin
|
|
||||||
document := docx_components_.Document;
|
|
||||||
document.Deserialize();
|
|
||||||
sect_ := document.Body.SectPr;
|
|
||||||
// 装饰器进行转换
|
|
||||||
sect_ := new SectPrUnitDecorator(sect_);
|
|
||||||
sect_.PgSz.Orient := sect_.PgSz.Orient ? "portrait" : "landscape";
|
|
||||||
|
|
||||||
// println("LinePitch = {}, Type = {}", sect_.DocGrid.LinePitch, sect_.DocGrid.Type);
|
|
||||||
// println("Width = {}, Height = {}", sect_.PgSz.W, sect_.PgSz.H);
|
|
||||||
// println("Top = {}, Right = {}, Bottom = {}, Left = {}, Header = {}, Footer = {}\n",
|
|
||||||
// sect_.PgMar.Top, sect_.PgMar.Right, sect_.PgMar.Bottom, sect_.PgMar.Left, sect_.PgMar.Header, sect_.PgMar.Footer);
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TSDocxToPdf.InitPoint();
|
|
||||||
begin
|
|
||||||
// 起始y的位置应为max(top, header) + 行距
|
|
||||||
point_ := new Point();
|
|
||||||
self.ResetCoordinates();
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TSDocxToPdf.InitStyles();
|
|
||||||
begin
|
|
||||||
styles := docx_components_.Styles;
|
|
||||||
styles.Deserialize();
|
|
||||||
styles_adapter_ := new StylesAdapter(styles);
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TSDocxToPdf.AddPage();
|
|
||||||
begin
|
|
||||||
current_page_ := pdf_.AddPage();
|
|
||||||
current_page_.SetWidth(sect_.PgSz.W);
|
|
||||||
current_page_.SetHeight(sect_.PgSz.H);
|
|
||||||
self.PrintGrid();
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TSDocxToPdf.ResetCoordinates();
|
|
||||||
begin
|
|
||||||
point_.X := sect_.PgMar.Left;
|
|
||||||
point_.Y := sect_.PgSz.H - sect_.PgMar.Top;
|
|
||||||
end;
|
|
||||||
|
|
||||||
///返回:err
|
|
||||||
function TSDocxToPdf.SaveToFile(alias, file);
|
|
||||||
begin
|
|
||||||
return pdf_.SaveToFile(alias, file);
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TSDocxToPdf.PrintGrid(); // test用
|
|
||||||
begin
|
|
||||||
page := current_page_;
|
|
||||||
|
|
||||||
i := 0;
|
|
||||||
while true do
|
|
||||||
begin
|
|
||||||
y := point_.Y - i * sect_.DocGrid.LinePitch;
|
|
||||||
if y <= sect_.PgMar.Bottom then break;
|
|
||||||
page.SetLineWidth(0.05);
|
|
||||||
page.SetGrayStroke(0.75);
|
|
||||||
page.MoveTo(sect_.PgMar.Left, y);
|
|
||||||
page.LineTo(sect_.PgSz.W- sect_.PgMar.Right, y);
|
|
||||||
page.Stroke();
|
|
||||||
i++;
|
|
||||||
end
|
|
||||||
|
|
||||||
x1 := sect_.PgMar.Left;
|
|
||||||
y1 := sect_.PgSz.H - sect_.PgMar.Top;
|
|
||||||
x2 := sect_.PgSz.W - sect_.PgMar.Right;
|
|
||||||
y2 := y1;
|
|
||||||
x3 := x1;
|
|
||||||
y3 := sect_.PgMar.Bottom;
|
|
||||||
x4 := x2;
|
|
||||||
y4 := y3;
|
|
||||||
page.SetLineWidth(0.05);
|
|
||||||
page.SetGrayStroke(0.5);
|
|
||||||
page.MoveTo(x1, y1);
|
|
||||||
page.LineTo(x2, y2);
|
|
||||||
page.Stroke();
|
|
||||||
page.MoveTo(x1, y1);
|
|
||||||
page.LineTo(x3, y3);
|
|
||||||
page.Stroke();
|
|
||||||
page.MoveTo(x2, y2);
|
|
||||||
page.LineTo(x4, y4);
|
|
||||||
page.Stroke();
|
|
||||||
page.MoveTo(x3, y3);
|
|
||||||
page.LineTo(x4, y4);
|
|
||||||
page.Stroke();
|
|
||||||
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TSDocxToPdf.GetElementType(element);
|
|
||||||
begin
|
|
||||||
if element.LocalName = 'p' then return 1;
|
|
||||||
if element.LocalName = 'tbl' then return 3;
|
|
||||||
return 0;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TSDocxToPdf.Transform();
|
function TSDocxToPdf.Transform();
|
||||||
begin
|
begin
|
||||||
elements := docx_components_.Document.Body.Elements();
|
prev := nil;
|
||||||
for i:=0 to length(elements)-1 do
|
for _,sect_ware in sect_ware_array_ do
|
||||||
// for i:=0 to 2 do
|
begin
|
||||||
begin
|
if prev <> sect_ware then
|
||||||
println("i = {}", i);
|
begin
|
||||||
case self.GetElementType(elements[i]) of
|
self.AddPage(sect_ware);
|
||||||
1: self.TransformParagraph(elements[i]); // 普通段落
|
prev := sect_ware;
|
||||||
2: self.TransformDrawing(elements[i]); // 图片段落
|
end
|
||||||
3: self.TransformTable(elements[i]); // 表格
|
elements := sect_ware.Elements();
|
||||||
end;
|
for _,element in elements do
|
||||||
end
|
begin
|
||||||
|
if element.LocalName = "p" then self.TransformParagraph(sect_ware, element);
|
||||||
|
else if element.LocalName = "tbl" then self.TransformTable(sect_ware, element);
|
||||||
|
end
|
||||||
|
end
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TSDocxToPdf.CheckAndAddPage(offset);
|
function TSDocxToPdf.GetCurrentPage(): PdfPage;
|
||||||
begin
|
begin
|
||||||
offset := ifnil(offset) ? 0 : offset;
|
return current_page_;
|
||||||
if point_.Y - offset <= sect_.PgMar.Bottom then
|
|
||||||
begin
|
|
||||||
self.AddPage();
|
|
||||||
self.ResetCoordinates();
|
|
||||||
self.PrintGrid();
|
|
||||||
return true;
|
|
||||||
end
|
|
||||||
return false;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TSDocxToPdf.ParagraphWordsToLine(ware);
|
function TSDocxToPdf.GetCurrentPoint(): Point;
|
||||||
begin
|
begin
|
||||||
self.CheckAndAddPage();
|
return point_;
|
||||||
page := current_page_;
|
|
||||||
lines := array();
|
|
||||||
x := point_.X + ware.Paragraph.PPr.Ind.FirstLine;
|
|
||||||
y := point_.Y;
|
|
||||||
max_size := 0;
|
|
||||||
|
|
||||||
i := 0;
|
|
||||||
begin_index := 0;
|
|
||||||
words := ware.GetWords();
|
|
||||||
while i <= length(words)-1 do
|
|
||||||
begin
|
|
||||||
[word, rpr] := words[i];
|
|
||||||
if rpr.Sz.Val > max_size then
|
|
||||||
max_size := rpr.Sz.Val;
|
|
||||||
|
|
||||||
font_obj := font_ware_.GetFont(rpr.RFonts.EastAsia, rpr.B, rpr.I);
|
|
||||||
lines[i]["page"] := page;
|
|
||||||
lines[i]["font"] := font_obj;
|
|
||||||
lines[i]["word"] := word;
|
|
||||||
lines[i]["rpr"] := rpr;
|
|
||||||
lines[i]["x"] := x;
|
|
||||||
page.SetFontAndSize(font_obj, rpr.Sz.Val);
|
|
||||||
w := page.TextWidth(word);
|
|
||||||
// println("word = {}, x = {}, w = {}, sz = {}", word, x, w, rpr.Sz.Val);
|
|
||||||
x += w;
|
|
||||||
|
|
||||||
if ware.Paragraph.PPr.AutoSpaceDN and i < length(words)-1 then
|
|
||||||
begin
|
|
||||||
current_len := length(word);
|
|
||||||
next_len := length(words[i+1][0]);
|
|
||||||
if (current_len = 1 and next_len >= 2) or (current_len >= 2 and next_len = 1) then
|
|
||||||
begin
|
|
||||||
cord := current_len = 1 ? ord(word) : ord(words[i+1][0]);
|
|
||||||
if cord >= 48 and cord <= 57 then
|
|
||||||
x += rpr.Sz.Val * 0.27;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if ware.Paragraph.PPr.AutoSpaceDE and i < length(words)-1 then
|
|
||||||
begin
|
|
||||||
current_len := length(word);
|
|
||||||
next_len := length(words[i+1][0]);
|
|
||||||
if (current_len = 1 and next_len >= 2) or (current_len >= 2 and next_len = 1) then
|
|
||||||
begin
|
|
||||||
cord := current_len = 1 ? ord(word) : ord(words[i+1][0]);
|
|
||||||
if (cord >= 97 and cord <= 122) or (cord >= 65 and cord <= 90) then
|
|
||||||
x += rpr.Sz.Val * 0.27;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
line_pt := self.CalcPagragraphPt(max_size, ware.Paragraph.PPr.Spacing.Line);
|
|
||||||
offset := (line_pt - max_size) / 2;
|
|
||||||
if self.CheckAndAddPage(line_pt) then // 换页,x不变,y变
|
|
||||||
begin
|
|
||||||
page := current_page_;
|
|
||||||
x := point_.X;
|
|
||||||
y := point_.Y;
|
|
||||||
i := begin_index;
|
|
||||||
max_size := 0;
|
|
||||||
continue;
|
|
||||||
end
|
|
||||||
if x >= sect_.PgSz.W - sect_.PgMar.Right then // 换行
|
|
||||||
begin
|
|
||||||
y := y - offset - max_size + max_size / 5;
|
|
||||||
for j:=begin_index to i-1 do
|
|
||||||
lines[j]["y"] := y;
|
|
||||||
|
|
||||||
// 重置参数
|
|
||||||
begin_index := i;
|
|
||||||
max_size := 0;
|
|
||||||
x := point_.X;
|
|
||||||
y := point_.Y - line_pt;
|
|
||||||
point_.Y := y;
|
|
||||||
|
|
||||||
// 换页
|
|
||||||
if self.CheckAndAddPage() then
|
|
||||||
begin
|
|
||||||
page := current_page_;
|
|
||||||
x := point_.X;
|
|
||||||
y := point_.Y;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else begin
|
|
||||||
i++;
|
|
||||||
if i > length(words)-1 then // 到了末尾仍未换行
|
|
||||||
begin
|
|
||||||
y := y - offset - max_size + max_size / 5;
|
|
||||||
for j:=begin_index to length(words)-1 do
|
|
||||||
lines[j]["y"] := y;
|
|
||||||
point_.Y -= line_pt;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return lines;
|
|
||||||
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TSDocxToPdf.SetPageItalic(page, x, y);
|
function TSDocxToPdf.GetTempPath(image_path: string): string;
|
||||||
begin
|
begin
|
||||||
angle := 130;
|
return temp_path_ + extractFileName(image_path);
|
||||||
rad := angle / 180 / Pi();
|
|
||||||
page.SetTextMatrix(1, 0, tan(rad), 1, x, y);
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TSDocxToPdf.TransformParagraph(paragraph);
|
function TSDocxToPdf.GetPdf(): PdfFile;
|
||||||
begin
|
begin
|
||||||
// 1. 字体大小
|
return pdf_;
|
||||||
// 2. 字体颜色
|
|
||||||
// 3. 字体斜体
|
|
||||||
// 4. 字体粗体
|
|
||||||
// 5. 首行间距
|
|
||||||
// 6. 字符间距
|
|
||||||
|
|
||||||
// 7. 下划线
|
|
||||||
// 8. 删除线
|
|
||||||
// 9. 上下标
|
|
||||||
// 10. 对齐方式
|
|
||||||
paragraph_ware := new TSParagraphWare(docx_components_, styles_adapter_, paragraph);
|
|
||||||
paragraph_ware.Do();
|
|
||||||
|
|
||||||
// 将段落中间件的每一个字符序列化成每一行
|
|
||||||
lines := self.ParagraphWordsToLine(paragraph_ware);
|
|
||||||
// 开始写入pdf
|
|
||||||
for i:=0 to length(lines)-1 do
|
|
||||||
begin
|
|
||||||
line := lines[i];
|
|
||||||
word := line["word"];
|
|
||||||
rpr := line["rpr"];
|
|
||||||
[r, g, b] := array(0, 0, 0);
|
|
||||||
if rpr.Color.Val then [r, g, b] := TSColorToolKit.HexToRGB(rpr.Color.Val);
|
|
||||||
page := line["page"];
|
|
||||||
page.SetRGBFill(r / 255, g / 255, b / 255);
|
|
||||||
page.SetFontAndSize(line["font"], rpr.Sz.Val);
|
|
||||||
|
|
||||||
x := line["x"];
|
|
||||||
y := line["y"];
|
|
||||||
if draw_bold then
|
|
||||||
begin
|
|
||||||
// 1. 调整偏移位置重复绘制 -- 当前参数的效果不太好
|
|
||||||
// z := 0.0005 * sqrt(x*x + y*y) * sqrt(2) / 2;
|
|
||||||
// left_x := x - z; // 左下角x位置
|
|
||||||
// left_y := y - z; // 左下角y位置
|
|
||||||
// right_x := x + z; // 右上角x位置
|
|
||||||
// right_y := y + z; // 右上角y位置
|
|
||||||
// offset := word.WordProperty.Size / 1000; // 每次偏移千分之一
|
|
||||||
// println("z = {}", z);
|
|
||||||
// println("x = {}, y = {}, offset = {}", x, y, offset);
|
|
||||||
// println("left_x = {}, left_y = {}, right_x = {}, left_y = {}\n", left_x, left_y, right_x, right_x);
|
|
||||||
// while left_x <= right_x and left_y <= right_y do
|
|
||||||
// begin
|
|
||||||
// if draw_italic then self.SetPageItalic(page, left_x, left_y);
|
|
||||||
// page.TextOut(left_x, left_y, word.Word);
|
|
||||||
// left_x += offset;
|
|
||||||
// left_y += right_y;
|
|
||||||
// end
|
|
||||||
|
|
||||||
// 2. 调整字体大小,x,y位置重复绘制
|
|
||||||
multi := 1.030;
|
|
||||||
size := word.WordProperty.Size;
|
|
||||||
target_size := size * multi;
|
|
||||||
offset := size * 0.01;
|
|
||||||
size /= multi;
|
|
||||||
while size <= target_size do
|
|
||||||
begin
|
|
||||||
page.SetFontAndSize(font, size);
|
|
||||||
page.beginText();
|
|
||||||
if draw_italic then self.SetPageItalic(page, x, y);
|
|
||||||
page.TextOut(x, y, word.Word);
|
|
||||||
page.endText();
|
|
||||||
size += offset;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else begin
|
|
||||||
page.beginText();
|
|
||||||
page.TextOut(x, y, word);
|
|
||||||
page.endText();
|
|
||||||
end
|
|
||||||
|
|
||||||
page.SetRGBFill(0, 0, 0);
|
|
||||||
end
|
|
||||||
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TSDocxToPdf.TransformDrawing(drawing);
|
|
||||||
begin
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TSDocxToPdf.TransformTable(table);
|
|
||||||
begin
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TSDocxToPdf.CalcPagragraphPt(size, line);
|
|
||||||
begin
|
|
||||||
if ifnil(line) then line := 12;
|
|
||||||
lines := self.FloatN(line / 12, 2);
|
|
||||||
multi := Ceil(size / base_size_);
|
|
||||||
return sect_.DocGrid.LinePitch * multi;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TSDocxToPdf.FloatN(r, n);
|
|
||||||
begin
|
|
||||||
return Round(r * IntPower(10, n)) / IntPower(10, n);
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TSDocxToPdf.ReadFont();
|
function TSDocxToPdf.ReadFont();
|
||||||
begin
|
begin
|
||||||
return font_ware_;
|
return font_ware_;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TSDocxToPdf.InitPdfEncoder();
|
||||||
|
begin
|
||||||
|
pdf_.UseCNSFonts();
|
||||||
|
pdf_.UseCNSEncodings();
|
||||||
|
// pdf_.UseUTFEncodings();
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TSDocxToPdf.InitDocxComponents(alias: string; file: string);
|
||||||
|
begin
|
||||||
|
namespace "DOCX";
|
||||||
|
docx_components_ := new Components();
|
||||||
|
[err, msg] := docx_components_.OpenFile(alias, file, nil);
|
||||||
|
if err then raise "Create obejct 'TSDocxFile' failed.";
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TSDocxToPdf.InitTempPath(file: string);
|
||||||
|
begin
|
||||||
|
path := format("%s_%s", extractFileName(file), formatDatetime("YYYYMMDDHHNNSSZZZ", now()));
|
||||||
|
temp_path_ := format("%s/funcext/WordToPdf/temp/%s/", extractFileDir(sysExecName()), path);
|
||||||
|
createDir("", temp_path_);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TSDocxToPdf.InitSectWare();
|
||||||
|
begin
|
||||||
|
document := docx_components_.Document;
|
||||||
|
document.Deserialize();
|
||||||
|
sect_ware_array_ := array();
|
||||||
|
self.AllocateElementsToSectWare();
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TSDocxToPdf.AllocateElementsToSectWare();
|
||||||
|
begin
|
||||||
|
elements := docx_components_.Document.Body.Elements();
|
||||||
|
ware := new TSSectWare();
|
||||||
|
fp := function(ware, sect);
|
||||||
|
begin
|
||||||
|
sect := new SectPrUnitDecorator(sect);
|
||||||
|
sect.PgSz.Orient := sect.PgSz.Orient ? "portrait" : "landscape";
|
||||||
|
ware.SectPr := sect;
|
||||||
|
ware.Do();
|
||||||
|
end
|
||||||
|
for i:=0 to length(elements)-1 do
|
||||||
|
begin
|
||||||
|
element := elements[i];
|
||||||
|
ware.Elements[length(ware.Elements)] := element;
|
||||||
|
if element.LocalName = "p" and ifObj(element.PPr.SectPr.XmlNode) then
|
||||||
|
begin
|
||||||
|
##fp(ware, element.PPr.SectPr);
|
||||||
|
sect_ware_array_[length(sect_ware_array_)] := ware;
|
||||||
|
ware := new TSSectWare();
|
||||||
|
end
|
||||||
|
else if element.LocalName = "sectPr" and i = length(elements)-1 then
|
||||||
|
begin
|
||||||
|
##fp(ware, element);
|
||||||
|
sect_ware_array_[length(sect_ware_array_)] := ware;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
println("sect_ware_array_ = {}", sect_ware_array_);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TSDocxToPdf.AddPage(sect_ware: TSSectWare): PdfPage;
|
||||||
|
begin
|
||||||
|
current_page_ := pdf_.AddPage();
|
||||||
|
current_page_.SetWidth(sect_ware.SectPr.PgSz.W);
|
||||||
|
current_page_.SetHeight(sect_ware.SectPr.PgSz.H);
|
||||||
|
self.ResetCoordinates(sect_ware);
|
||||||
|
page_array_[length(page_array_)] := current_page_;
|
||||||
|
|
||||||
|
{$DEFINE WordToPdfTEST}
|
||||||
|
{$IFDEF WordToPdfTEST}
|
||||||
|
self.PrintGrid(current_page_, sect_ware);
|
||||||
|
{$ENDIF}
|
||||||
|
|
||||||
|
return current_page_;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TSDocxToPdf.ResetCoordinates(sect_ware: TSSectWare);
|
||||||
|
begin
|
||||||
|
point_.X := sect_ware.SectPr.PgMar.Left;
|
||||||
|
point_.Y := sect_ware.SectPr.PgSz.H - max(sect_ware.SectPr.PgMar.Top, sect_ware.SectPr.PgMar.Header);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TSDocxToPdf.PrintGrid(page: PdfPage; sect_ware: TSSectWare);
|
||||||
|
begin
|
||||||
|
i := 0;
|
||||||
|
while true do
|
||||||
|
begin
|
||||||
|
y := point_.Y - i * sect_ware.SectPr.DocGrid.LinePitch;
|
||||||
|
if y <= sect_ware.SectPr.PgMar.Bottom then break;
|
||||||
|
page.SetLineWidth(0.05);
|
||||||
|
page.SetGrayStroke(0.75);
|
||||||
|
page.MoveTo(sect_ware.SectPr.PgMar.Left, y);
|
||||||
|
page.LineTo(sect_ware.SectPr.PgSz.W- sect_ware.SectPr.PgMar.Right, y);
|
||||||
|
page.Stroke();
|
||||||
|
i++;
|
||||||
|
end
|
||||||
|
|
||||||
|
x1 := sect_ware.SectPr.PgMar.Left;
|
||||||
|
y1 := sect_ware.SectPr.PgSz.H - sect_ware.SectPr.PgMar.Top;
|
||||||
|
x2 := sect_ware.SectPr.PgSz.W - sect_ware.SectPr.PgMar.Right;
|
||||||
|
y2 := y1;
|
||||||
|
x3 := x1;
|
||||||
|
y3 := sect_ware.SectPr.PgMar.Bottom;
|
||||||
|
x4 := x2;
|
||||||
|
y4 := y3;
|
||||||
|
page.SetLineWidth(0.05);
|
||||||
|
page.SetGrayStroke(0.5);
|
||||||
|
page.MoveTo(x1, y1);
|
||||||
|
page.LineTo(x2, y2);
|
||||||
|
page.Stroke();
|
||||||
|
page.MoveTo(x1, y1);
|
||||||
|
page.LineTo(x3, y3);
|
||||||
|
page.Stroke();
|
||||||
|
page.MoveTo(x2, y2);
|
||||||
|
page.LineTo(x4, y4);
|
||||||
|
page.Stroke();
|
||||||
|
page.MoveTo(x3, y3);
|
||||||
|
page.LineTo(x4, y4);
|
||||||
|
page.Stroke();
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TSDocxToPdf.TransformParagraph(sect_ware: TSSectWare; paragraph: P);
|
||||||
|
begin
|
||||||
|
w := sect_ware.SectPr.PgSz.W - sect_ware.SectPr.PgMar.Right - sect_ware.SectPr.PgMar.Left;
|
||||||
|
range := new TSPdfParagraphRange(self, docx_components_, sect_ware, paragraph);
|
||||||
|
range.X := point_.X;
|
||||||
|
range.Y := point_.Y;
|
||||||
|
range.W := w;
|
||||||
|
range.H := 0;
|
||||||
|
range.Calc();
|
||||||
|
range.Do();
|
||||||
|
point_.Y := range.Y;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TSDocxToPdf.TransformTable(sect_ware: TSSectWare; table: Tbl);
|
||||||
|
begin
|
||||||
|
return;
|
||||||
|
w := sect_ware.SectPr.PgSz.W - sect_ware.SectPr.PgMar.Right - sect_ware.SectPr.PgMar.Left;
|
||||||
|
range := new TSPdfTableRange(self, docx_components_, sect_ware, table);
|
||||||
|
range.X := point_.X;
|
||||||
|
range.Y := point_.Y;
|
||||||
|
range.W := w;
|
||||||
|
range.H := 0;
|
||||||
|
range.Calc();
|
||||||
|
range.Do();
|
||||||
|
point_.Y := range.Y;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
type TSPdfAbstractRange = class
|
||||||
|
public
|
||||||
|
function Do();virtual;
|
||||||
|
public
|
||||||
|
X: real;
|
||||||
|
Y: real; // range的起始坐标(x,y)
|
||||||
|
W: real; // range的宽度
|
||||||
|
H: real; // range的高度
|
||||||
|
|
||||||
|
end;
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
type TSPdfImageRange = class(TSPdfAbstractRange)
|
||||||
|
public
|
||||||
|
function Do();override;
|
||||||
|
public
|
||||||
|
Page: PdfPage;
|
||||||
|
Image: PdfImage;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TSPdfImageRange.Do();
|
||||||
|
begin
|
||||||
|
println("image = {}, x = {}, y = {}, w = {}, h = {}", image, x, y, w, h);
|
||||||
|
self.Page.DrawImage(self.Image, self.X, self.Y, self.W, self.H);
|
||||||
|
|
||||||
|
{$DEFINE WordToPdfTEST}
|
||||||
|
{$IFDEF WordToPdfTEST}
|
||||||
|
// Page.SetLineWidth(0.5);
|
||||||
|
// Page.SetGrayStroke(0.5);
|
||||||
|
// Page.MoveTo(0, self.Y);
|
||||||
|
// Page.LineTo(90, self.Y);
|
||||||
|
// Page.Stroke();
|
||||||
|
self.Page.SetLineWidth(0.1);
|
||||||
|
self.Page.SetGrayStroke(0.5);
|
||||||
|
self.Page.Rectangle(0, Y, 900, H);
|
||||||
|
self.Page.Stroke();
|
||||||
|
{$ENDIF}
|
||||||
|
end;
|
||||||
|
|
@ -0,0 +1,353 @@
|
||||||
|
type TSPdfParagraphRange = class(TSPdfAbstractRange)
|
||||||
|
public
|
||||||
|
function Create(docx_to_pdf: TSDocxToPdf; components: Components; sect_ware: TSSectWare; paragraph: P);
|
||||||
|
function Calc();
|
||||||
|
function Do();override;
|
||||||
|
function SetExtraStyleId(style_id: string);
|
||||||
|
|
||||||
|
private
|
||||||
|
function SetPPr(var ppr: PPr);
|
||||||
|
function SetPPrByStyleId(var ppr: PPr; style_id: string);
|
||||||
|
function SetRPr(var rpr; ppr: PPr);
|
||||||
|
function SetRPrByStyleId(var rpr: RPr; style_id: string);
|
||||||
|
function SetLvlText();
|
||||||
|
function GetImageFileType(data: binary): string;
|
||||||
|
function GetParagraphLineSpace(size: real; line: integer): real;
|
||||||
|
function RangesToLines(ppr: PPr): tableArray;
|
||||||
|
function CheckAndAddPage(y: real; offset: real): boolean;
|
||||||
|
function GetUtf8CharLength(byte: string): integer;
|
||||||
|
function RToTextRange(r: R; ppr: PPr);
|
||||||
|
function SplitTextToTextRange(text: string; rpr: RPr);
|
||||||
|
function RToDrawingRange(r: R; ppr: PPr);
|
||||||
|
function SetLinesAlignment(lines_range_array: tableArray; ppr: PPr);
|
||||||
|
|
||||||
|
private
|
||||||
|
docx_to_pdf_: TSDocxToPdf;
|
||||||
|
docx_components_: Components;
|
||||||
|
sect_ware_: TSSectWare;
|
||||||
|
paragraph_: P;
|
||||||
|
extra_style_id_: string;
|
||||||
|
range_array_: array of TSPdfAbstractRange;
|
||||||
|
page_: PdfPage;
|
||||||
|
point_: TSPoint;
|
||||||
|
lines_range_array_: tableArray;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TSPdfParagraphRange.Create(docx_to_pdf: TSDocxToPdf; components: Components; sect_ware: TSSectWare; paragraph: P);
|
||||||
|
begin
|
||||||
|
docx_to_pdf_ := docx_to_pdf;
|
||||||
|
docx_components_ := Components;
|
||||||
|
sect_ware_ := sect_ware;
|
||||||
|
paragraph_ := paragraph;
|
||||||
|
extra_style_id_ := "";
|
||||||
|
page_ := docx_to_pdf_.GetCurrentPage();
|
||||||
|
range_array_ := array();
|
||||||
|
point_ := new TSPoint(); // 动态记录段落的坐标位置
|
||||||
|
lines_range_array_ := array();
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TSPdfParagraphRange.Calc(): tableArray;
|
||||||
|
begin
|
||||||
|
self.SetPPr(paragraph_.PPr);
|
||||||
|
self.SetLvlText();
|
||||||
|
ppr := new PPrUnitDecorator(paragraph_.PPr);
|
||||||
|
// 根据段落的间距确定新的坐标
|
||||||
|
self.X += ppr.Ind.Left;
|
||||||
|
self.W := self.W - ppr.Ind.Left - ppr.Ind.Right;
|
||||||
|
point_.X := self.X;
|
||||||
|
point_.Y := self.Y;
|
||||||
|
self.CheckAndAddPage(point_.Y, ppr.Spacing.Before);
|
||||||
|
point_.Y -= ppr.Spacing.Before;
|
||||||
|
rs := paragraph_.Rs();
|
||||||
|
if length(rs) = 0 then
|
||||||
|
begin
|
||||||
|
line_space := self.GetParagraphLineSpace(ppr.RPr.Sz.Val, ppr.Spacing.Line);
|
||||||
|
if not self.H then self.H := ppr.Spacing.After + line_space;
|
||||||
|
point_.Y -= self.H;
|
||||||
|
end
|
||||||
|
else begin
|
||||||
|
for _, r in rs do
|
||||||
|
begin
|
||||||
|
self.SetRPr(r.RPr, paragraph_.PPr);
|
||||||
|
if r.Br.Type = "page" then
|
||||||
|
self.CheckAndAddPage(sect_ware_.SectPr.PgMar.Bottom, 1);
|
||||||
|
else if ifObj(r.Drawing.XmlNode) then self.RToDrawingRange(r, ppr);
|
||||||
|
else self.RToTextRange(r, ppr);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
self.RangesToLines(ppr);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TSPdfParagraphRange.Do();
|
||||||
|
begin
|
||||||
|
for _,line_range in lines_range_array_ do
|
||||||
|
for _,range in line_range do
|
||||||
|
range.Do();
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TSPdfParagraphRange.SetExtraStyleId(style_id: string);
|
||||||
|
begin
|
||||||
|
extra_style_id_ := style_id;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TSPdfParagraphRange.RangesToLines(ppr: PPr);
|
||||||
|
begin
|
||||||
|
lines_range_array_ := array();
|
||||||
|
i := 0;
|
||||||
|
max_size := 0;
|
||||||
|
max_y := 0;
|
||||||
|
line_range := array();
|
||||||
|
total_height := 0;
|
||||||
|
while i <= length(range_array_)-1 do
|
||||||
|
begin
|
||||||
|
range := range_array_[i];
|
||||||
|
if i = 0 then point_.X += ppr.Ind.FirstLine;
|
||||||
|
if range is class(TSPdfTextRange) and range.RPr.Sz.Val > max_size then
|
||||||
|
max_size := range.RPr.Sz.Val;
|
||||||
|
if range.H > max_y then max_y := range.H;
|
||||||
|
line_space := self.GetParagraphLineSpace(max_size, ppr.Spacing.Line);
|
||||||
|
if self.CheckAndAddPage(point_.Y, max(line_space, range.H)) then
|
||||||
|
total_height += point_.Y - sect_ware_.SectPr.PgMar.Bottom;
|
||||||
|
range.X := point_.X - range.X;
|
||||||
|
if_newline := point_.X + range.W - self.X > self.W + 1e-6;
|
||||||
|
if if_newline and range.W < self.W then
|
||||||
|
begin
|
||||||
|
offset := line_space > max_y ? (line_space - max_size) / 2 + max_size - max_size / 5 : max_y;
|
||||||
|
for _,item in line_range do
|
||||||
|
begin
|
||||||
|
item.Page := page_;
|
||||||
|
item.Y := point_.Y - offset;
|
||||||
|
end
|
||||||
|
lines_range_array_[length(lines_range_array_)] := line_range;
|
||||||
|
line_range := array();
|
||||||
|
max_value := max(line_space, max_y);
|
||||||
|
max_size := 0;
|
||||||
|
max_y := 0;
|
||||||
|
total_height += max_value;
|
||||||
|
point_.Y -= max_value;
|
||||||
|
point_.X := self.X;
|
||||||
|
continue;
|
||||||
|
end
|
||||||
|
point_.X += range.W;
|
||||||
|
line_range[length(line_range)] := range;
|
||||||
|
i++;
|
||||||
|
if i = length(range_array_) then
|
||||||
|
begin
|
||||||
|
offset := line_space > max_y ? (line_space - max_size) / 2 + max_size - max_size / 5 : max_y;
|
||||||
|
for _,item in line_range do
|
||||||
|
begin
|
||||||
|
item.Page := page_;
|
||||||
|
item.Y := point_.Y - offset;
|
||||||
|
end
|
||||||
|
lines_range_array_[length(lines_range_array_)] := line_range;
|
||||||
|
max_value := max(line_space, max_y);
|
||||||
|
total_height += max_value;
|
||||||
|
point_.Y -= max_value;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
// self.SetLinesAlignment(lines_range_array, ppr);
|
||||||
|
if not self.H then self.H := total_height;
|
||||||
|
self.Y := point_.Y;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TSPdfParagraphRange.SetLinesAlignment(lines_range_array: tableArray; ppr: PPr);
|
||||||
|
begin
|
||||||
|
if length(lines_range_array) = 0 then return;
|
||||||
|
idx := length(lines_range_array)-1;
|
||||||
|
line := lines_range_array[idx];
|
||||||
|
offset := 0;
|
||||||
|
case ppr.Jc.Val of
|
||||||
|
"center":
|
||||||
|
begin
|
||||||
|
first := line[0];
|
||||||
|
last := line[length(line)-1];
|
||||||
|
offset := (self.W - last.X + first.X - last.W) / 2;
|
||||||
|
end
|
||||||
|
"right":
|
||||||
|
begin
|
||||||
|
first := line[0];
|
||||||
|
last := line[length(line)-1];
|
||||||
|
offset := self.W - last.X + first.X - last.W;
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
if offset then
|
||||||
|
for i:=0 to length(line)-1 do
|
||||||
|
line[i].X += offset;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TSPdfParagraphRange.CheckAndAddPage(y: real; offset: real): boolean;
|
||||||
|
begin
|
||||||
|
if y - offset < sect_ware_.SectPr.PgMar.Bottom then
|
||||||
|
begin
|
||||||
|
page_ := docx_to_pdf_.AddPage(sect_ware_);
|
||||||
|
point := docx_to_pdf_.GetCurrentPoint();
|
||||||
|
point_.Y := point.Y;
|
||||||
|
page_array_ := array(page_);
|
||||||
|
return true;
|
||||||
|
end
|
||||||
|
return false;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TSPdfParagraphRange.GetUtf8CharLength(byte: string): integer;
|
||||||
|
begin
|
||||||
|
if (_and(ord(byte), 0b10000000)) = 0 then
|
||||||
|
return 1;
|
||||||
|
else if (_and(ord(byte), 0b11100000)) = 0b11000000 then
|
||||||
|
return 2;
|
||||||
|
else if (_and(ord(byte), 0b11110000)) = 0b11100000 then
|
||||||
|
return 3;
|
||||||
|
else if (_and(ord(byte), 0b11111000)) = 0b11110000 then
|
||||||
|
return 4;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TSPdfParagraphRange.RToTextRange(r: R; ppr: PPr);
|
||||||
|
begin
|
||||||
|
rpr := new RPrUnitDecorator(r.RPr);
|
||||||
|
text := r.T.Text;
|
||||||
|
if ifString(text) then self.SplitTextToTextRange(text, rpr);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TSPdfParagraphRange.SplitTextToTextRange(text: string; rpr: RPr);
|
||||||
|
begin
|
||||||
|
pos := 1;
|
||||||
|
while pos <= length(text) do
|
||||||
|
begin
|
||||||
|
num := self.GetUtf8CharLength(text[pos]);
|
||||||
|
word := text[pos : pos+num-1];
|
||||||
|
word := utf8ToAnsi(word);
|
||||||
|
pos += num;
|
||||||
|
font_name := rpr.RFonts.EastAsia ? rpr.RFonts.EastAsia : rpr.RFonts.Ascii;
|
||||||
|
font_obj := docx_to_pdf_.Font.GetFont(font_name, 0, 0);
|
||||||
|
if not rpr.Sz.Val then rpr.Sz.Val := rpr.SzCs.Val ? rpr.SzCs.Val : docx_to_pdf_.Font.GetDefaultSz();
|
||||||
|
page_.SetFontAndSize(font_obj, rpr.Sz.Val);
|
||||||
|
word_width := page_.TextWidth(word);
|
||||||
|
text_range := new TSPdfTextRange();
|
||||||
|
text_range.RPr := rpr;
|
||||||
|
text_range.Text := word;
|
||||||
|
text_range.Font := font_obj;
|
||||||
|
text_range.W := word_width;
|
||||||
|
text_range.H := 0;
|
||||||
|
text_range.X := 0;
|
||||||
|
text_range.Y := 0;
|
||||||
|
range_array_[length(range_array_)] := text_range;
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TSPdfParagraphRange.RToDrawingRange(r: R; ppr: PPr);
|
||||||
|
begin
|
||||||
|
xfrm := new XfrmUnitDecorator(r.Drawing._Inline.Graphic.GraphicData.Pic.SpPr.Xfrm);
|
||||||
|
rels_adapter := class(TSPdfSingletonKit).GetComponent(docx_components_, "document_rels_adapter");
|
||||||
|
id := r.Drawing._Inline.Graphic.GraphicData.Pic.BlipFill.Blip.Embed;
|
||||||
|
rel := rels_adapter.Id(id);
|
||||||
|
image_path := "word/" + rel.Target;
|
||||||
|
image := docx_components_.Zip().Get(image_path);
|
||||||
|
data := image.Data();
|
||||||
|
image_path := docx_to_pdf_.GetTempPath(image_path);
|
||||||
|
writeFile(rwBinary(), "", image_path, 0, length(data)-1, data);
|
||||||
|
image := nil;
|
||||||
|
case self.GetImageFileType(data) of
|
||||||
|
"png":
|
||||||
|
image := docx_to_pdf_.GetPdf().LoadPngImageFromFile("", image_path);
|
||||||
|
"jpg":
|
||||||
|
image := docx_to_pdf_.GetPdf().LoadJpegImageFromFile("", image_path);
|
||||||
|
end;
|
||||||
|
image_range := new TSPdfImageRange();
|
||||||
|
image_range.Image := image;
|
||||||
|
image_range.X := xfrm.Off.X;
|
||||||
|
image_range.Y := xfrm.Off.Y;
|
||||||
|
image_range.W := xfrm.Ext.CX;
|
||||||
|
image_range.H := xfrm.Ext.CY;
|
||||||
|
fileDelete("", image_path);
|
||||||
|
range_array_[length(range_array_)] := image_range;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TSPdfParagraphRange.GetImageFileType(data: binary): string;
|
||||||
|
begin
|
||||||
|
stream := new TMemoryStream();
|
||||||
|
size := length(data);
|
||||||
|
stream.Write(data[0:size-1], size);
|
||||||
|
def := array(
|
||||||
|
('name': 'png', 'position': 0, 'value': array(0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A)),
|
||||||
|
('name': 'jpg', 'position': 0, 'value': array(0xFF, 0xD8)),
|
||||||
|
);
|
||||||
|
for i:=0 to length(def)-1 do
|
||||||
|
begin
|
||||||
|
value := def[i]['value'];
|
||||||
|
stream.Seek(def[i]['position']);
|
||||||
|
for j:=0 to length(value)-1 do
|
||||||
|
begin
|
||||||
|
r := 0;
|
||||||
|
stream.Read(r, 1);
|
||||||
|
if r <> value[j] then break;
|
||||||
|
if j = length(value)-1 then return def[i]['name'];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return '';
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TSPdfParagraphRange.GetParagraphLineSpace(size: real; line: integer): real;
|
||||||
|
begin
|
||||||
|
if not line then line := 12;
|
||||||
|
lines := roundto(line / 12, -1);
|
||||||
|
multi := ceil(size / sect_ware_.BaseSize) * lines;
|
||||||
|
return sect_ware_.SectPr.DocGrid.LinePitch * multi;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TSPdfParagraphRange.SetPPr(var ppr: PPr);
|
||||||
|
begin
|
||||||
|
new_ppr := new PPr();
|
||||||
|
styles := class(TSPdfSingletonKit).GetComponent(docx_components_, "styles");
|
||||||
|
new_ppr.Copy(styles.DocDefaults.PPrDefault.PPr);
|
||||||
|
new_ppr.RPr.Copy(styles.DocDefaults.RPrDefault.RPr);
|
||||||
|
self.SetPPrByStyleId(new_ppr, extra_style_id_);
|
||||||
|
self.SetPPrByStyleId(new_ppr, ppr.PStyle.Val);
|
||||||
|
new_ppr.Copy(ppr);
|
||||||
|
ppr.Copy(new_ppr);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TSPdfParagraphRange.SetPPrByStyleId(var ppr: PPr; style_id: string);
|
||||||
|
begin
|
||||||
|
styles := class(TSPdfSingletonKit).GetComponent(docx_components_, "styles_adapter");
|
||||||
|
style := styles.StyleId(style_id);
|
||||||
|
if ifObj(style) then
|
||||||
|
begin
|
||||||
|
based_on := style.BasedOn.Val;
|
||||||
|
self.SetPPrByStyleId(ppr, based_on);
|
||||||
|
ppr.Copy(style.PPr);
|
||||||
|
ppr.RPr.Copy(style.RPr);
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TSPdfParagraphRange.SetRPr(var rpr; ppr: PPr);
|
||||||
|
begin
|
||||||
|
// rpr,先继承ppr,再继承样式,最后继承自己
|
||||||
|
new_rpr := new RPr();
|
||||||
|
style_id := rpr.RStyle.Val;
|
||||||
|
new_rpr.Copy(ppr.RPr);
|
||||||
|
self.SetRPrByStyleId(new_rpr, style_id);
|
||||||
|
new_rpr.Copy(rpr);
|
||||||
|
rpr.Copy(new_rpr);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TSPdfParagraphRange.SetRPrByStyleId(var rpr: RPr; style_id: string);
|
||||||
|
begin
|
||||||
|
styles := class(TSPdfSingletonKit).GetComponent(docx_components_, "styles_adapter");
|
||||||
|
style := styles.StyleId(style_id);
|
||||||
|
if ifObj(style) then
|
||||||
|
begin
|
||||||
|
based_on := style.BasedOn.Val;
|
||||||
|
self.SetRPrByStyleId(rpr, based_on);
|
||||||
|
rpr.Copy(style.RPr);
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TSPdfParagraphRange.SetLvlText();
|
||||||
|
begin
|
||||||
|
numbering_ware := class(TSPdfSingletonKit).GetComponent(docx_components_, "numbering_ware");
|
||||||
|
if not ifObj(numbering_ware) then return;
|
||||||
|
[lvl_text, lvl] := numbering_ware.GetNumberLvl(paragraph_.PPr);
|
||||||
|
if lvl_text = "" and ifnil(lvl) then return;
|
||||||
|
self.SetRPr(lvl.RPr, paragraph_.PPr);
|
||||||
|
rpr := new RPrUnitDecorator(lvl.RPr);
|
||||||
|
self.SplitTextToTextRange(lvl_text, rpr);
|
||||||
|
end;
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
type TSPdfRectRange = class(TSPdfAbstractRange)
|
||||||
|
public
|
||||||
|
function Do();override;
|
||||||
|
public
|
||||||
|
Page: PdfPage;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TSPdfRectRange.Do();override;
|
||||||
|
begin
|
||||||
|
self.Page.SetRGBStroke(1.0, 0.0, 0.0);
|
||||||
|
self.Page.Rectangle(self.X, self.Y - self.H, self.W, self.H);
|
||||||
|
self.Page.Stroke();
|
||||||
|
end;
|
||||||
|
|
@ -0,0 +1,177 @@
|
||||||
|
type TSPdfTableRange = class(TSPdfAbstractRange)
|
||||||
|
public
|
||||||
|
function Create(docx_to_pdf: TSDocxToPdf; components: Components; sect_ware: TSSectWare; paragraph: P);
|
||||||
|
function Calc(): tableArray;
|
||||||
|
|
||||||
|
private
|
||||||
|
function ProcessTrData(grid_cols: array of GridCol; tr: Tr; tbl_pr: TblPr): array of TSPdfAbstractRange;
|
||||||
|
function ResetCoordinates(tbl_pr: TblPr; grid_cols: array of GridCol);
|
||||||
|
function SetTblPr(tbl_pr: TblPr);
|
||||||
|
function SetTblPrByStyleId(var tbl_pr: TblPr; style_id: string);
|
||||||
|
function SetTrPr(var tr_pr: TrPr);
|
||||||
|
function SetTrPrByStyleId(var tr_pr: TrPr; style_id: string);
|
||||||
|
function SetTcPr(var tc_pr: TcPr);
|
||||||
|
function SetTcPrByStyleId(var tc_pr: TcPr; style_id: string);
|
||||||
|
|
||||||
|
private
|
||||||
|
docx_to_pdf_: TSDocxToPdf;
|
||||||
|
docx_components_: Components;
|
||||||
|
sect_ware_: TSSectWare;
|
||||||
|
table_: Tbl;
|
||||||
|
range_array_: array of TSPdfAbstractRange;
|
||||||
|
page_: PdfPage;
|
||||||
|
point_: TSPoint;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TSPdfTableRange.Create(docx_to_pdf: TSDocxToPdf; components: Components; sect_ware: TSSectWare; table: Tbl);
|
||||||
|
begin
|
||||||
|
docx_to_pdf_ := docx_to_pdf;
|
||||||
|
docx_components_ := Components;
|
||||||
|
sect_ware_ := sect_ware;
|
||||||
|
table_ := table;
|
||||||
|
page_ := docx_to_pdf_.GetCurrentPage();
|
||||||
|
range_array_ := array();
|
||||||
|
point_ := new TSPoint(); // 动态记录段落的坐标位置
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TSPdfTableRange.Calc(): tableArray;
|
||||||
|
begin
|
||||||
|
self.SetTblPr(table_.TblPr);
|
||||||
|
tbl_pr := new TblPrUnitDecorator(table_.TblPr);
|
||||||
|
grid_cols := table_.TblGrid.GridCols();
|
||||||
|
for i:=0 to length(grid_cols)-1 do
|
||||||
|
grid_cols[i] := new GridColUnitDecorator(grid_cols[i]);
|
||||||
|
self.ResetCoordinates(tbl_pr, grid_cols);
|
||||||
|
point_.X := self.X;
|
||||||
|
point_.Y := self.Y;
|
||||||
|
// 如果是根据内容自适应,应该计算并调整grid_cols的值
|
||||||
|
trs := table_.Trs();
|
||||||
|
matrix := array();
|
||||||
|
for i,tr in trs do
|
||||||
|
matrix[i] := self.ProcessTrData(grid_cols, tr, tbl_pr);
|
||||||
|
return matrix;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TSPdfTableRange.ProcessTrData(grid_cols: array of GridCol; tr: Tr; tbl_pr: TblPr): array of TSPdfAbstractRange;
|
||||||
|
begin
|
||||||
|
self.SetTrPr(tr.TrPr);
|
||||||
|
tr_pr := new TrPrUnitDecorator(tr.TrPr);
|
||||||
|
tcs := tr.Tcs();
|
||||||
|
rows_range_array := array();
|
||||||
|
for _,tc in tcs do
|
||||||
|
begin
|
||||||
|
elements := tc.Elements();
|
||||||
|
rect_range := new TSPdfRectRange();
|
||||||
|
rect_range.X := point_.X;
|
||||||
|
rect_range.Y := point_.Y;
|
||||||
|
rect_range.W := grid_col.W;
|
||||||
|
rect_range.H := 100;
|
||||||
|
rows_range_array[length(rows_range_array)] := rect_range;
|
||||||
|
for _,element in elements do
|
||||||
|
begin
|
||||||
|
range := nil;
|
||||||
|
if element.LocalName = "p" then
|
||||||
|
begin
|
||||||
|
range := new TSPdfParagraphRange(docx_to_pdf_, docx_components_, sect_ware_, element);
|
||||||
|
range.SetExtraStyleId(tbl_pr.TblStyle.Val);
|
||||||
|
end
|
||||||
|
else if element.LocalName = "tbl" then
|
||||||
|
begin
|
||||||
|
range := new TSPdfTableRange(docx_to_pdf_, docx_components_, sect_ware_, element);
|
||||||
|
end
|
||||||
|
if ifObj(range) then
|
||||||
|
begin
|
||||||
|
range.X := point_.X - tbl_pr.TblCellMar.Left.W;
|
||||||
|
range.Y := point_.Y - tbl_pr.TblCellMar.Top.W;
|
||||||
|
range.W := grid_col.W - tbl_pr.TblCellMar.Right.W;
|
||||||
|
range.H := nil;
|
||||||
|
ret := range.Calc();
|
||||||
|
point_.Y := range.Y;
|
||||||
|
point_.X += grid_col.W;
|
||||||
|
rows_range_array[length(rows_range_array)] := range;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return rows_range_array;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TSPdfTableRange.ResetCoordinates(tbl_pr: TblPr; grid_cols: array of GridCol);
|
||||||
|
begin
|
||||||
|
total_width := 0;
|
||||||
|
for _,grid_col in grid_cols do
|
||||||
|
total_width += grid_col.W;
|
||||||
|
diff := total_width - self.W;
|
||||||
|
case tbl_pr.jc.Val of
|
||||||
|
"center":
|
||||||
|
begin
|
||||||
|
offset := diff/2;
|
||||||
|
self.X -= offset;
|
||||||
|
end
|
||||||
|
"right":
|
||||||
|
begin
|
||||||
|
self.X -= diff;
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
self.W := total_width;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TSPdfTableRange.SetTblPr(var tbl_pr: TblPr);
|
||||||
|
begin
|
||||||
|
new_tbl_pr := new TblPr();
|
||||||
|
tbl_pr.TblStyle.XmlNode.print;
|
||||||
|
self.SetTblPrByStyleId(new_tbl_pr, tbl_pr.TblStyle.Val);
|
||||||
|
new_tbl_pr.Copy(tbl_pr);
|
||||||
|
tbl_pr.Copy(new_tbl_pr);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TSPdfTableRange.SetTblPrByStyleId(var tbl_pr: TblPr; style_id: string);
|
||||||
|
begin
|
||||||
|
styles := class(TSPdfSingletonKit).GetComponent(docx_components_, "styles_adapter");
|
||||||
|
style := styles.StyleId(style_id);
|
||||||
|
if ifObj(style) then
|
||||||
|
begin
|
||||||
|
based_on := style.BasedOn.Val;
|
||||||
|
self.SetTblPrByStyleId(tbl_pr, based_on);
|
||||||
|
tbl_pr.Copy(style.TblPr);
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TSPdfTableRange.SetTrPr(var tr_pr: TrPr);
|
||||||
|
begin
|
||||||
|
new_tr_pr := new TrPr();
|
||||||
|
self.SetTrPrByStyleId(new_tr_pr, table_.TblPr.TblStyle.Val);
|
||||||
|
new_tr_pr.Copy(tr_pr);
|
||||||
|
tr_pr.Copy(new_tr_pr);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TSPdfTableRange.SetTrPrByStyleId(var tr_pr: TrPr; style_id: string);
|
||||||
|
begin
|
||||||
|
styles := class(TSPdfSingletonKit).GetComponent(docx_components_, "styles_adapter");
|
||||||
|
style := styles.StyleId(style_id);
|
||||||
|
if ifObj(style) then
|
||||||
|
begin
|
||||||
|
based_on := style.BasedOn.Val;
|
||||||
|
self.SetTrPrByStyleId(tr_pr, based_on);
|
||||||
|
tr_pr.Copy(style.TrPr);
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TSPdfTableRange.SetTcPr(var tc_pr: TcPr);
|
||||||
|
begin
|
||||||
|
new_tc_pr := new TcPr();
|
||||||
|
self.SetTcPrByStyleId(new_tc_pr, table_.TblPr.TblStyle.Val);
|
||||||
|
new_tc_pr.Copy(tc_pr);
|
||||||
|
tc_pr.Copy(new_tc_pr);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TSPdfTableRange.SetTcPrByStyleId(var tc_pr: TcPr; style_id: string);
|
||||||
|
begin
|
||||||
|
styles := class(TSPdfSingletonKit).GetComponent(docx_components_, "styles_adapter");
|
||||||
|
style := styles.StyleId(style_id);
|
||||||
|
if ifObj(style) then
|
||||||
|
begin
|
||||||
|
based_on := style.BasedOn.Val;
|
||||||
|
self.SetTcPrByStyleId(tc_pr, based_on);
|
||||||
|
tc_pr.Copy(style.TcPr);
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
type TSPdfTextRange = class(TSPdfAbstractRange)
|
||||||
|
uses TSColorToolKit;
|
||||||
|
public
|
||||||
|
function Do();override;
|
||||||
|
public
|
||||||
|
RPr: RPr;
|
||||||
|
Text: string;
|
||||||
|
Font: PdfFont;
|
||||||
|
Page: PdfPage;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TSPdfTextRange.Do();
|
||||||
|
begin
|
||||||
|
// println("text = {}, x = {}, y = {}, w = {}, sz = {}", ansiToUtf8(text), x, y, w);
|
||||||
|
[r, g, b] := array(0, 0, 0);
|
||||||
|
if self.RPr.Color.Val then [r, g, b] := TSColorToolKit.HexToRGB(self.RPr.Color.Val);
|
||||||
|
self.Page.SetRGBFill(r / 255, g / 255, b / 255);
|
||||||
|
self.Page.SetFontAndSize(self.Font, self.RPr.Sz.Val);
|
||||||
|
self.Page.BeginText();
|
||||||
|
self.Page.TextOut(self.X, self.Y, self.Text);
|
||||||
|
self.Page.EndText();
|
||||||
|
self.Page.SetRGBFill(0, 0, 0);
|
||||||
|
|
||||||
|
{$DEFINE WordToPdfTEST}
|
||||||
|
{$IFDEF WordToPdfTEST}
|
||||||
|
self.Page.SetLineWidth(0.5);
|
||||||
|
self.Page.SetGrayStroke(0.5);
|
||||||
|
self.Page.MoveTo(0, self.Y);
|
||||||
|
self.Page.LineTo(90, self.Y);
|
||||||
|
self.Page.Stroke();
|
||||||
|
{$ENDIF}
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
@ -1,23 +1,23 @@
|
||||||
unit TSColorToolKit;
|
unit TSColorToolKit;
|
||||||
interface
|
interface
|
||||||
function HexToRGB(hex);
|
function HexToRGB(hex);
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
function HexToRGB(hex);
|
function HexToRGB(hex);
|
||||||
begin
|
begin
|
||||||
hex_string := ifnumber(hex) ? format("%x", hex) : hex;
|
hex_string := ifnumber(hex) ? format("%x", hex) : hex;
|
||||||
if length(hex_string) = 7 then
|
if length(hex_string) = 7 then
|
||||||
begin
|
begin
|
||||||
if hex_string[1] <> "#" then raise "Invalid hexadecimal parameter.";
|
if hex_string[1] <> "#" then raise "Invalid hexadecimal parameter.";
|
||||||
hex_string := hex_string[1:];
|
hex_string := hex_string[1:];
|
||||||
end
|
end
|
||||||
if length(hex_string) <> 6 then raise "Invalid hexadecimal parameter";
|
if length(hex_string) <> 6 then raise "Invalid hexadecimal parameter";
|
||||||
r := eval(&"return 0x" + hex_string[1:2]);
|
r := eval(&"return 0x" + hex_string[1:2]);
|
||||||
g := eval(&"return 0x" + hex_string[3:4]);
|
g := eval(&"return 0x" + hex_string[3:4]);
|
||||||
b := eval(&"return 0x" + hex_string[5:6]);
|
b := eval(&"return 0x" + hex_string[5:6]);
|
||||||
return array(r, g, b);
|
return array(r, g, b);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,100 +0,0 @@
|
||||||
type TSFontWare = class
|
|
||||||
public
|
|
||||||
function Create(pdf);
|
|
||||||
function Init();
|
|
||||||
function UseBuiltInFont();
|
|
||||||
function SetSubstitutionRules(source, target);
|
|
||||||
function GetFont(name, bold, italic);
|
|
||||||
|
|
||||||
private
|
|
||||||
function GetExternalFont(name, bold, italic);
|
|
||||||
function GetBuiltInFont(name, bold, italic);
|
|
||||||
|
|
||||||
private
|
|
||||||
pdf_;
|
|
||||||
is_linux_; // 是否是linux
|
|
||||||
|
|
||||||
use_built_in_font_; // 是否使用内置字体
|
|
||||||
substitution_rules_; // 替换规则
|
|
||||||
external_reference_;
|
|
||||||
external_font_cache_;
|
|
||||||
end;
|
|
||||||
|
|
||||||
|
|
||||||
function TSFontWare.Create(pdf);
|
|
||||||
begin
|
|
||||||
pdf_ := pdf;
|
|
||||||
is_linux_ := true;
|
|
||||||
use_built_in_font_ := false;
|
|
||||||
substitution_rules_ := array("宋体": "SimSun", "黑体": "SimHei");
|
|
||||||
external_reference_ := array();
|
|
||||||
external_font_cache_ := array();
|
|
||||||
// self.Init();
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TSFontWare.UseBuiltInFont();
|
|
||||||
begin
|
|
||||||
use_built_in_font_ := true;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TSFontWare.Init();
|
|
||||||
begin
|
|
||||||
{$IFDEF LINUX}
|
|
||||||
is_linux_ := true;
|
|
||||||
{$ELSE}
|
|
||||||
is_linux_ := false;
|
|
||||||
{$ENDIF}
|
|
||||||
separator := is_linux_ ? "/" : "\\";
|
|
||||||
path := extractFileDir(sysExecName()) + separator + "funcext" + separator + "WordToPdf" + separator + "fonts" + separator;
|
|
||||||
files := fileList("", path + "*.tt*");
|
|
||||||
for i:=0 to length(files)-1 do
|
|
||||||
begin
|
|
||||||
filename := files[i]["FileName"];
|
|
||||||
ext := extractFileExt(filename);
|
|
||||||
pos := pos(ext, filename);
|
|
||||||
name := is_linux_ ? filename[:pos-1] : ansiToUTF8(filename[:pos-1]);
|
|
||||||
external_reference_[name] := array("ext": ext, "path": path + filename);
|
|
||||||
end
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TSFontWare.GetExternalFont(name, bold, italic);
|
|
||||||
begin
|
|
||||||
if ifnil(name) or name = '' then name := "等线";
|
|
||||||
if not ifnil(external_font_cache_[name]) then return external_font_cache_[name];
|
|
||||||
value := external_reference_[name];
|
|
||||||
if ifnil(value) then return nil;
|
|
||||||
// if ifnil(value) then raise name + " is unsupported font.";
|
|
||||||
if value["ext"] = ".ttf" then
|
|
||||||
font_name := pdf_.LoadTTFontFromFile("", value["path"], true);
|
|
||||||
else if value["ext"] = ".ttc" then
|
|
||||||
font_name := pdf_.LoadTTFontFromFile2("", value["path"], 0, true);
|
|
||||||
// if not ifString(font_name) then raise "Load font error : " + format("%x", font_name);
|
|
||||||
if not ifString(font_name) then return nil;
|
|
||||||
font := pdf_.GetFont(font_name, "UTF-8");
|
|
||||||
external_font_cache_[name] := font;
|
|
||||||
return font;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TSFontWare.GetFont(name, bold, italic);
|
|
||||||
begin
|
|
||||||
return use_built_in_font_ ? self.GetBuiltInFont(name, bold, italic) : self.GetExternalFont(name, bold, italic);
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TSFontWare.GetBuiltInFont(name, bold, italic);
|
|
||||||
begin
|
|
||||||
font_name := substitution_rules_["name"];
|
|
||||||
if ifnil(font_name) then font_name := "SimSun";
|
|
||||||
if bold and italic then
|
|
||||||
font_name += ",BoldItalic";
|
|
||||||
else if bold then
|
|
||||||
font_name += ",Bold";
|
|
||||||
else if italic then
|
|
||||||
font_name += ",Italic";
|
|
||||||
font := pdf_.GetFont(font_name, "GBK-EUC-H");
|
|
||||||
return font;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TSFontWare.SetSubstitutionRules(source, target);
|
|
||||||
begin
|
|
||||||
substitution_rules_[source] := target;
|
|
||||||
end;
|
|
||||||
|
|
@ -1,108 +0,0 @@
|
||||||
type TSParagraphWare = class
|
|
||||||
public
|
|
||||||
function Create(components, styles, paragraph);
|
|
||||||
function Do();
|
|
||||||
function GetWords();
|
|
||||||
|
|
||||||
property Paragraph read ReadParagraph;
|
|
||||||
function ReadParagraph();
|
|
||||||
|
|
||||||
private
|
|
||||||
function SetPPr(ppr);
|
|
||||||
function SetRPr(rpr, ppr);
|
|
||||||
function SetRPrByStyleId(rpr, style_id);
|
|
||||||
function SetPPrByStyleId(ppr, style_id);
|
|
||||||
|
|
||||||
private
|
|
||||||
docx_components_;
|
|
||||||
styles_;
|
|
||||||
paragraph_;
|
|
||||||
words_;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TSParagraphWare.Create(components, styles, paragraph);
|
|
||||||
begin
|
|
||||||
docx_components_ := components;
|
|
||||||
styles_ := styles;
|
|
||||||
paragraph_ := paragraph;
|
|
||||||
words_ := array();
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TSParagraphWare.Do();
|
|
||||||
begin
|
|
||||||
self.SetPPr(paragraph_.PPr); // styleid与ppr样式合并
|
|
||||||
rs := paragraph_.Rs();
|
|
||||||
for i:=0 to length(rs)-1 do
|
|
||||||
begin
|
|
||||||
r := rs[i];
|
|
||||||
self.SetRPr(r.RPr, paragraph_.PPr); // rpr样式与ppr与styleid样式合并
|
|
||||||
rpr := new RPrUnitDecorator(r.RPr);
|
|
||||||
pos := 1;
|
|
||||||
text := r.T.Text;
|
|
||||||
while pos <= length(text) do
|
|
||||||
begin
|
|
||||||
c := text[pos];
|
|
||||||
pos ++;
|
|
||||||
if ord(c) > 127 then
|
|
||||||
begin
|
|
||||||
c := text[pos-1 : pos+1];
|
|
||||||
pos += 2;
|
|
||||||
end
|
|
||||||
words_[length(words_)] := array(utf8ToAnsi(c), rpr);
|
|
||||||
end
|
|
||||||
end
|
|
||||||
paragraph_.PPr := new PPrUnitDecorator(paragraph_.PPr);
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TSParagraphWare.SetPPrByStyleId(ppr, style_id);
|
|
||||||
begin
|
|
||||||
style := styles_.StyleId(style_id);
|
|
||||||
if ifObj(style) then
|
|
||||||
begin
|
|
||||||
based_on := style.BasedOn.Val;
|
|
||||||
self.SetPPrByStyleId(ppr, based_on);
|
|
||||||
ppr.Copy(style.PPr);
|
|
||||||
ppr.Rpr.Copy(style.RPr);
|
|
||||||
end
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TSParagraphWare.SetPPr(ppr);
|
|
||||||
begin
|
|
||||||
new_ppr := new PPr();
|
|
||||||
style_id := ppr.PStyle.Val;
|
|
||||||
self.SetPPrByStyleId(new_ppr, style_id);
|
|
||||||
new_ppr.Copy(ppr);
|
|
||||||
ppr.Copy(new_ppr);
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TSParagraphWare.SetRPrByStyleId(rpr, style_id);
|
|
||||||
begin
|
|
||||||
style := styles_.StyleId(style_id);
|
|
||||||
if ifObj(style) then
|
|
||||||
begin
|
|
||||||
based_on := style.BasedOn.Val;
|
|
||||||
self.SetRPrByStyleId(rpr, based_on);
|
|
||||||
rpr.Copy(style.RPr);
|
|
||||||
end
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TSParagraphWare.SetRPr(rpr, ppr);
|
|
||||||
begin
|
|
||||||
// rpr,先继承ppr,再继承样式,最后继承自己
|
|
||||||
new_rpr := new RPr();
|
|
||||||
style_id := rpr.RStyle.Val;
|
|
||||||
new_rpr.Copy(ppr.RPr);
|
|
||||||
self.SetRPrByStyleId(new_rpr, style_id);
|
|
||||||
new_rpr.Copy(rpr);
|
|
||||||
rpr.Copy(new_rpr);
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TSParagraphWare.GetWords();
|
|
||||||
begin
|
|
||||||
return words_;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TSParagraphWare.ReadParagraph();
|
|
||||||
begin
|
|
||||||
return paragraph_;
|
|
||||||
end
|
|
||||||
|
|
@ -0,0 +1,59 @@
|
||||||
|
type TSPdfSingletonKit = class
|
||||||
|
public
|
||||||
|
function Create();
|
||||||
|
class function GetComponent(components: Components; type: string);
|
||||||
|
public
|
||||||
|
hash_: array of tslobj;
|
||||||
|
|
||||||
|
private
|
||||||
|
static singleton_: Singleton;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TSPdfSingletonKit.Create();
|
||||||
|
begin
|
||||||
|
hash_ := array();
|
||||||
|
end;
|
||||||
|
|
||||||
|
class function TSPdfSingletonKit.GetComponent(components: Components; type: string);
|
||||||
|
begin
|
||||||
|
if not ifObj(singleton_) then singleton_ := new TSPdfSingletonKit();
|
||||||
|
if ifnil(singleton_.hash_[components]) then singleton_.hash_[components] := array();
|
||||||
|
if ifObj(singleton_.hash_[components][type]) then return singleton_.hash_[components][type];
|
||||||
|
case type of
|
||||||
|
"styles":
|
||||||
|
begin
|
||||||
|
styles := components.Styles;
|
||||||
|
styles.Deserialize();
|
||||||
|
singleton_.hash_[components][type] := styles;
|
||||||
|
return styles;
|
||||||
|
end
|
||||||
|
"styles_adapter":
|
||||||
|
begin
|
||||||
|
styles := class(TSPdfSingletonKit).GetComponent(components, "styles");
|
||||||
|
styles_adapter := new StylesAdapter(styles);
|
||||||
|
singleton_.hash_[components][type] := styles_adapter;
|
||||||
|
return styles_adapter;
|
||||||
|
end
|
||||||
|
"numbering_ware":
|
||||||
|
begin
|
||||||
|
numbering := components.Numbering;
|
||||||
|
numbering_ware := nil;
|
||||||
|
if ifObj(numbering) then
|
||||||
|
begin
|
||||||
|
numbering.Deserialize();
|
||||||
|
numbering_ware := new TSNumberingWare(numbering);
|
||||||
|
end
|
||||||
|
singleton_.hash_[components][type] := numbering_ware;
|
||||||
|
return numbering_ware;
|
||||||
|
end
|
||||||
|
"document_rels_adapter":
|
||||||
|
begin
|
||||||
|
document_rels := components.DocumentRels;
|
||||||
|
document_rels.Deserialize();
|
||||||
|
rels_adapter := new RelationShipsAdapter(document_rels);
|
||||||
|
singleton_.hash_[components][type] := rels_adapter;
|
||||||
|
return rels_adapter;
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
type TSPoint = class
|
||||||
|
function Create();
|
||||||
|
begin
|
||||||
|
self.X := 0;
|
||||||
|
self.Y := 0;
|
||||||
|
end
|
||||||
|
X: real;
|
||||||
|
Y: real;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
@ -0,0 +1,88 @@
|
||||||
|
type TSFontWare = class
|
||||||
|
public
|
||||||
|
function Create(pdf: PdfFile);
|
||||||
|
function GetFont(name: string; bold: boolean; italic: boolean);
|
||||||
|
function UseExternalFont();
|
||||||
|
function SetSubstitutionRules(source: string; target: string);
|
||||||
|
function SetDefaultSz(value: real);
|
||||||
|
function GetDefaultSz();
|
||||||
|
|
||||||
|
private
|
||||||
|
function GetExternalFont(name:string; bold: boolean; italic: boolean);
|
||||||
|
function GetBuiltInFont(name:string; bold: boolean; italic: boolean);
|
||||||
|
|
||||||
|
private
|
||||||
|
[weakref]pdf_: PdfFile;
|
||||||
|
|
||||||
|
is_linux_: boolean; // 是否是linux
|
||||||
|
use_built_in_font_: boolean; // 是否使用内置字体
|
||||||
|
substitution_rules_: array of string; // 替换规则
|
||||||
|
external_reference_: array of string;
|
||||||
|
default_sz_: real;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TSFontWare.Create(pdf: PdfFile);
|
||||||
|
begin
|
||||||
|
pdf_ := pdf;
|
||||||
|
use_built_in_font_ := true;
|
||||||
|
substitution_rules_ := array("宋体": "SimSun", "黑体": "SimHei");
|
||||||
|
external_reference_ := array();
|
||||||
|
default_sz_ := 10.5;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TSFontWare.SetDefaultSz(value: real);
|
||||||
|
begin
|
||||||
|
default_sz_ := value;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TSFontWare.GetDefaultSz();
|
||||||
|
begin
|
||||||
|
return default_sz_;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TSFontWare.UseExternalFont();
|
||||||
|
begin
|
||||||
|
use_built_in_font_ := false;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TSFontWare.GetExternalFont(name:string; bold: boolean; italic: boolean);
|
||||||
|
begin
|
||||||
|
if ifnil(name) or name = '' then name := "等线";
|
||||||
|
if not ifnil(external_font_cache_[name]) then return external_font_cache_[name];
|
||||||
|
value := external_reference_[name];
|
||||||
|
if ifnil(value) then return nil;
|
||||||
|
// if ifnil(value) then raise name + " is unsupported font.";
|
||||||
|
if value["ext"] = ".ttf" then
|
||||||
|
font_name := pdf_.LoadTTFontFromFile("", value["path"], true);
|
||||||
|
else if value["ext"] = ".ttc" then
|
||||||
|
font_name := pdf_.LoadTTFontFromFile2("", value["path"], 0, true);
|
||||||
|
// if not ifString(font_name) then raise "Load font error : " + format("%x", font_name);
|
||||||
|
if not ifString(font_name) then return nil;
|
||||||
|
font := pdf_.GetFont(font_name, "UTF-8");
|
||||||
|
external_font_cache_[name] := font;
|
||||||
|
return font;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TSFontWare.GetFont(name: string; bold: boolean; italic: boolean);
|
||||||
|
begin
|
||||||
|
return use_built_in_font_ ? self.GetBuiltInFont(name, bold, italic) : self.GetExternalFont(name, bold, italic);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TSFontWare.GetBuiltInFont(name: string; bold: boolean; italic: boolean);
|
||||||
|
begin
|
||||||
|
font_name := substitution_rules_["name"];
|
||||||
|
if ifnil(font_name) then font_name := "SimSun";
|
||||||
|
if bold and italic then
|
||||||
|
font_name += ",BoldItalic";
|
||||||
|
else if bold then
|
||||||
|
font_name += ",Bold";
|
||||||
|
else if italic then
|
||||||
|
font_name += ",Italic";
|
||||||
|
font := pdf_.GetFont(font_name, "GBK-EUC-H");
|
||||||
|
return font;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TSFontWare.SetSubstitutionRules(source: string; target: string);
|
||||||
|
begin
|
||||||
|
substitution_rules_[source] := target;
|
||||||
|
end;
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
type TSNumberingWare = class
|
||||||
|
public
|
||||||
|
function Create(number: NumberingAdapter);
|
||||||
|
function GetNumberLvl(ppr: PPr);
|
||||||
|
|
||||||
|
private
|
||||||
|
numbering_adapter_: NumberingAdapter;
|
||||||
|
num_hash_: array of tslobj;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TSNumberingWare.Create(number: NumberingAdapter);
|
||||||
|
begin
|
||||||
|
numbering_adapter_ := new NumberingAdapter(number);
|
||||||
|
num_hash_ := array();
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TSNumberingWare.GetNumberLvl(ppr: PPr);
|
||||||
|
begin
|
||||||
|
num_id := ppr.NumPr.NumId.Val;
|
||||||
|
if ifnil(num_id) then return array("", nil);
|
||||||
|
ilvl := ppr.NumPr.Ilvl.Val;
|
||||||
|
pstyle := ppr.PStyle.Val;
|
||||||
|
num := numbering_adapter_.NumId(num_id);
|
||||||
|
abstract_id := num.AbstractNumId.Val;
|
||||||
|
abstract_num := numbering_adapter_.AbstractNumId(abstract_id);
|
||||||
|
lvls := abstract_num.Lvls();
|
||||||
|
if ifnil(ilvl) then ilvl := "0";
|
||||||
|
for k,v in lvls do
|
||||||
|
begin
|
||||||
|
if ilvl and v.Ilvl = ilvl then
|
||||||
|
begin
|
||||||
|
lvl_text := v.LvlText.Val;
|
||||||
|
if not ifarray(num_hash_[num_id]) then num_hash_[num_id] := array(0, 0, 0, 0, 0, 0, 0, 0, 0);
|
||||||
|
ilvl_int := strtoint(ilvl);
|
||||||
|
for i:=0 to ilvl_int do
|
||||||
|
begin
|
||||||
|
source_str := "%" $ (i + 1);
|
||||||
|
n := i = ilvl_int ? num_hash_[num_id][i] + 1 : num_hash_[num_id][i];
|
||||||
|
dest_str := format("%d", n);
|
||||||
|
lvl_text := replaceStr(lvl_text, source_str, dest_str);
|
||||||
|
end
|
||||||
|
num_hash_[num_id][ilvl_int]++;
|
||||||
|
if v.Suff.Val = "space" then lvl_text += " ";
|
||||||
|
return array(lvl_text, v);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return array("", nil);
|
||||||
|
end
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
type TSSectWare = class
|
||||||
|
public
|
||||||
|
function Create();
|
||||||
|
function Do();
|
||||||
|
|
||||||
|
public
|
||||||
|
Elements: array of tslobj;
|
||||||
|
SectPr: SectPr;
|
||||||
|
BaseSize: integer;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TSSectWare.Create();
|
||||||
|
begin
|
||||||
|
self.Elements := array();
|
||||||
|
self.SectPr := nil;
|
||||||
|
self.BaseSize := 0;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TSSectWare.Do();
|
||||||
|
begin
|
||||||
|
if ifObj(self.SectPr) then
|
||||||
|
self.BaseSize := round(self.SectPr.DocGrid.LinePitch * 0.75);
|
||||||
|
// println("LinePitch = {}, Type = {}", self.SectPr.DocGrid.LinePitch, self.SectPr.DocGrid.Type);
|
||||||
|
// println("Width = {}, Height = {}", self.SectPr.PgSz.W, self.SectPr.PgSz.H);
|
||||||
|
// println("Top = {}, Right = {}, Bottom = {}, Left = {}, Header = {}, Footer = {}\n",
|
||||||
|
// self.SectPr.PgMar.Top, self.SectPr.PgMar.Right, self.SectPr.PgMar.Bottom, self.SectPr.PgMar.Left, self.SectPr.PgMar.Header, self.SectPr.PgMar.Footer);
|
||||||
|
end;
|
||||||
Loading…
Reference in New Issue