2 คะแนน โดย GN⁺ 2023-09-05 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • หากต้องการเปลี่ยน เนื้อหาข้อความ ใน PDF โดยไม่ใช้เครื่องมือ PDF เชิงพาณิชย์ ต้องคลายสตรีมที่ถูกบีบอัด แล้วไล่ตามการเข้ารหัสของแต่ละฟอนต์ เพื่อเปลี่ยนข้อความต้นฉบับและข้อความแทนที่ด้วยวิธีเดียวกัน
  • PDF จำนวนมากไม่ได้เก็บข้อความจริงของเอกสารเป็นข้อความธรรมดา แต่เก็บเป็น สตรีมที่ถูกบีบอัด และสตริงที่ดูเหมือนเลขฐานสิบหก โดยสามารถใช้ qpdf --qdf --object-streams=disable เพื่อคลายให้อยู่ในรูปที่ใกล้เคียงกับการแก้ไขได้
  • บล็อกข้อความประกอบด้วยคำสั่ง PDF เช่น BT, Tf, Td, Tj, ET และค่าอย่าง <002a004800570003003600480057> Tj อาจไม่ใช่ Unicode code point แบบตรงไปตรงมา
  • หาก PDF มี ToUnicode mapping แยกตามฟอนต์ สามารถใช้ pdffonts ตรวจสอบว่า emb และ uni เป็น yes หรือไม่ และไล่ตาม reference อย่าง /ToUnicode 19 0 R เพื่อค้นหาตารางเข้ารหัสได้
  • วิธีนี้ยากที่จะใช้ได้ทั่วไปกับทุกไฟล์เพราะความซับซ้อนของมาตรฐาน PDF แต่ใน PDF บางไฟล์สามารถหา encoding ของข้อความต้นฉบับแล้วแทนที่ข้อความด้วย find-and-replace ได้

คลายสตรีมข้อความ PDF ที่ถูกบีบอัด

  • เมื่อเปิด PDF ด้วย text editor อาจอ่านโครงสร้างบางส่วนได้ แต่ไม่เห็นข้อความจริงของเอกสาร
  • PDF จำนวนมากเก็บข้อมูลข้อความใน รูปแบบที่ถูกบีบอัด
  • สามารถใช้ qpdf คลายสตรีมข้อความที่ถูกบีบอัดเพื่อตรวจสอบได้
    • บน Mac มี homebrew formula
    • ใน Linux distribution ก็มีเครื่องมือที่เกี่ยวข้องให้ใช้เช่นกัน
qpdf --qdf --object-streams=disable in.pdf out.pdf
  • หลังแก้ไขแล้วสามารถบีบอัดสตรีมกลับได้
qpdf out-edited.pdf out-recompressed.pdf
  • คำสั่งบีบอัดกลับให้ข้อผิดพลาด แต่ PDF ที่ได้ยังอ่านได้ใน Preview

ค้นหาข้อความในคำสั่ง PDF

  • แม้คลายการบีบอัดแล้ว ข้อความก็ยังคงอยู่ภายในบล็อกคำสั่ง PDF
  • บล็อกข้อความพื้นฐานมีรูปแบบดังนี้
BT
  /Font_0 12 Tf
  288 720 Td
  <002a004800570003003600480057> Tj
ET
  • ตาม PDF Reference บล็อกนี้ทำงานตามลำดับดังนี้
    • เริ่ม text object
    • ตั้งค่า ฟอนต์และขนาด ที่จะใช้
    • กำหนดตำแหน่งเริ่มต้นบนหน้า
    • วาด glyph ของสตริง ณ ตำแหน่งนั้น
    • จบ text object

เหตุผลที่อ่านข้อความไม่ได้ทันที

  • ค่าอย่าง <002a004800570003003600480057> ดูเหมือนสตริงเลขฐานสิบหก แต่อาจไม่ใช่รายการ Unicode code point แบบตรงไปตรงมา
  • PDF มีวิธีระบุ encoding ได้หลายแบบ และสามารถรวม encoding ที่ผู้ใช้กำหนดเอง ไว้ภายในไฟล์ได้
  • encoding เหล่านี้ส่วนใหญ่สามารถ map ไปยัง Unicode code point ได้
  • ขั้นตอนนี้ตั้งอยู่บนสมมติฐานว่า PDF ที่กำลังทำงานด้วยมี embedded encoding อยู่
    • ไม่ครอบคลุมวิธีจัดการกรณีอื่น

