重构第一版完成

This commit is contained in:
csh 2024-06-25 14:19:57 +08:00
parent 007da049a3
commit 20cfa5120a
6 changed files with 190 additions and 70 deletions

View File

@ -9,6 +9,7 @@ public
function GetCurrentPoint(): Point;
function GetTempPath(image_path: string): string;
function GetPdf(): PdfFile;
function GetNextPage(page: PdfPage): PdfPage;
function AddPage(sect_ware: TSSectWare): PdfPage;
property Font read ReadFont;
@ -34,8 +35,9 @@ private
sect_ware_array_: array of TSSectWare; // 页面布局组件数组
font_ware_: TSFontWare; // 字体部件
current_page_: PdfPage;
page_array_: array of PdfPage;
point_: TSPoint; // 定位坐标点
page_array_: array of PdfPage;
page_index_: tableArray;
end;
function TSDocxToPdf.Create(alias: string; file: string);
@ -47,8 +49,9 @@ begin
self.InitSectWare();
font_ware_ := new TSFontWare(pdf_);
current_page_ := nil;
page_array_ := array();
point_ := new TSPoint();
page_array_ := array();
page_index_ := array();
end;
function TSDocxToPdf.Destroy();
@ -162,7 +165,7 @@ begin
sect_ware_array_[length(sect_ware_array_)] := ware;
end
end
println("sect_ware_array_ = {}", sect_ware_array_);
// println("sect_ware_array_ = {}", sect_ware_array_);
end;
function TSDocxToPdf.AddPage(sect_ware: TSSectWare): PdfPage;
@ -171,16 +174,23 @@ begin
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}
len := length(page_array_);
page_array_[len] := current_page_;
page_index_[current_page_] := len;
if sysparams["_PDF_PAGE_GRID_DEBUG_"] then
self.PrintGrid(current_page_, sect_ware);
{$ENDIF}
return current_page_;
end;
function TSDocxToPdf.GetNextPage(page: PdfPage);
begin
pos := page_index_[page];
return page_array_[pos + 1];
end;
function TSDocxToPdf.ResetCoordinates(sect_ware: TSSectWare);
begin
point_.X := sect_ware.SectPr.PgMar.Left;
@ -229,7 +239,7 @@ 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 := new TSPdfParagraphRange(self, current_page_, docx_components_, sect_ware, paragraph);
range.X := point_.X;
range.Y := point_.Y;
range.W := w;
@ -241,9 +251,8 @@ 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 := new TSPdfTableRange(self, current_page_, docx_components_, sect_ware, table);
range.X := point_.X;
range.Y := point_.Y;
range.W := w;

View File

@ -8,19 +8,14 @@ end;
function TSPdfImageRange.Do();
begin
println("image = {}, x = {}, y = {}, w = {}, h = {}", image, x, y, w, h);
// 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();
if sysparams["_PDF_IMAGE_DEBUG_"] then
begin
self.Page.SetLineWidth(0.1);
self.Page.SetGrayStroke(0.5);
self.Page.Rectangle(0, Y, 900, H);
self.Page.SetRGBStroke(0.8, 0.8, 0);
self.Page.Rectangle(X, Y, W, H);
self.Page.Stroke();
{$ENDIF}
end
end;

View File

