- หากต้องการเปลี่ยน เนื้อหาข้อความ ใน 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 ความคิดเห็น
ความคิดเห็นจาก 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
หนึ่งในบทเรียนแคร็กที่โด่งดังในตอนนั้นคือการลบ DRM ของ reader อย่างเป็นทางการด้วยการแพตช์ฟังก์ชันที่ตรวจสอบสิทธิ์
หัวข้อนี้โผล่มาเป็นระยะ ๆ คนส่วนใหญ่คิดว่า 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 ได้ เป็นสิ่งที่ดีกับผู้ใช้ และจากประสบการณ์ของผมมักจะมีอยู่และค่อนข้างถูกต้อง
ตั้งแต่แรก ปรัชญาการออกแบบที่คิดจะสร้าง ฟอร์แมตแบบอ่านอย่างเดียว ก็ผิดแล้ว ฟีเจอร์ที่ผู้คนจะเรียกร้องเป็นอย่างแรกมันก็เห็น ๆ กันอยู่ไม่ใช่หรือ
อยากรู้ว่ามี insight อื่น ๆ เรื่องวิธีจัดการให้ดีแบบ native โดยไม่ต้องใช้ cloud provider ไหม โดยเฉพาะตอนจัดการตาราง
สามารถทำแบบนี้ได้:
แปลงเป็น PostScript
a.psด้วยpdf2ps a.pdfแก้ไข PostScript โดยตรงด้วย
vim a.psแปลงกลับเป็น PDF ด้วย
ps2pdf a.psPDF ที่ซับซ้อนซึ่งมี JavaScript ในตัวหรือแอนิเมชันอาจทำงานไม่ถูกต้องหลังแปลงไปกลับแบบนี้ แต่ถ้าเป็น เอกสารธรรมดา ก็ใช้ได้ค่อนข้างดี การลบลายน้ำ การเปลี่ยนคำและตัวเลขทำได้ง่าย ส่วนการแก้ระยะห่างจะยากกว่า แน่นอนว่าต้องรู้ PostScript อยู่พอสมควร
ต่อให้ผลลัพธ์การพิมพ์ถูกต้อง ก็ยังต้องจัดลำดับหน้าใหม่ ใส่บาร์โค้ดสำหรับการประมวลผลด้วยเครื่องไปรษณีย์และการคัดแยกไปรษณีย์ รวมถึงสร้างรายงาน โดยทั่วไปเราใช้ Perl กับเครื่องมืออื่น ๆ ดึงข้อความจากหน้าเพื่อเอาที่อยู่ และ PS มักง่ายกว่า PDF มาก แต่บางกรณีก็เปราะบางมาก เช่น PDF แบบ “ปลอดภัย” ที่ไม่มีการแมป glyph ที่ถูกต้อง
กรณีแย่ที่สุดคือลูกค้าส่ง PDF เอกสารเดี่ยว ๆ มาให้ แล้วพอรวมเข้าด้วยกัน ฟอนต์แบบ subset ในงานพิมพ์ก็เพิ่มขึ้นมหาศาลจนกินหน่วยความจำเครื่องพิมพ์เต็มและทำให้เครื่องค้าง ตอนลาออกจากงานนั้น ผมก็ยังไม่เห็นว่ามีเครื่องมือที่มีประโยชน์สำหรับรวม/ผสานฟอนต์แบบ subset ที่มาจากฟอนต์ต้นฉบับเดียวกัน น่าจะทำได้และมีประโยชน์มาก แต่ผมไม่มีเวลาหรือความรู้พอจะไปดู
พูดตรง ๆ ความซับซ้อนของ PDF ดูเหมือนจะเป็นประโยชน์ต่อแค่ ผู้สร้างมัลแวร์ เท่านั้น
รู้สึกเหมือนมีจุดสำคัญที่ขาดไป ท้าย PDF จะมีตารางที่เก็บ ไบต์ออฟเซ็ต ของอ็อบเจ็กต์ต่าง ๆ ในไฟล์ หรือก็คือ ตาราง cross-reference
ถ้าแก้ไขภายในไฟล์ ออฟเซ็ตเหล่านี้มักจะเปลี่ยน ทำให้ไฟล์เสีย บทความดูเหมือนสนใจแค่การเปลี่ยนตัวเลขหนึ่งเป็นอีกตัวเลขหนึ่ง จึงอาจไม่ได้ทำให้ตำแหน่งเปลี่ยน
แต่โดยทั่วไป ถ้าเพิ่ม ลบ หรือแก้ไขกลางไฟล์ จะต้องคำนวณตาราง xref ใหม่ ดังนั้นการใช้ไลบรารีจึงง่ายกว่าการแก้ข้อความด้วยมือมาก
qpdf ดูเหมือนจะสร้างโครงสร้าง PDF เดิมขึ้นใหม่ และพยายามคงหมายเลขอ็อบเจ็กต์ไว้เหมือนเดิม แต่ออฟเซ็ตจะถูกคำนวณใหม่ทั้งหมด
ถ้าผู้เขียนมาเล่าให้ฟังสักวัน ผมอยากอ่านว่าทำไมฟอร์แมตถึงออกมาเป็นแบบนั้น ตอนแรกอาจตั้งใจให้เป็นรูปแบบข้อความล้วนทั้งหมด แล้วภายหลังเห็นว่าไบนารีมีประสิทธิภาพกว่า เพียงแต่ข้อกำหนดที่ต้องให้รายการในตาราง xref มีความยาวคงที่ก็ดูขัด ๆ กับสมมติฐานนั้นอยู่เหมือนกัน
mutool cleanเพื่อซ่อม เพราะมันอนุมานได้ทั้งหมดจากเนื้อหา จึงปลอดภัยตราบใดที่รักษาความยาวไว้ ก็แก้ไบนารีได้ตามใจ
เคยมีซอฟต์แวร์ตัวหนึ่งที่ผมใช้ มันตรวจสอบสิทธิ์กับเซิร์ฟเวอร์ แต่การประมวลผลทั้งหมดทำที่ไคลเอนต์ ไคลเอนต์รัน SQL กับเซิร์ฟเวอร์โดยตรง และเซิร์ฟเวอร์แค่ตรวจว่าจำนวนไลเซนส์ที่ไคลเอนต์นี้ซื้อไว้เกินหรือไม่
ผมเอาเข้า disassembler เพื่อหาส่วนที่ตรวจสอบ แล้วเปลี่ยนส่วนนั้นเป็น JMP ตรง ๆ จากนั้นเติมพื้นที่ที่เหลือด้วย NOP ได้
ดูเหมือนจะขาดขั้นตอนสำคัญเมื่อใช้โหมด
--qdfของ qpdf หลังแก้ไขเสร็จ ต้องส่งไฟล์ผ่านยูทิลิตี fix-pdf เพื่อคำนวณออฟเซ็ตของอ็อบเจ็กต์ทั้งหมดใหม่ และสร้างตาราง cross-reference ที่ท้ายไฟล์ขึ้นใหม่ ยกเว้นกรณีที่คุณเปลี่ยนแบบแทนที่ตำแหน่งเดิมเท่านั้น โดยไม่ได้เพิ่มหรือลบไบต์ข้อเท็จจริงสนุก ๆ เกี่ยวกับ PDF 3 อันดับแรกมีดังนี้
[0] ตัวอย่าง: https://lab6.com/2
ถ้าต้องการเรียนรู้ต่อในเส้นทาง 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 ถึงมีรูปแบบเช่นนั้น
ถ้าพิมพ์ด้วยเครื่องพิมพ์ PostScript ก็จะออกมาตรงกัน และถ้าใช้ฟอนต์ Type 1 ก็ยิ่งดีขึ้นด้วย
คนที่พยายามทำแบบนี้กำลังพลาดแก่นของ PDF ไป PDF เป็น รูปแบบคำอธิบายหน้า ดังนั้นมันไม่ได้แทนโครงสร้างเอกสาร แต่แทนเพียงร่องรอยการแสดงผลบนหน้า
อย่าพยายามแก้ไข PDF ควรแก้ไขเอกสารต้นฉบับที่ใช้สร้าง PDF แทน
ไม่รู้ตั้งแต่เมื่อไหร่ที่การส่งเอกสารที่ทำมาเพื่อให้แก้ไขได้กลายเป็นเรื่อง “ไม่มืออาชีพ” และสุดท้ายก็เลยเป็นสถานการณ์แบบนี้
เป็นตัวเลือกเสริม แต่แนะนำเพื่อการเข้าถึง เช่น PDF/UA ดูบท 14.7–14.8 ของ [1]
[1] https://opensource.adobe.com/dc-acrobat-sdk-docs/pdfstandard...
คุณแก้ข้อความใน PDF โดยตรงไม่ได้ เพราะคนจัดหน้าจะไม่เห็นการเปลี่ยนแปลงนั้น เครื่องมือมาร์กอัปของ Acrobat ก็ไม่ได้แย่มาก แต่ยังไม่เท่ายุคที่ใช้กระดาษกับดินสอแดง เว้นแต่จะใช้เครื่องมือ “pencil” ของ Acrobat ก็หวังว่าส่วนนี้จะดีขึ้น
เมื่อ 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