ตรวจสอบฟอนต์และ Unicode mapping

  • encoding ของข้อความใน PDF เชื่อมโยงกับ ฟอนต์ เฉพาะ
  • pdffonts แสดงข้อมูลเกี่ยวกับฟอนต์และ encoding ภายใน PDF
$ pdffonts sample.pdf
name                                 type              emb sub uni prob object ID
------------------------------------ ----------------- --- --- --- ---- ---------
CLDQZB+TrebuchetMS,Bold              CID TrueType      yes yes yes           9  0
YQBAIZ+TrebuchetMS                   CID TrueType      yes yes yes          10  0
  • ฟิลด์ที่ควรตรวจสอบมีดังนี้
    • emb: หมายถึงฟอนต์ถูก embed อยู่ใน PDF
    • uni: หมายถึงมี Unicode mapping
  • หากทั้งสองค่าเป็น yes ก็มีโอกาสค้นหา mapping ที่ต้องการได้
  • font identifier อย่าง /Font_0 ในตัวอย่างอาจสัมพันธ์กับชื่อฟอนต์ใน output ของ pdffonts แล้วแต่กรณี
    • ในกรณีนั้น /Font_0 ชี้ไปที่ CLDQZB+TrebuchetMS,Bold

ไล่ตามตาราง ToUnicode mapping

  • หลังจากหาชื่อเต็มของฟอนต์ที่ใช้กับข้อความแล้ว ให้ค้นหาชื่อนั้นภายใน PDF
  • ในตำแหน่งหนึ่งอาจพบ reference ดังนี้
/ToUnicode 19 0 R
  • ค่านี้ชี้ไปยัง object ID ของตาราง encoding
  • จากนั้นเมื่อค้นหา 19 0 obj ก็สามารถพบตารางดังกล่าวได้

แทนที่ข้อความโดยใช้ตาราง encoding

  • ส่วนสำคัญของตาราง mapping อาจมีรูปแบบดังนี้
38 beginbfrange^M
<0036><0036><0053>^M
<0057><0057><0074>^M
<0044><0044><0061>^M
<0048><0048><0065>^M
<0050><0050><006D>^M
...
  • ตัวอย่างนี้ map ช่วงของ code point ใน encoding ที่ผู้ใช้กำหนดเองไปยัง Unicode point
    • ในที่นี้แต่ละช่วงมีเพียงหนึ่งตัวอักษร
    • 0036 ถูก map ไปยัง Unicode point 0053
  • หากรูปแบบของตารางต่างออกไป สามารถอ้างอิง ToUnicode mapping file tutorial ได้
  • เพื่อแปลงอัตโนมัติ จึงใช้ Python เปลี่ยนตารางเป็น dictionary แล้วเขียน ฟังก์ชัน encode/decode ง่าย ๆ
  • ลำดับการแทนที่สุดท้ายมีดังนี้
    • ตรวจสอบค่า encoding แบบผู้ใช้กำหนดเองของข้อความเดิมที่ต้องการเปลี่ยน
    • encode ข้อความแทนที่ด้วยวิธีเดียวกันเป็น encoding แบบผู้ใช้กำหนดเอง
    • ใช้ find-and-replace ใน PDF เพื่อแทนที่ค่าเดิม