@ -1,6 +1,6 @@
type TSPdfParagraphRange = class(TSPdfAbstractRange)
public
function Create(docx_to_pdf: TSDocxToPdf; components: Components; sect_ware: TSSectWare; paragraph: P);
function Create(docx_to_pdf: TSDocxToPdf; page: PdfPage; components: Components; sect_ware: TSSectWare; paragraph: P);
function Calc();
function Do();override;
function SetExtraStyleId(style_id: string);
@ -19,7 +19,8 @@ private
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);
function SetLinesAlignment(ppr: PPr);
function ResetCoordinates(ppr);
private
docx_to_pdf_: TSDocxToPdf;
@ -33,14 +34,14 @@ private
lines_range_array_: tableArray;
end;
function TSPdfParagraphRange.Create(docx_to_pdf: TSDocxToPdf; components: Components; sect_ware: TSSectWare; paragraph: P);
function TSPdfParagraphRange.Create(docx_to_pdf: TSDocxToPdf; page: PdfPage; components: Components; sect_ware: TSSectWare; paragraph: P);
begin
docx_to_pdf_ := docx_to_pdf;
page_ := page;
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();
@ -51,9 +52,7 @@ 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;
self.ResetCoordinates(ppr);
point_.X := self.X;
point_.Y := self.Y;
self.CheckAndAddPage(point_.Y, ppr.Spacing.Before);
@ -106,9 +105,9 @@ begin
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);
diff := point_.Y - sect_ware_.SectPr.PgMar.Bottom;
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;
total_height += diff;
if_newline := point_.X + range.W - self.X > self.W + 1e-6;
if if_newline and range.W < self.W then
begin
@ -126,8 +125,12 @@ begin
total_height += max_value;
point_.Y -= max_value;
point_.X := self.X;
// w:hanging
sz := range.RPr.SzCs.Val ? range.RPr.SzCs.Val : range.RPr.Sz.Val ? range.RPr.Sz.Val : docx_to_pdf_.Font.GetDefaultSz();
point_.X -= ppr.Ind.HangingChars ? ppr.Ind.HangingChars * sz : ppr.Ind.Hanging;
continue;
end
range.X := point_.X - range.X;
point_.X += range.W;
line_range[length(line_range)] := range;
i++;
@ -140,21 +143,21 @@ begin
item.Y := point_.Y - offset;
end
lines_range_array_[length(lines_range_array_)] := line_range;
max_value := max(line_space, max_y);
max_value := max(line_space, max_y) + ppr.Spacing.After;
total_height += max_value;
point_.Y -= max_value;
end
end
// self.SetLinesAlignment(lines_range_array, ppr);
self.SetLinesAlignment(ppr);
if not self.H then self.H := total_height;
self.Y := point_.Y;
end;
function TSPdfParagraphRange.SetLinesAlignment(lines_range_array: tableArray; ppr: PPr);
function TSPdfParagraphRange.SetLinesAlignment(ppr: PPr);
begin
if length(lines_range_array) = 0 then return;
idx := length(lines_range_array)-1;
line := lines_range_array[idx];
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":
@ -170,6 +173,7 @@ begin
offset := self.W - last.X + first.X - last.W;
end
end;
if offset < 0 then return;
if offset then
for i:=0 to length(line)-1 do
line[i].X += offset;
@ -179,10 +183,10 @@ 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_);
page_ := docx_to_pdf_.GetNextPage(page_);
if ifnil(page_) then 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;
@ -217,7 +221,7 @@ begin
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);
font_obj := docx_to_pdf_.Font.GetFont(font_name, rpr.B, rpr.I);
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);
@ -351,3 +355,12 @@ begin
rpr := new RPrUnitDecorator(lvl.RPr);
self.SplitTextToTextRange(lvl_text, rpr);
end;
function TSPdfParagraphRange.ResetCoordinates(ppr);
begin
// 根据段落的间距确定新的坐标
sz := ppr.RPr.SzCs.Val ? ppr.RPr.SzCs.Val : ppr.RPr.Sz.Val ? ppr.RPr.Sz.Val : docx_to_pdf_.Font.GetDefaultSz();
self.X += ppr.Ind.LeftChars ? ppr.Ind.LeftChars * sz : ppr.Ind.Left;
self.W -= ppr.Ind.LeftChars ? ppr.Ind.LeftChars * sz : ppr.Ind.Left;
self.W -= ppr.Ind.RightChars ? ppr.Ind.RightChars * sz : ppr.Ind.Right;
end;

View File

@ -7,7 +7,10 @@ end;
function TSPdfRectRange.Do();override;
begin
self.Page.SetRGBStroke(1.0, 0.0, 0.0);
// self.Page.SetRGBStroke(1.0, 0.0, 0.0);
self.Page.SetGrayStroke(0.5);
self.Page.SetLineWidth(0.5);
self.Page.Rectangle(self.X, self.Y - self.H, self.W, self.H);
self.Page.Stroke();
self.Page.SetGrayStroke(0);
end;

View File

