כדי לייצא גיליון עבודה של Excel ל-PDF מדלפי או מ-C++Builder ללא Office מותקן, קרא ל-SaveAsPDF בגיליון עבודה או בחוברת עבודה של HotXLS. HotXLS הוא רכיב Excel מקורי של VCL, וייצוא גיליון העבודה שלו ל-PDF מרנדר את הטווח המשומש (used range) של הגיליון לקובץ PDF 1.4 עצמאי, וממפה את רוחבי העמודות של Excel ואת טקסט התצוגה של התאים לעמודי A4 עם מספור עמודים אוטומטי מרובה עמודים. שום עותק של Excel, מנהל התקן מדפסת או DLL חיצוני אינם משתתפים ברינדור
HotXLS מתייחסת ל-PDF כפורמט להצגת נתונים, אח לנתיבי הייצוא שלה ל-CSV, TSV ו-HTML, ולא כמנוע רינדור מדויק ברמת הפיקסל. הייצוא משחזר את התוכן והפריסה הטבלאיים: הערכים שאתה רואה בגריד, פרופורציות העמודות וקווי הגריד סביב התאים. מסגור זה חשוב מכיוון שהוא מציב ציפיות כנות מראש, והמשך מאמר זה עוסק בדיוק במקום שבו עובר הגבול
כיצד ממירים Excel ל-PDF בדלפי ללא Office?
הנתיב הקצר ביותר הוא קריאה בודדת. TXLSWorksheet חושף את SaveAsPDF(FileName) ואת SaveAsPDF(Stream), ו-TXLSWorkbook חושפת את שתי אותן העמסות (overloads) המנתבות לגיליון הפעיל. כל אחת מחזירה Integer, 1 בהצלחה ו- -1 בכשל, כך שתוכל להסתעף לפי התוצאה מבלי לעטוף את הקריאה בטיפול בחריגות משלך
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;
כשר אתה קורא ל-SaveAsPDF בגיליון עבודה, HotXLS מייצאת את ה-UsedRange של אותו גיליון, התיבה החוסמת של כל תא מאוכלס. העמסת חוברת העבודה היא נוחות המאצילה לגיליון הפעיל, כך שדוח מרובה גיליונות עובר בלולאה על הגיליונות שהוא צריך או בוחר את הגיליון הפעיל לפני הקריאה. אין מצב של חוברת עבודה שלמה המשרשר את כל הלשוניות במעבר אחד: כל קריאה מרנדרת גיליון אחד או טווח אחד
כיצד HotXLS הופכת טווח משומש לעמודי PDF?
HotXLS עוברת על הטווח המשומש תא אחר תא ופורסת אותו כגריד ממוספר לעמודים. גיאומטריית העמודות מגיעה ישירות מ-Excel: כל רוחב עמודה מומר מיחידת הרוחב של Excel לנקודות טיפוגרפיות, עם רצפת מינימום כדי שאף עמודה לא תתכווץ לפס דק. כאשר העמודות יחד רחבות יותר מהעמוד השמיש, HotXLS מקטינה אותן באופן אחיד כדי שיתאימו; כאשר הן כבר מתאימות, היא משאירה אותן ברוחבן הטבעי במקום למתוח אותן לרוחב הגיליון
השורות זורמות במורד העמוד עד שהשורה הבאה תחצה את השוליים התחתונים, ואז HotXLS פותחת עמוד חדש וממשיכה, כך שגיליון של אלף שורות ממוספר לעמודים מעצמו ללא צורך ברישום מעברי עמוד מצדך. כל תא מדפיס את ה-FormattedText שלו, מחרוזת התצוגה המופקת לאחר החלת פורמט המספר, כך שתאריך מופיע כתאריך שהגיליון מציג ותא מטבע שומר על מפרידי האלפים והסמל שלו. טקסט הגולש מעבר לעמודה שלו נגזר לרוחב התא במקום לגלוש לשכן
שליטה בכיוון הנייר, השוליים וגודל הגופן
עבור כל דבר מעבר לפריסת ברירת המחדל, הפעל את המייצא ישירות. TXLSPDFExport היא המחלקה שמאחורי עוזרי השורה הבודדת, והיא מפרסמת שלושה מאפיינים: Orientation (xlsPdfPortrait או xlsPdfLandscape, לאורך כברירת מחדל), Margin (בנקודות, ברירת מחדל 40), ו-FontSize (בנקודות, ברירת מחדל 9). הגדר אותם לפני שתקרא ל-SaveAsPDF והמסמך כולו יאמץ אותם
TXLSPDFExport מקבלת גם טווח במקום גיליון שלם דרך SaveAsPDF(Range: IXLSRange; ...), וכך מייצאים בלוק סיכום מתוך גיליון המחזיק גם חישובי טיוטה. העמסת טווח זו היא אותה אחת שעוזר גיליון העבודה נשען עליה פנימית, כך שהפריסה, הגדלת/הקטנת התצוגה והמספור לעמודים מתנהגים באופן זהה בין אם אתה מגיש לה טווח משומש מלא ובין אם בחירה שנבחרה ידנית
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 מקבלת גם טווח במקום גיליון שלם דרך SaveAsPDF(Range: IXLSRange; ...), וכך מייצאים בלוק סיכום מתוך גיליון המחזיק גם חישובי טיוטה. העמסת טווח זו היא אותה אחת שעוזר גיליון העבודה נשען עליה פנימית, כך שהפריסה, הגדלת/הקטנת התצוגה והמספור לעמודים מתנהגים באופן זהה בין אם אתה מגיש לה טווח משומש מלא ובין אם בחירה שנבחרה ידנית
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;
מדוע HotXLS אינה מטמיעה גופנים: הפשרה בין Helvetica ל-WinAnsi
HotXLS כותבת את הטקסט עם גופן Helvetica המובנה של PDF ועם WinAnsiEncoding, בחירה מכוונת ללא תלויות עם מגבלה אמיתית אחת. מכיוון ש-Helvetica הוא אחד מ-14 גופני הבסיס שכל קורא PDF תואם כבר נושא, המייצא אינו מטמיע שום קובץ גופן כלל: הקובץ נשאר קטן ונפתח בכל מקום, ללא צורך ברישוי או במשלוח רכיבים נלווים. המחיר של בחירה זו הוא רפרטואר התווים שהעמוד יכול להציג
WinAnsiEncoding מכסה את סט Windows-1252, כך שטקסט לטיני, סימני פיסוק נפוצים והדגשים הרגילים של מערב אירופה מרונדרים כהלכה, ו-HotXLS מקפלת קומץ תווים טיפוגרפיים, מירכאות מעוקלות, מקפי en ו-em, וסימן האירו לחריצים שלהם ב-CP1252. תווים מחוץ לטווח זה, כגון סימניות CJK, קירילית, יוונית וערבית, קורסים לסימן שאלה בעמוד. אם הגיליונות שלך נושאים טקסט שאינו לטיני, מייצא זה הוא הכלי הלא נכון, ומנוע רינדור PDF בעל עיצוב מלא הוא הפתרון המתאים
היכן שהייצוא מגיליון עבודה ל-PDF נעצר
HotXLS מרנדרת תוכן ומבנה, ולא את הסגנון הוויזואלי המלא של הגיליון. מילויי תאים, סגנונות גבול לכל קצה, גופנים וצבעים לכל תא, תרשימים ותמונות מוטמעות נמצאים מחוץ למה שהמייצא מצייר; מה שמתקבל הוא גריד הטקסט עם קווי גריד אחידים. זהו אותו חוזה שנתיבי הייצוא ל-HTML ו-RTF מכבדים, והוא הנכון עבור דוח או מסירת נתונים שבהם המספרים נושאים את המשמעות והעיצוב לא
כאשר המטרה היא מסמך מעוצב ועקבי מבחינת מותג, התבנית הרגילה היא לאסוף תחילה את המספרים בתבנית של גיליון עבודה, תהליך שזרימת העבודה של הפקת דוחות מבוססת תבניות מכסה לעומק. ומכיוון ששום דבר מזה אינו נוגע ב-COM או במופע פעיל של Excel, צינור העבודה מתאים לאותו מודל אוטומציה ללא Office ש-HotXLS משתמשת בו לכל אורך הדרך: Pascal טהור, שניתן לפריסה בשרת ללא ממשק משתמש (headless), ללא צורך ברישוי או בתחזוקה של תיווך מערכות
קובץ ה-PDF העצמאי, בית אחר בית
HotXLS בונה את מבנה קובץ ה-PDF ידנית ומחשבת את טבלת ההפניות הנגדיות (cross-reference) שלו מהיסטים (offsets) מדויקים של בתים, וזו הסיבה שהפלט נפתח בכל קורא. כשהיא מבצעת סריאליזציה לכל אובייקט, HotXLS רושמת את היסט ההתחלה של אותו אובייקט לפני הוספת הבתים שלו, ואז מקדמת את המיקום הנוכחי באורך שהיא זה עתה כתבה, כך שטבלת ה-xref נוחתת בדיוק על כל אובייקט ו-startxref מסמן היכן מתחילה אותה טבלה. קורא המוצא את ההיסטים הללו מוסטים אפילו בבית אחד פוסל את הקובץ כולו, מה שהופך את ההיסט המחושב עצמאית לחוזה נושא העומס של המייצא
לחוזה זה יש תוצאה קשיחה אחת שראוי להכיר. צומת ה-Pages נכתב ראשון כאובייקט 1, אך רשימת עמודי הבנים שלו אינה ידועה עד שכל עמוד נפלט, ולכן HotXLS שומרת אותו כממלא מקום (placeholder) ומעדכנת (patches) את הבנים והספירה הסופיים לפני הרצת מעבר ההיסטים, ולעולם לא אחריו. ברגע שבתים של אובייקט נמדדים עבור ה-xref, הם מוקפאים: שינוי של בית בודד לאחר מכן יסיט כל היסט עוקב וישחית את הטבלה. זוהי משמעת קטנה המקנה קובץ PDF 1.4 תקני ותואם תקנים ללא שום ספרייה מתחתיו
שיטות ה-SaveAsPDF ומחלקת TXLSPDFExport המוצגות כאן מגיעות עם HotXLS Delphi Excel Component, לצד מייצאי ה-CSV, HTML ו-RTF וממשק ה-API המלא של גיליון עבודה עבור דלפי ו-C++Builder