PDFlibPas ไหลข้อความที่เก็บไว้ผ่านคอลัมน์ความกว้างเท่ากันตั้งแต่ 1 ถึง 64 คอลัมน์ด้วย DrawTextFlowColumns และตัดบรรทัดด้วยการแบ่งพยางค์ตามภาษาแบบมีขอบเขต เมื่อคุณเรียก SetTextFlowLanguage และ SetTextFlowHyphenation รองรับภาษาทั้งหมดเก้าภาษา และภาษาสามารถสืบทอดมาจากค่า /Lang ใน Catalog ของเอกสารได้ แทนที่จะต้องตั้งค่าแยกทีละโฟลว์
ทั้งสองฟีเจอร์นี้มีอยู่ด้วยเหตุผลเดียวกัน คือคอลัมน์แคบเป็นจุดที่การตัดบรรทัดแบบไม่ฉลาดเลิกดูเหมือนงานจัดพิมพ์และเริ่มดูเหมือนรายงานบั๊กแทน
เหตุใดข้อความจัดคอลัมน์จึงพังในคอลัมน์แคบ
เพราะการจัดคอลัมน์จะกระจายพื้นที่ว่างที่เหลือลงไปในช่องว่างระหว่างคำของแต่ละบรรทัด และปริมาณที่เหลือขึ้นอยู่กับว่าอะไรพอดีกับบรรทัดนั้น ในความกว้างมาก ๆ พื้นที่เหลือจะน้อยจนสายตาไม่ทันสังเกต แต่ถ้าลดความกว้างลงครึ่งหนึ่ง คำยาวคำเดียวที่ใส่ไม่พอดีจะถูกดันไปบรรทัดถัดไป ทำให้คำก่อนหน้าต้องรับพื้นที่ว่างทั้งหมดแทน สามบรรทัดแบบนี้ติดกันจะเกิดเป็นช่องว่างสีขาวแนวตั้งที่นักจัดพิมพ์เรียกว่า rivers และผู้อ่านจะรู้สึกว่าข้อความอ่านตามยากโดยไม่รู้สาเหตุ
การแบ่งพยางค์แก้ที่ต้นเหตุแทนอาการ ด้วยการยอมให้ตัดคำได้จากภายในคำ คำประสมในภาษาเยอรมันและดัตช์ทำให้เรื่องนี้ต่อรองไม่ได้เลย: คำนามยาว 24 ตัวอักษรในคอลัมน์กว้าง 60 มิลลิเมตรไม่มีทางออกที่ดีถ้าไม่มีจุดตัดคำ ภาษาอังกฤษทนต่อการไม่มีจุดตัดคำได้ดีกว่า นั่นคือเหตุผลที่ผลิตภัณฑ์ที่ออกแบบมาสำหรับภาษาอังกฤษก่อนมักส่งมอบโค้ดเลย์เอาต์ที่พังทันทีที่ลูกค้าชาวเยอรมันลองใช้
รองรับภาษาใดบ้าง และภาษามาจากไหน
การแบ่งพยางค์รองรับภาษาอังกฤษ เยอรมัน ดัตช์ ฝรั่งเศส สเปน อิตาลี โปรตุเกส รัสเซีย และตุรกี ตั้งค่าได้โดยตรงต่อโฟลว์ด้วย SetTextFlowLanguage หรือปล่อยให้สืบทอดมาจากรายการ /Lang ใน Catalog ของเอกสาร ซึ่งเป็นค่าที่เอกสารแบบมีแท็กและเข้าถึงได้อยู่แล้วมีติดตัวมาโดยธรรมชาติ
การสืบทอดค่านี้คุ้มค่าที่จะใช้มากกว่าการเขียนทับ เอกสารที่ประกาศภาษาไว้ใน Catalog กำลังบอกข้อเท็จจริงเดียวกันแก่โปรแกรมอ่านหน้าจอ ตัวทำดัชนีค้นหา และระบบแบ่งพยางค์จากจุดเดียว และจุดเดียวก็คือที่ที่ข้อเท็จจริงควรอยู่ ถ้าคุณสร้างผลลัพธ์แบบมีแท็กอยู่แล้วตามที่อธิบายไว้ใน การติดแท็กอัตโนมัติสำหรับ PDF ที่เข้าถึงได้ รายการภาษาก็ถูกตั้งไว้แล้ว และโฟลว์สามารถทำตามได้เลย
var
Lib: TPDFlib;
Flow, Drawn: Integer;
begin
Lib := TPDFlib.Create;
try
Lib.SetOrigin(1);
Lib.AddTrueTypeFont('Georgia', 1);
Lib.SetTextSize(10.5);
Flow := Lib.NewTextFlow(ArticleBody);
try
Lib.SetTextFlowLanguage(Flow, 'de');
// เปิดใช้งาน อย่างน้อย 3 ตัวอักษรก่อนจุดตัด และ 3 ตัวอักษรหลังจุดตัด
Lib.SetTextFlowHyphenation(Flow, 1, 3, 3);
Lib.SetTextFlowMinLines(Flow, 2); // ไม่ปล่อยให้เหลือบรรทัดเดียวโดดเดี่ยว
repeat
// สามคอลัมน์ในพื้นที่กว้าง 480 pt ร่องคอลัมน์ 18 pt แบบสมดุล
Drawn := Lib.DrawTextFlowColumns(Flow, 72, 720, 480, 620, 3, 18, 1);
if (Drawn = 0) or (Lib.TextFlowFinished(Flow) = 1) then
Break;
Lib.NewPage;
until False;
finally
Lib.ReleaseTextFlow(Flow);
end;
Lib.SaveToFile('newsletter.pdf');
finally
Lib.Free;
end;
end;
MinPrefix และ MinSuffix เป็นเรื่องการจัดพิมพ์ ไม่ใช่การตรวจสอบความถูกต้อง
จำนวนเต็มสองตัวหลังแฟล็กเปิดใช้งานกำหนดจำนวนตัวอักษรขั้นต่ำที่ต้องเหลืออยู่ก่อนและหลังจุดตัด ค่าเริ่มต้นแบบระมัดระวังคือสามและสาม ซึ่งสไตล์การจัดพิมพ์ส่วนใหญ่ยอมรับได้ ค่าสองและสองจะให้โอกาสตัดคำมากขึ้นแต่ผลลัพธ์จะดูไม่สวยงามอย่างเห็นได้ชัด เพราะเศษคำสองตัวอักษรที่ห้อยอยู่ท้ายบรรทัดจะดูเหมือนพิมพ์ผิด
เพิ่มค่าต่ำสุดขึ้นเมื่อขนาดตัวอักษรใหญ่ เพราะเศษคำแต่ละส่วนจะเด่นชัดทางสายตา และลดค่าลงเฉพาะเมื่อคอลัมน์แคบจริง ๆ และคุณตัดสินใจแล้วว่าความกระชับสำคัญกว่าความสะอาดตา นี่เป็นการตัดสินใจตามสไตล์การจัดพิมพ์ขององค์กร ไม่ใช่การตัดสินใจทางเทคนิค ซึ่งเป็นเหตุผลที่มันเป็นพารามิเตอร์ ไม่ใช่ค่าคงที่
คำว่า “balanced” ในที่นี้หมายความว่าอย่างไรกันแน่
พารามิเตอร์ Balance จะเปลี่ยนพฤติกรรมเฉพาะตอนท้ายของข้อความเท่านั้น เมื่อเปิดการสมดุลไว้ คอลัมน์จะถูกย่อให้มีจำนวนบรรทัดเท่ากันพอดี เมื่อสิ่งที่เหลือทั้งหมดพอดีกับพื้นที่ ซึ่งเป็นสิ่งที่ป้องกันไม่ให้หน้าสุดท้ายแสดงคอลัมน์เต็มสองคอลัมน์และคอลัมน์ที่สามมีเพียงบรรทัดเดียวโดดเดี่ยว เมื่อข้อความไม่พอดีกับพื้นที่ ทุกคอลัมน์จะคงความสูงเต็มไว้ เพื่อให้หน้านั้นบรรจุข้อความได้มากที่สุดเท่าที่จะทำได้ และส่วนที่เหลือจะไปต่อในหน้าถัดไป
ความไม่สมมาตรแบบนี้คือค่าเริ่มต้นที่ถูกต้องสำหรับเอกสารต่อเนื่อง การสมดุลกลางบทความที่กำลังไหลอยู่จะสิ้นเปลืองพื้นที่แนวตั้งทุกหน้าเพื่อผลด้านความสวยงามที่ไม่มีใครเห็น เพราะคอลัมน์เต็มอยู่แล้ว การสมดุลตอนท้ายคือจุดที่สายตาจะสังเกตเห็นได้จริง และนั่นคือจุดที่มันถูกนำไปใช้พอดี
การตัดบรรทัดวัดจากทั้งคำ
อัลกอริทึมการตัดบรรทัดวัดทั้งคำแทนที่จะสะสมความกว้างตัวอักษรทีละตัว และสำรองการค้นหาแบบมีขอบเขตไว้สำหรับโทเคนขนาดใหญ่เกินที่ใส่บรรทัดไม่ได้เลย เช่น URL หรือหมายเลขทะเบียน ทำให้กรณีทั่วไปทำงานเร็วและกรณีผิดปกติมีขอบเขตจำกัด แทนที่จะเป็นในทางกลับกัน
ยัติภังค์แบบเลือกได้และยัติภังค์อัตโนมัติจะถูกแสดงผลก็ต่อเมื่อจุดตัดที่มันทำเครื่องหมายไว้เป็นจุดตัดที่ถูกเลือกใช้จริง เรื่องนี้ฟังดูเป็นเรื่องพื้นฐาน แต่กลับเป็นข้อบกพร่องคลาสสิก: การเขียนแบบไม่รอบคอบจะเขียนตัวอักษรยัติภังค์ลงไประหว่างการวัดขนาด และถ้าจุดตัดเปลี่ยนไป ยัติภังค์นั้นก็จะค้างอยู่กลางบรรทัด ไม่มีอะไรจะดูเหมือนเอนจินข้อความที่พังมากไปกว่ายัติภังค์ที่หลงเหลืออยู่กลางคำ
var
Lib: TPDFlib;
Flow, Needed: Integer;
begin
// ตัดสินใจเรื่องเลย์เอาต์ก่อนวาดสิ่งใด
Flow := Lib.NewTextFlow(ArticleBody);
try
Lib.SetTextFlowLanguage(Flow, 'fr');
Lib.SetTextFlowHyphenation(Flow, 1, 3, 3);
// จำนวนบรรทัดที่ข้อความส่วนที่เหลือต้องการที่ความกว้างหนึ่งคอลัมน์
Needed := Lib.MeasureTextFlow(Flow, 148);
if Needed > 3 * LinesPerColumn then
UseTwoPageSpread
else
UseSinglePage;
Lib.DrawTextFlowColumns(Flow, 72, 720, 480, 620, 3, 18, 1);
if Lib.TextFlowFinished(Flow) <> 1 then
CarryOver(Lib.GetTextFlowRemaining(Flow));
finally
Lib.ReleaseTextFlow(Flow);
end;
end;
คงการตั้งค่าฟอนต์ให้เหมือนกันในทุกกล่องข้อความ
มีกฎข้อเดียวที่ควบคุมเลย์เอาต์แบบไหลทุกแบบ และควรพูดตรง ๆ ว่า: DrawTextFlow, DrawTextFlowColumns และ MeasureTextFlow ล้วนตัดบรรทัดโดยใช้ฟอนต์ที่เลือกไว้ ณ ขณะที่ถูกเรียกใช้ หากเปลี่ยนฟอนต์หรือขนาดระหว่างสองกล่องข้อความในโฟลว์เดียวกัน หรือขึ้นหน้าใหม่โดยไม่เลือกฟอนต์ใหม่อีกครั้ง กล่องที่สองจะตัดบรรทัดต่างไปจากที่กล่องแรกวัดไว้
อาการนี้ชวนหงุดหงิดเพราะดูเหมือนเกิดขึ้นเป็นครั้งคราว: ข้อความที่พอดีในหน้าหนึ่งกลับล้นในหน้าสอง หรือจำนวนบรรทัดที่วัดไว้ไม่ตรงกับที่วาดจริง เลือกฟอนต์ครั้งเดียวก่อนเข้าลูป แล้วเลือกใหม่อีกครั้งหลัง NewPage ทุกครั้ง แล้วโฟลว์จะทำงานถูกต้อง เมื่อมีหลายสคริปต์ปนกันในข้อความเดียวกัน การแก้ปัญหาที่อธิบายไว้ใน การสำรองฟอนต์อัตโนมัติสำหรับข้อความ CJK และอิโมจิ จะใช้ได้ทั้งกับการวัดและการวาด ทำให้ความกว้างยังคงสอดคล้องกันตลอดช่วงที่ใช้ฟอนต์สำรองด้วย
สำหรับเลย์เอาต์รายงานที่โฟลว์เป็นเพียงองค์ประกอบหนึ่งท่ามกลางส่วนหัว ส่วนท้าย และบล็อกข้อมูล รูปแบบการประกอบใน เอนจินรายงานจากชุดข้อมูล ผสานเข้ากับโฟลว์คอลัมน์ได้อย่างลงตัว: วัดก่อน จัดวางองค์ประกอบตายตัวก่อน แล้วจึงมอบพื้นที่ที่เหลืออยู่ให้กับโฟลว์
PDFlibPas เป็นไลบรารี PDF สำหรับ Delphi, C++Builder และ Lazarus และวงจรชีวิตของ TextFlow ทั้งหมด ตั้งแต่การสร้าง การวาด การวัด การตรวจสอบ การย้อนกลับ ไปจนถึงการปล่อยทรัพยากร ก็เปิดให้ใช้งานผ่านอินเทอร์เฟซ DLL และ ActiveX ด้วยเช่นกัน เอกสารฉบับเต็มอยู่ที่ หน้าไลบรารี PDF สำหรับ Delphi ของ PDFlibPas