@ -1,11 +1,13 @@
type TSPdfTableRange = class(TSPdfAbstractRange)
public
function Create(docx_to_pdf: TSDocxToPdf; components: Components; sect_ware: TSSectWare; paragraph: P);
function Calc(): tableArray;
function Create(docx_to_pdf: TSDocxToPdf; page: PdfPage; components: Components; sect_ware: TSSectWare; paragraph: P);
function Calc();
function Do();override;
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 CheckAndAddPage(y: real; offset: real): boolean;
function SetTblPr(tbl_pr: TblPr);
function SetTblPrByStyleId(var tbl_pr: TblPr; style_id: string);
function SetTrPr(var tr_pr: TrPr);
@ -18,23 +20,23 @@ private
docx_components_: Components;
sect_ware_: TSSectWare;
table_: Tbl;
range_array_: array of TSPdfAbstractRange;
range_array_: tableArray;
page_: PdfPage;
point_: TSPoint;
end;
function TSPdfTableRange.Create(docx_to_pdf: TSDocxToPdf; components: Components; sect_ware: TSSectWare; table: Tbl);
function TSPdfTableRange.Create(docx_to_pdf: TSDocxToPdf; page: PdfPage; components: Components; sect_ware: TSSectWare; table: Tbl);
begin
docx_to_pdf_ := docx_to_pdf;
page_ := page;
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;
function TSPdfTableRange.Calc();
begin
self.SetTblPr(table_.TblPr);
tbl_pr := new TblPrUnitDecorator(table_.TblPr);
@ -46,51 +48,149 @@ begin
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;
range_array_[i] := self.ProcessTrData(grid_cols, tr, tbl_pr);
end;
function TSPdfTableRange.Do();
begin
for _,row in range_array_ do
for _,range in row do
range.Do();
end;
function TSPdfTableRange.CheckAndAddPage(y: real; offset: real): boolean;
begin
if y - offset < sect_ware_.SectPr.PgMar.Bottom then
begin
page_ := docx_to_pdf_.GetNextPage(page_);
if ifnil(page_) then page_ := docx_to_pdf_.AddPage(sect_ware_);
point := docx_to_pdf_.GetCurrentPoint();
point_.Y := point.Y;
return true;
end
return false;
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);
height := tr_pr.TrHeight.Val;
tcs := tr.Tcs();
tc_x := point_.X;
tc_y := point_.Y;
tc_h := height;
max_height := tc_h;
rows_range_array := array();
for _,tc in tcs do
for i,tc in tcs do
begin
tc_w := grid_cols[i].W;
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;
rect_range.X := tc_x;
rect_range.Y := tc_y;
rect_range.W := tc_w;
rect_range.H := tc_h;
rect_range.Page := page_;
rows_range_array[length(rows_range_array)] := rect_range;
cell_x := tc_x + tbl_pr.TblCellMar.Left.W;
cell_y := tc_y - tbl_pr.TblCellMar.Top.W;
cell_w := tc_w - tbl_pr.TblCellMar.Right.W - tbl_pr.TblCellMar.Left.W;
cell_total_h := 0;
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);
if element.w14paraId="5CEC646C" then
println("???????????");
range := new TSPdfParagraphRange(docx_to_pdf_, page_, 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);
range := new TSPdfTableRange(docx_to_pdf_, page_, 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;
range.X := cell_x;
range.Y := cell_y;
range.W := cell_w;
range.H := tc_h;
range.Calc();
rows_range_array[length(rows_range_array)] := range;
cell_total_h += range.H;
cell_y -= range.H;
end
end
tc_x += tc_w;
if cell_total_h > max_height then max_height := cell_total_h;
end
// 判定是否跨页
total_height := max_height + tbl_pr.TblCellMar.Top.W + tbl_pr.TblCellMar.Bottom.W;
surplus := total_height - (point_.Y - sect_ware_.SectPr.PgMar.Bottom);
if not tc_h and not self.H and surplus > 0 then
begin
for _,range in rows_range_array do
range.H := point_.Y - sect_ware_.SectPr.PgMar.Bottom;
span := sect_ware_.SectPr.PgSz.H - sect_ware_.SectPr.PgMar.Top - sect_ware_.SectPr.PgMar.Bottom;
quotient := surplus div span;
remainder := surplus % span;
println("page_ = {}, quotient = {}, remainder = {}", page_, quotient, remainder);
page := page_;
tc_y := point_.Y;
i := 0;
while i < quotient do
begin
tc_x := point_.X;
tc_y := sect_ware_.SectPr.PgSz.H - sect_ware_.SectPr.PgMar.Top;
tc_h := tc_y - sect_ware_.SectPr.PgMar.Bottom;
page := docx_to_pdf_.GetNextPage(page);
for j:=0 to length(tcs)-1 do
begin
tc_w := grid_cols[i].W;
rect_range := new TSPdfRectRange();
rect_range.X := tc_x;
rect_range.Y := tc_y;
rect_range.W := tc_w;
rect_range.H := tc_h;
rect_range.Page := page;
tc_x += tc_w;
rows_range_array[length(rows_range_array)] := rect_range;
end
i++;
end
if remainder then
begin
tc_x := point_.X;
tc_y := sect_ware_.SectPr.PgSz.H - sect_ware_.SectPr.PgMar.Top;
tc_h := remainder;
page := docx_to_pdf_.GetNextPage(page);
for j:=0 to length(tcs)-1 do
begin
tc_w := grid_cols[i].W;
rect_range := new TSPdfRectRange();
rect_range.X := tc_x;
rect_range.Y := tc_y;
rect_range.W := tc_w;
rect_range.H := tc_h;
rect_range.Page := page;
tc_x += tc_w;
rows_range_array[length(rows_range_array)] := rect_range;
end
end
point_.Y := tc_y - remainder;
self.Y := point_.Y;
page_ := page;
end
else begin
tc_h := tc_h ? tc_h : max_height;
for _,range in rows_range_array do
range.H := tc_h;
point_.Y -= tc_h;
self.Y := point_.Y;
end
return rows_range_array;
end;
@ -118,7 +218,6 @@ 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);

View File

@ -21,13 +21,14 @@ begin
self.Page.EndText();
self.Page.SetRGBFill(0, 0, 0);
{$DEFINE WordToPdfTEST}
{$IFDEF WordToPdfTEST}
self.Page.SetLineWidth(0.5);
self.Page.SetGrayStroke(0.5);
if sysparams["_PDF_TEXT_DEBUG_"] then
begin
self.Page.SetLineWidth(0.1);
self.Page.SetRGBStroke(1.0, 0.5, 0.0);
self.Page.MoveTo(0, self.Y);
self.Page.LineTo(90, self.Y);
self.Page.LineTo(600, self.Y);
self.Page.Stroke();
{$ENDIF}
end
end;