1 ความคิดเห็น

 
GN⁺ 2023-09-05
ความคิดเห็นจาก Hacker News
  • ข้อกำหนดของ PDF ค่อนข้างดิบทีเดียว เกร็ดความรู้ที่ผมชอบที่สุดช่วงนี้คือ เวลามันเรนเดอร์องค์ประกอบที่ซ้อนทับกัน มันรองรับ โหมด Layer Blend ทั้งหมดของ Photoshop
    อย่างที่ชอบรองลงมาคือ เนื้อหาที่ต่อท้ายในภายหลังสามารถแก้ไขเนื้อหาก่อนหน้าได้ ทำให้ต้องตรวจสอบเชิงนิติพิสูจน์ทุกเวอร์ชันที่แตกต่างกันซึ่งถูกแทนอยู่ในไฟล์เดียว
    นี่ยังเป็นตัวอย่างที่แสดงให้เห็นความว่างเปล่าของ DRM ด้วย ในข้อกำหนดมีการเข้ารหัสแบบใช้รหัสผ่าน และสามารถมีรหัสผ่าน “เจ้าของ” กับ “ผู้ใช้” แยกกันได้ รวมถึงมี bit field อย่าง “ห้ามพิมพ์” และ “ห้ามคัดลอกข้อความ” ด้วย แต่สุดท้ายถ้าจะอ่านเอกสารก็ต้องถอดรหัสอยู่ดี ดังนั้นถ้าเปิด PDF ที่เข้ารหัสด้วยรหัสผ่าน “ผู้ใช้” ในเครื่องมือที่ไม่ปฏิบัติตามข้อจำกัด แล้วบันทึกเป็นเวอร์ชันที่ไม่เข้ารหัส ก็จะได้สำเนาเทียบเท่าที่แก้ไขได้
    [1] ส่วน “More than just transparency” ของ https://blog.adobe.com/en/publish/2022/01/31/20-years-of-tra...
    [2] https://blog.didierstevens.com/2008/05/07/solving-a-little-p...
    [3] หน้า 61 ของ https://opensource.adobe.com/dc-acrobat-sdk-docs/pdfstandard...
    [4] เช่น สคริปต์ที่ใช้ไลบรารี pypdf

    • ในบริบทที่เดิมทีเป็น ฟอร์แมตปิด ไม่ได้เปิดเผยต่อทุกคนอย่างกว้างขวาง และถูกสร้างขึ้นในยุคที่การเข้ารหัสถูกควบคุมอย่างเข้มงวดตามกฎหมายส่งออก security through obscurity แบบนั้นจึงพบได้บ่อยมาก
      หนึ่งในบทเรียนแคร็กที่โด่งดังในตอนนั้นคือการลบ DRM ของ reader อย่างเป็นทางการด้วยการแพตช์ฟังก์ชันที่ตรวจสอบสิทธิ์
    • วิธีทำ: https://www.cyberciti.biz/faq/removing-password-from-pdf-on-...
    • โหมด blend ที่รองรับก็เป็นแค่ โหมดการคอมโพสิตแบบ Porter-Duff ไม่ใช่หรือ? มันอาจดูเกินจำเป็น แต่สอดคล้องกับสิ่งที่ pipeline เรนเดอร์อื่น ๆ มีให้อย่างดีมาก และช่วยลดงานในการสร้าง PDF ได้พอสมควร
    • ถ้าขุดลงไปใน ฟิลด์สิทธิ์ จะเข้าสู่โพรงกระต่ายที่เจอทั้งวิธีที่โปรแกรมสร้าง PDF บางตัวไม่ทำตามข้อกำหนด และการจัดการแบบ workaround ที่อาจมีหรือไม่มีในแต่ละ PDF reader หรือไลบรารี
    • ถ้าพูดอย่างเป็นธรรม ถ้าต้องการกันไม่ให้คัดลอกข้อความ วิธีที่ง่ายที่สุดคือเอา ToUnicode mapping ของฟอนต์ออก แบบนั้นผู้คนก็ต้องลงแรงทำขึ้นมาใหม่เอง
  • หัวข้อนี้โผล่มาเป็นระยะ ๆ คนส่วนใหญ่คิดว่า PDF เป็นฟอร์แมตไบนารีที่เจาะยาก แต่จริง ๆ แล้วไม่ใช่
    PDF คือ กราฟของอ็อบเจ็กต์ หลายประเภท และตัวประเภทเองก็อธิบายไว้อย่างดีในข้อกำหนดทางการ ผมมีรสนิยมทรมานตัวเองคืออ่านมันเล่น ๆ
    สิ่งที่แนะนำเสมอคือแปลง PDF ให้เป็นเวอร์ชันที่ไม่มีข้อมูลบีบอัดเหมือนที่ผู้เขียนทำ เครื่องมือที่ชอบคือ mutool ใช้ mutool clean -d in.pdf out.pdf ได้เลย จากนั้นลองค้นดูจะประหลาดใจว่าตามส่วนต่าง ๆ ได้มากกว่าที่คิด
    ในบทความข้ามขั้นตอนการดู page object แล้วตรวจสอบ resources ไป ตรงนั้นคือจุดที่ชื่อฟอนต์ที่ใช้ใน content stream ถูกเชื่อมกับ sub-object จริง
    อีกส่วนสำคัญที่ขาดไปคือ ฟอนต์ส่วนใหญ่ถูกฝังมาใน PDF แบบ subset มีแค่ glyph ที่จำเป็นเท่านั้นที่ถูกเก็บไว้ในฟอนต์ การ re-encode มักเกิดขึ้นตรงนี้ และ ToUnicode จะถูกเก็บไว้เพื่อให้คัดลอกข้อความหรือค้นหาใน PDF ได้ เป็นสิ่งที่ดีกับผู้ใช้ และจากประสบการณ์ของผมมักจะมีอยู่และค่อนข้างถูกต้อง

    • ถ้า “อ่านเล่น ๆ” ก็น่าจะใกล้เคียง มาโซคิสต์ มากกว่า ซาดิสต์ ถ้าเข้าร่วมเขียนข้อกำหนดหรือทำให้คนอื่นต้องอ่าน แบบนั้นถึงจะเป็นซาดิสต์
    • น่าเสียดายที่ Adobe ออกแบบฟอร์แมตให้จัดการยากเกินไป จนผู้คนประหลาดใจเมื่อมีใครทำสิ่งที่ควรเป็นงานพื้นฐานได้สำเร็จ
      ตั้งแต่แรก ปรัชญาการออกแบบที่คิดจะสร้าง ฟอร์แมตแบบอ่านอย่างเดียว ก็ผิดแล้ว ฟีเจอร์ที่ผู้คนจะเรียกร้องเป็นอย่างแรกมันก็เห็น ๆ กันอยู่ไม่ใช่หรือ
    • ถ้ารู้สึกสนุกกับการได้รับความเจ็บปวดคือมาโซคิสต์ ถ้าชอบทำให้คนอื่นเจ็บปวดคือซาดิสต์ ดูเหมือนเขาพยายามช่วยผู้คน จึงใกล้เคียงแบบแรกมากกว่า ขอบคุณสำหรับ คำแนะนำเรื่อง mutool
    • ผมพึ่งพา Amazon Textract ค่อนข้างมากในการ parse PDF
      อยากรู้ว่ามี insight อื่น ๆ เรื่องวิธีจัดการให้ดีแบบ native โดยไม่ต้องใช้ cloud provider ไหม โดยเฉพาะตอนจัดการตาราง
  • สามารถทำแบบนี้ได้:
    แปลงเป็น PostScript a.ps ด้วย pdf2ps a.pdf
    แก้ไข PostScript โดยตรงด้วย vim a.ps
    แปลงกลับเป็น PDF ด้วย ps2pdf a.ps
    PDF ที่ซับซ้อนซึ่งมี JavaScript ในตัวหรือแอนิเมชันอาจทำงานไม่ถูกต้องหลังแปลงไปกลับแบบนี้ แต่ถ้าเป็น เอกสารธรรมดา ก็ใช้ได้ค่อนข้างดี การลบลายน้ำ การเปลี่ยนคำและตัวเลขทำได้ง่าย ส่วนการแก้ระยะห่างจะยากกว่า แน่นอนว่าต้องรู้ PostScript อยู่พอสมควร

    • ที่บริษัทจัดการไปรษณีย์ที่เคยทำงานอยู่ เราเคยทำ งานเตรียมพิมพ์ บางส่วนเกือบจะด้วยวิธีแบบนี้ ปกติเราจะสร้างเอกสารสำหรับพิมพ์ด้วยเครื่องมือที่เหมาะสม แต่บางครั้งลูกค้าคิดว่าตัวเองรู้ดีกว่าแล้วส่ง PDF มาให้ ซึ่งส่วนใหญ่มักต้องลงแรงมากกว่าและมีโอกาสผิดพลาดสูงกว่า
      ต่อให้ผลลัพธ์การพิมพ์ถูกต้อง ก็ยังต้องจัดลำดับหน้าใหม่ ใส่บาร์โค้ดสำหรับการประมวลผลด้วยเครื่องไปรษณีย์และการคัดแยกไปรษณีย์ รวมถึงสร้างรายงาน โดยทั่วไปเราใช้ Perl กับเครื่องมืออื่น ๆ ดึงข้อความจากหน้าเพื่อเอาที่อยู่ และ PS มักง่ายกว่า PDF มาก แต่บางกรณีก็เปราะบางมาก เช่น PDF แบบ “ปลอดภัย” ที่ไม่มีการแมป glyph ที่ถูกต้อง
      กรณีแย่ที่สุดคือลูกค้าส่ง PDF เอกสารเดี่ยว ๆ มาให้ แล้วพอรวมเข้าด้วยกัน ฟอนต์แบบ subset ในงานพิมพ์ก็เพิ่มขึ้นมหาศาลจนกินหน่วยความจำเครื่องพิมพ์เต็มและทำให้เครื่องค้าง ตอนลาออกจากงานนั้น ผมก็ยังไม่เห็นว่ามีเครื่องมือที่มีประโยชน์สำหรับรวม/ผสานฟอนต์แบบ subset ที่มาจากฟอนต์ต้นฉบับเดียวกัน น่าจะทำได้และมีประโยชน์มาก แต่ผมไม่มีเวลาหรือความรู้พอจะไปดู
    • ถ้าใส่ JavaScript และแอนิเมชันใน PDF ได้ แล้วอะไรล่ะที่จะขวางไม่ให้สร้าง ฟรอนต์เอนด์ ในนั้น? อยากรู้เหมือนกันว่าขอบเขตของสิ่งที่ทำได้ด้วย PDF อยู่ตรงไหน
      พูดตรง ๆ ความซับซ้อนของ PDF ดูเหมือนจะเป็นประโยชน์ต่อแค่ ผู้สร้างมัลแวร์ เท่านั้น
  • รู้สึกเหมือนมีจุดสำคัญที่ขาดไป ท้าย PDF จะมีตารางที่เก็บ ไบต์ออฟเซ็ต ของอ็อบเจ็กต์ต่าง ๆ ในไฟล์ หรือก็คือ ตาราง cross-reference
    ถ้าแก้ไขภายในไฟล์ ออฟเซ็ตเหล่านี้มักจะเปลี่ยน ทำให้ไฟล์เสีย บทความดูเหมือนสนใจแค่การเปลี่ยนตัวเลขหนึ่งเป็นอีกตัวเลขหนึ่ง จึงอาจไม่ได้ทำให้ตำแหน่งเปลี่ยน
    แต่โดยทั่วไป ถ้าเพิ่ม ลบ หรือแก้ไขกลางไฟล์ จะต้องคำนวณตาราง xref ใหม่ ดังนั้นการใช้ไลบรารีจึงง่ายกว่าการแก้ข้อความด้วยมือมาก

    • นั่นจึงเป็นเหตุผลที่ถอดรหัสด้วย qpdf แล้วเข้ารหัสกลับในภายหลัง แบบนั้น qpdf จะจัดการส่วนนี้ให้
      qpdf ดูเหมือนจะสร้างโครงสร้าง PDF เดิมขึ้นใหม่ และพยายามคงหมายเลขอ็อบเจ็กต์ไว้เหมือนเดิม แต่ออฟเซ็ตจะถูกคำนวณใหม่ทั้งหมด
    • ผมมองว่านั่นเป็นส่วนที่แปลกที่สุดของสเปก PDF มันผสมไบนารีกับข้อความ และไบต์ออฟเซ็ตถูกระบุเป็นข้อความ
      ถ้าผู้เขียนมาเล่าให้ฟังสักวัน ผมอยากอ่านว่าทำไมฟอร์แมตถึงออกมาเป็นแบบนั้น ตอนแรกอาจตั้งใจให้เป็นรูปแบบข้อความล้วนทั้งหมด แล้วภายหลังเห็นว่าไบนารีมีประสิทธิภาพกว่า เพียงแต่ข้อกำหนดที่ต้องให้รายการในตาราง xref มีความยาวคงที่ก็ดูขัด ๆ กับสมมติฐานนั้นอยู่เหมือนกัน
    • จากประสบการณ์ของผม วิธีที่ง่ายที่สุดคือทำให้ ตาราง xref พังไปเลย แล้วรันเครื่องมืออย่าง mutool clean เพื่อซ่อม เพราะมันอนุมานได้ทั้งหมดจากเนื้อหา จึงปลอดภัย
    • ค่อนข้างคล้ายกับการแก้ไขไบนารีที่คอมไพล์แล้ว
      ตราบใดที่รักษาความยาวไว้ ก็แก้ไบนารีได้ตามใจ
      เคยมีซอฟต์แวร์ตัวหนึ่งที่ผมใช้ มันตรวจสอบสิทธิ์กับเซิร์ฟเวอร์ แต่การประมวลผลทั้งหมดทำที่ไคลเอนต์ ไคลเอนต์รัน SQL กับเซิร์ฟเวอร์โดยตรง และเซิร์ฟเวอร์แค่ตรวจว่าจำนวนไลเซนส์ที่ไคลเอนต์นี้ซื้อไว้เกินหรือไม่
      ผมเอาเข้า disassembler เพื่อหาส่วนที่ตรวจสอบ แล้วเปลี่ยนส่วนนั้นเป็น JMP ตรง ๆ จากนั้นเติมพื้นที่ที่เหลือด้วย NOP ได้
  • ดูเหมือนจะขาดขั้นตอนสำคัญเมื่อใช้โหมด --qdf ของ qpdf หลังแก้ไขเสร็จ ต้องส่งไฟล์ผ่านยูทิลิตี fix-pdf เพื่อคำนวณออฟเซ็ตของอ็อบเจ็กต์ทั้งหมดใหม่ และสร้างตาราง cross-reference ที่ท้ายไฟล์ขึ้นใหม่ ยกเว้นกรณีที่คุณเปลี่ยนแบบแทนที่ตำแหน่งเดิมเท่านั้น โดยไม่ได้เพิ่มหรือลบไบต์
    ข้อเท็จจริงสนุก ๆ เกี่ยวกับ PDF 3 อันดับแรกมีดังนี้

    1. เอกสาร PDF โดยปกติเป็นไฟล์ไบนารี 8 บิต แต่ถ้าใช้ฟิลเตอร์ ASCII85 ก็สามารถสร้าง PDF ที่เป็น ข้อความธรรมดา UTF-8 ที่ถูกต้องได้ แม้จะรวมรูปภาพด้วย
    2. PDF อนุญาตฟีเจอร์ประหลาดจำนวนมหาศาล เช่น อ็อบเจ็กต์ 3D, JavaScript, วิดีโอในอ็อบเจ็กต์ Flash ที่ฝังไว้, annotation ที่มองไม่เห็น ฯลฯ ส่วน PDF/A เป็น subset ที่มีสติและปลอดภัยกว่ามาก
    3. สเปก PDF อนุญาตให้เขียนวิดเจ็ต เช่น ฟอร์มคอนโทรล ด้วย rich text ซึ่งเป็น subset ของ XHTML และ CSS แต่ฟีเจอร์นี้แทบไม่มีการรองรับนอก Adobe Reader อย่างเป็นทางการ
      [0] ตัวอย่าง: https://lab6.com/2
    • หลังแก้ไขเสร็จ แค่ส่งผ่าน qpdf โดยไม่ใส่พารามิเตอร์ ตามที่อธิบายไว้ช่วงต้นของบทความก็พอ แบบนั้นมันจะบีบอัดข้อมูลใหม่และสร้างตาราง xref ใหม่ด้วย ไม่จำเป็นต้องใช้เครื่องมืออื่น
  • ถ้าต้องการเรียนรู้ต่อในเส้นทาง PDF นี้ สามารถอ่านเอกสารผ่าไฟล์ที่เพิ่งสรุปไว้ได้:
    https://pdfsyntax.dev/introduction_pdf_syntax.html

  • สิ่งที่คนมักมองข้ามเกี่ยวกับ PDF คือ ในแง่หนึ่งมันใกล้เคียงกับ รูปแบบภาพ มากกว่าเอกสาร Word เอกสาร Word, PDF, และรูปภาพในการแก้ไขเอกสาร ก็เหมือนกับโปรเจกต์ DAW, MIDI, และ MP3 ในดนตรี และคล้ายกับซอร์สโค้ด Java, ไบต์โค้ด JVM, และภาษาเครื่อง x86 ล้วน ๆ ในซอฟต์แวร์
    เป้าหมายหลักของไฟล์ PDF คือการบอกอย่างชัดเจนสมบูรณ์ว่าควรแสดงหรือพิมพ์อะไร โดยใช้จำนวนไบต์น้อยกว่าภาพจริงมาก มันใช้ประโยชน์จากข้อเท็จจริงที่ว่าผู้สร้างเอกสารรู้แพตเทิร์นของโครงสร้างเอกสาร ทำให้เมื่อแทนค่าอย่างเหมาะสมแล้วบีบอัดได้ดีกว่าอัลกอริทึมบีบอัดภาพจริงมาก เช่น ถ้าเข้าถึงฟอนต์จริงได้ การบอกว่า “วางอักขระเหล่านี้ที่พิกัดนี้ ด้วยระยะห่างเท่านี้” ย่อมดีกว่าการใส่การปรากฏของตัวอักษรทุกตัวเป็นส่วนหนึ่งของภาพ แล้วหวังให้อัลกอริทึมบีบอัดลดความซ้ำซ้อนให้เอง โดยพื้นฐานแล้ว ถ้าเป้าหมายมีแค่การส่งต่อภาพของเอกสารอย่างมีประสิทธิภาพ ก็ไม่สำคัญว่าอักขระใดเป็นของคำใด หรือแม้แต่ว่าโค้ดพอยต์ Unicode ใดสอดคล้องกับ glyph ใดในฟอนต์
    สำหรับเอกสารที่แก้ไขได้ โครงสร้างเชิงความหมาย ของเนื้อหาสำคัญกว่าการแสดงผลมาก ต้องรู้ว่าการเว้นช่วงบางจุดในข้อความเป็นช่องว่างหลายตัว เป็นคอลัมน์ถัดไปของตาราง หรือเป็นการจัดหน้าประหลาด ๆ ที่เกิดจากรูปภาพ ต้องรู้ด้วยว่าข้อความด้านล่างของแต่ละหน้าเป็นสิ่งที่ผู้เขียนใส่ซ้ำหลายครั้ง หรือป้อนครั้งเดียวแล้วตั้งเป็น footer ถ้าต้องเพิ่มย่อหน้าใหม่จนเลย์เอาต์หน้าเปลี่ยน ก็สำคัญที่จะรู้ว่าย่อหน้าสุดท้ายของหน้านี้เป็นเชิงอรรถ จึงไม่ควรถูกดันไปหน้าถัดไป ถ้าหัวข้อของส่วนย้ายไปอีกหน้า สิ่งที่สำคัญคือสารบัญควรอัปเดตอัตโนมัติ ไม่ใช่เป็นเพียงข้อความที่ผู้เขียนพิมพ์เองด้วยมือ
    จากมุมมองของเครื่องพิมพ์หรือหน้าจอ เรื่องเหล่านี้ไม่เกี่ยวเลย แค่พิมพ์หรือแสดงตามคำสั่งก็พอ ใน PDF เชิงอรรถ หัวข้อส่วน footer และสารบัญไม่จำเป็นต้องเป็นสิ่งพิเศษ และอาจเป็นแค่ข้อความที่มีการจัดรูปแบบแบบไม่มีความหมายก็ได้ ดังนั้นเมื่อพยายามใช้ PDF เพื่อจุดประสงค์อื่นที่ไม่ใช่การแสดงหรือพิมพ์ มันจึงไม่มีทางถูกต้อง 100% แน่นอนว่ามีความพยายามชดเชยเรื่องนี้ และโปรแกรมสร้าง PDF ก็ใส่เมตาดาต้าที่ต้องการได้อย่างอิสระ แต่ไม่ใช่ข้อบังคับ
    นี่อาจไม่ใช่ mental model ที่ผู้สร้าง PDF ตั้งใจไว้ แต่เป็นมุมมองที่มีประโยชน์ในการเข้าใจว่าทำไม PDF ถึงมีรูปแบบเช่นนั้น

    • เป้าหมายดั้งเดิมของ PDF คือการสร้าง สำเนาที่คงความถูกต้องสำหรับงานพิมพ์ แบบพกพาได้ เป็น WYSIWYG ของจริง ไฟล์ PDF ต้องดูเหมือนกันไม่ว่าจะส่งไปยังเครื่องพิมพ์เลเซอร์ เครื่อง Linotype หรือหน้าจอ
      ถ้าพิมพ์ด้วยเครื่องพิมพ์ PostScript ก็จะออกมาตรงกัน และถ้าใช้ฟอนต์ Type 1 ก็ยิ่งดีขึ้นด้วย
  • คนที่พยายามทำแบบนี้กำลังพลาดแก่นของ PDF ไป PDF เป็น รูปแบบคำอธิบายหน้า ดังนั้นมันไม่ได้แทนโครงสร้างเอกสาร แต่แทนเพียงร่องรอยการแสดงผลบนหน้า
    อย่าพยายามแก้ไข PDF ควรแก้ไขเอกสารต้นฉบับที่ใช้สร้าง PDF แทน

    • ถ้าคนหยุดส่ง PDF ที่ผมต้องการแก้ไขมาให้ ผมก็จะหยุดแก้ไข PDF
      ไม่รู้ตั้งแต่เมื่อไหร่ที่การส่งเอกสารที่ทำมาเพื่อให้แก้ไขได้กลายเป็นเรื่อง “ไม่มืออาชีพ” และสุดท้ายก็เลยเป็นสถานการณ์แบบนี้
    • PDF ยังรองรับฟีเจอร์ที่ใส่ข้อมูล โครงสร้างเอกสารเชิงตรรกะ ได้ด้วย เรียกว่า Tagged PDF
      เป็นตัวเลือกเสริม แต่แนะนำเพื่อการเข้าถึง เช่น PDF/UA ดูบท 14.7–14.8 ของ [1]
      [1] https://opensource.adobe.com/dc-acrobat-sdk-docs/pdfstandard...
    • การบอกว่า “ไม่ควรทำ” ในที่นี้แทบไม่มีความหมาย ในโลกจริงมีสถานการณ์จำนวนมากที่ต้องให้ แก้ไข PDF ไม่ทางใดก็ทางหนึ่ง
    • ความยากอย่างหนึ่งคือการทำเครื่องหมายการแก้ไขที่ต้องย้อนกลับไปแก้ในเอกสารต้นฉบับ คุณได้รับ proof จากคนจัดหน้า แล้วต้องทำเครื่องหมายให้เขาแก้
      คุณแก้ข้อความใน PDF โดยตรงไม่ได้ เพราะคนจัดหน้าจะไม่เห็นการเปลี่ยนแปลงนั้น เครื่องมือมาร์กอัปของ Acrobat ก็ไม่ได้แย่มาก แต่ยังไม่เท่ายุคที่ใช้กระดาษกับดินสอแดง เว้นแต่จะใช้เครื่องมือ “pencil” ของ Acrobat ก็หวังว่าส่วนนี้จะดีขึ้น
    • ถ้ามันเป็น “รูปแบบคำอธิบายหน้า” และไม่ได้แทนโครงสร้างเอกสาร แต่แทนเฉพาะสิ่งที่แสดงบนหน้า ก็ควรตั้งชื่อว่า Page Description Format แทน Portable Document Format ไม่ใช่หรือ
  • เมื่อ 20 ปีก่อนผมทำงานที่หนังสือพิมพ์ในตำแหน่ง ฝ่ายเพลตพิมพ์ มี “เครื่องพิมพ์” เพลต Kodak ราคาเป็นล้านดอลลาร์อยู่สองเครื่อง แต่เรียกว่าเครื่องพิมพ์ก็ไม่ค่อยถูกนัก ถ้าจำไม่ผิด สารเคลือบบนเพลตจะโดนแสงอัลตราไวโอเลตแล้วละลายในอ่างเคมี
    อุปกรณ์ Kodak เสียบ่อย และหัวหน้าผมมักเปิดไฟล์ PostScript หรือ EPS โดยตรง เพื่อแก้ header หรือส่วนผิดพลาดที่ซอฟต์แวร์จัดหน้าใส่มา แล้วมันก็กลับมาทำงานได้อีก อย่างไรก็ตาม แท่นพิมพ์ออฟเซ็ตแบบม้วนขนาดมหึมาจากเยอรมนีของเราใช้ Linux
    หัวหน้าน่าจะชื่อ Bill เขาเป็นคนดีที่พาผมซึ่งอายุ 17 ไปดูคอนเสิร์ต Sigur Ros กลายเป็นว่ามีเรื่องที่ไม่เกี่ยวกับ PDF ตั้งสองเรื่องแล้ว

  • บทความดีมาก ผมสร้าง DocSpring [1] มาราว 5 ปีที่ผ่านมา และอ่านสเปก PDF ไปเยอะแล้ว แต่ก็ยังรู้สึกว่าเพิ่งแตะผิวเผินเท่านั้น qpdf เป็นเครื่องมือที่ยอดเยี่ยม และอีกเครื่องมือที่ผมชอบคือ RUPS [2] ซึ่งใช้เจาะลึกโครงสร้าง PDF ได้
    [1] https://docspring.com
    [2] https://github.com/itext/i7j-rups