Để xuất một trang tính Excel sang PDF từ Delphi hoặc C++Builder mà không cần cài đặt Office, hãy gọi SaveAsPDF trên một trang tính hoặc sổ làm việc HotXLS. HotXLS là một thành phần Excel VCL tự nhiên, và việc xuất trang tính sang PDF của nó kết xuất phạm vi đã sử dụng của trang tính thành một tệp PDF 1.4 độc lập, ánh xạ các chiều rộng cột Excel và văn bản hiển thị của ô lên các trang A4 với tính năng phân trang tự động nhiều trang. Không có bản sao Excel, không có trình điều khiển máy in (printer driver) và không có DLL bên ngoài nào tham gia vào quá trình kết xuất
HotXLS coi PDF là một định dạng trình bày dữ liệu, một người anh em với các đường dẫn xuất CSV, TSV và HTML của nó, chứ không phải là một công cụ kết xuất chính xác đến từng điểm ảnh. Việc xuất này tái tạo nội dung và bố cục dạng bảng: các giá trị bạn thấy trong lưới, tỷ lệ cột và các đường lưới xung quanh các ô. Khung nhận thức đó rất quan trọng vì nó đặt ra một kỳ vọng thực tế ngay từ đầu, và phần còn lại của bài viết này là về chính xác nơi ranh giới được phân định
Làm thế nào để chuyển đổi Excel sang PDF trong Delphi không cần Office?
Con đường ngắn nhất là một cuộc gọi duy nhất. TXLSWorksheet cung cấp các hàm SaveAsPDF(FileName) và SaveAsPDF(Stream), và TXLSWorkbook cung cấp cùng hai hàm nạp chồng chuyển tiếp đến trang tính đang hoạt động. Mỗi hàm trả về một số nguyên (Integer), 1 khi thành công và -1 khi thất bại, nhờ đó bạn có thể rẽ nhánh dựa trên kết quả mà không cần bao bọc cuộc gọi trong xử lý ngoại lệ của riêng mình
uses
lxHandle;
var
Book: TXLSWorkbook;
begin
Book := TXLSWorkbook.Create;
try
Book.Open('sales-june.xlsx');
// Render the active sheet's used range straight to report.pdf.
if Book.SaveAsPDF('report.pdf') = 1 then
Writeln('PDF written');
finally
Book.Free;
end;
end;
Khi bạn gọi SaveAsPDF trên một trang tính, HotXLS sẽ xuất UsedRange của trang tính đó, hộp bao của mọi ô có dữ liệu. Hàm nạp chồng của sổ làm việc là một sự tiện lợi ủy quyền cho trang tính đang hoạt động, do đó một báo cáo nhiều trang tính sẽ lặp qua các trang tính cần thiết hoặc chọn trang tính đang hoạt động trước cuộc gọi. Không có chế độ xuất toàn bộ sổ làm việc trong một lượt duy nhất ghép nối mọi tab: mỗi cuộc gọi kết xuất một trang tính hoặc một phạm vi
HotXLS chuyển đổi một phạm vi đã sử dụng thành các trang PDF như thế nào?
HotXLS duyệt qua phạm vi đã sử dụng theo từng ô một và sắp xếp nó thành một lưới được phân trang. Hình học cột được lấy trực tiếp từ Excel: chiều rộng của mỗi cột được chuyển đổi từ đơn vị chiều rộng của Excel sang các điểm in ấn (typographic points), với một mức tối thiểu để không cột nào bị thu hẹp thành một dải cực nhỏ. Khi tổng chiều rộng của các cột lớn hơn trang khả dụng, HotXLS sẽ thu nhỏ chúng một cách đồng đều để vừa vặn; khi chúng đã vừa vặn, nó giữ nguyên chiều rộng tự nhiên thay vì kéo giãn chúng trên toàn bộ trang tính
Các hàng sau đó chảy xuống trang cho đến khi hàng tiếp theo vượt qua lề dưới, tại thời điểm đó HotXLS mở một trang mới và tiếp tục, do đó một trang tính nghìn hàng tự phân trang mà không cần bạn phải theo dõi ngắt trang. Mỗi ô in ra FormattedText của nó, chuỗi hiển thị được tạo ra sau khi định dạng số được áp dụng, vì thế một ngày tháng hiển thị giống như ngày tháng trang tính hiển thị và một ô tiền tệ giữ nguyên các ký tự phân tách hàng nghìn và ký hiệu của nó. Văn bản vượt quá giới hạn cột của nó sẽ bị cắt bớt theo chiều rộng của ô thay vì tràn sang ô bên cạnh
Kiểm soát hướng trang, lề trang và kích thước phông chữ
Đối với bất kỳ thứ gì vượt ngoài bố cục mặc định, hãy điều khiển trực tiếp bộ xuất. TXLSPDFExport là lớp đằng sau các hàm tiện ích một dòng, và it công khai ba thuộc tính: Orientation (xlsPdfPortrait hoặc xlsPdfLandscape, mặc định là hướng dọc), Margin (điểm, mặc định 40), và FontSize (điểm, mặc định 9). Hãy thiết lập chúng trước khi bạn gọi SaveAsPDF và toàn bộ tài liệu sẽ áp dụng các thiết lập đó
uses
lxHandle, lxPDF;
var
Book: TXLSWorkbook;
Exporter: TXLSPDFExport;
begin
Book := TXLSWorkbook.Create;
try
Book.Open('wide-ledger.xlsx');
Exporter := TXLSPDFExport.Create;
try
Exporter.Orientation := xlsPdfLandscape; // fit wide sheets on the page
Exporter.Margin := 28; // tighter page margin, in points
Exporter.FontSize := 8; // denser rows
Exporter.SaveAsPDF(Book.ActiveSheet, 'ledger.pdf');
finally
Exporter.Free;
end;
finally
Book.Free;
end;
end;
TXLSPDFExport cũng chấp nhận một phạm vi thay vì toàn bộ trang tính thông qua SaveAsPDF(Range: IXLSRange; ...), đây là cách bạn xuất một khối tổng hợp ra khỏi một trang tính vốn chứa cả các phép tính nháp. Hàm nạp chồng phạm vi đó cũng chính là hàm mà tiện ích trang tính dựa vào ở bên trong, do đó bố cục, tỷ lệ và phân trang hoạt động giống hệt nhau cho dù bạn bàn giao toàn bộ phạm vi đã sử dụng hay một vùng chọn được chọn thủ công
var
Book: TXLSWorkbook;
Exporter: TXLSPDFExport;
Summary: IXLSRange;
begin
Book := TXLSWorkbook.Create;
try
Book.Open('quarter.xlsx');
// Export only the summary block, not the scratch columns beside it.
Summary := Book.Sheets[1].Range['A1', 'F20'];
Exporter := TXLSPDFExport.Create;
try
Exporter.SaveAsPDF(Summary, 'summary.pdf');
finally
Exporter.Free;
end;
finally
Book.Free;
end;
end;
Tại sao HotXLS không nhúng phông chữ: sự đánh đổi giữa Helvetica và WinAnsi
HotXLS ghi văn bản bằng phông chữ Helvetica tích hợp sẵn của PDF và mã hóa WinAnsiEncoding, một lựa chọn không phụ thuộc có chủ ý nhưng đi kèm với một giới hạn thực tế. Bởi vì Helvetica là một trong 14 phông chữ tiêu chuẩn mà mọi trình đọc PDF tương thích đều có sẵn, bộ xuất hoàn toàn không nhúng bất kỳ chương trình phông chữ nào: tệp tin giữ dung lượng nhỏ và mở được ở bất kỳ đâu, không có gì cần cấp phép hay phân phối đi kèm. Cái giá của lựa chọn đó là kho ký tự mà trang có thể hiển thị
WinAnsiEncoding bao trùm bộ Windows-1252, vì vậy văn bản Latin, dấu câu thông dụng và các dấu tiếng Tây Âu thông thường được kết xuất chính xác, và HotXLS đưa một số ký tự in ấn, dấu ngoặc kép dạng cong, dấu gạch ngang (en dash, em dash) và ký hiệu euro vào các vị trí CP1252 của chúng. Các ký tự nằm ngoài phạm vi đó như chữ Hán CJK, chữ Kirin, tiếng Hy Lạp và tiếng Ả Rập sẽ chuyển thành dấu hỏi chấm trên trang giấy. Nếu các trang tính của bạn chứa văn bản không phải hệ Latin, bộ xuất này là công cụ không phù hợp, và một trình kết xuất PDF đầy đủ định dạng mới là lựa chọn vừa vặn
Nơi việc xuất trang tính sang PDF dừng lại
HotXLS kết xuất nội dung và cấu trúc, chứ không phải toàn bộ kiểu dáng trực quan của trang tính. Màu tô ô, kiểu đường viền trên mỗi cạnh, phông chữ và màu sắc trên mỗi ô, biểu đồ và các hình ảnh nhúng nằm ngoài những gì bộ xuất vẽ ra; những gì bạn nhận được là lưới văn bản với các đường lưới đồng nhất. Đó là cùng một hợp đồng mà các bộ xuất HTML và RTF tuân thủ, và nó là lựa chọn phù hợp cho một báo cáo hoặc một lượt bàn giao dữ liệu nơi các con số mang ý nghĩa còn chủ đề hình ảnh thì không
Khi mục tiêu là một tài liệu có kiểu dáng và nhất quán thương hiệu, mô hình thông thường là tập hợp các con số trong một mẫu bảng tính trước, điều mà quy trình tạo báo cáo dựa trên mẫu (template-driven report generation workflow) bao trùm chi tiết. Và bởi vì không có phần nào trong tiến trình này chạm tới COM hoặc một thực thể Excel đang chạy, đường ống dữ liệu phù hợp với cùng một mô hình tự động hóa không cần Office mà HotXLS sử dụng xuyên suốt: mã Pascal thuần túy, có thể triển khai trên máy chủ không giao diện (headless server), không có tính liên tác (interop) nào cần cấp phép hay giám sát
Tệp PDF độc lập, chính xác từng byte
HotXLS tự xây dựng cấu trúc tệp PDF bằng tay và tính toán bảng tham chiếu chéo (cross-reference table) của nó từ các độ lệch byte (byte offsets) chính xác, đây là lý do đầu ra mở được trong mọi trình đọc. Khi tuần tự hóa từng đối tượng, HotXLS ghi lại độ lệch bắt đầu của đối tượng đó trước khi thêm vào các byte của nó, sau đó tiến vị trí chạy lên theo độ dài nó vừa ghi, nhờ đó bảng xref đáp xuống chính xác trên từng đối tượng và startxref đánh dấu nơi bảng đó bắt đầu. Một trình đọc phát hiện các độ lệch đó lệch đi dù chỉ một byte cũng sẽ từ chối toàn bộ tệp tin, điều này làm cho độ lệch tự tính toán trở thành hợp đồng chịu tải (load-bearing contract) của bộ xuất
Hợp đồng đó mang lại một hậu quả nghiêm ngặt đáng được biết. Nút Pages được ghi đầu tiên dưới dạng đối tượng 1, nhưng danh sách các trang con của nó chưa được biết cho đến khi mọi trang đã được phát ra, vì thế HotXLS dự phòng nó như một trình giữ chỗ và chắp vá các phần tử con cuối cùng cùng số lượng trước khi lượt chạy độ lệch diễn ra, tuyệt đối không bao giờ sau đó. Một khi các byte của một đối tượng được đo lường cho bảng xref, chúng sẽ bị đóng băng: việc thay đổi dù chỉ một byte sau đó sẽ làm trượt mọi độ lệch tiếp theo và làm hỏng bảng dữ liệu. Đó là một kỷ luật nhỏ đổi lại một tệp PDF 1.4 hợp lệ theo tiêu chuẩn mà không cần thư viện nào bên dưới
Các phương thức SaveAsPDF và lớp TXLSPDFExport hiển thị ở đây đi kèm với HotXLS Delphi Excel Component, bên cạnh các bộ xuất CSV, HTML, RTF và API trang tính đầy đủ dành cho Delphi và C++Builder