शून्य से PDF लिखना (01): हेल्लो, वर्ल्ड - एक न्यूनतम उपयोगी PDF बनाना
शून्य से PDF लिखना (01): हेल्लो, वर्ल्ड - एक न्यूनतम उपयोगी PDF बनाना
श्रृंखला का लक्ष्य: PDF को एक पढ़ने योग्य फ़ाइल प्रारूप के रूप में समझना - पहले "चलने योग्य" न्यूनतम उदाहरण से शुरू करें, फिर धीरे-धीरे ग्राफिक्स, बहु-पृष्ठ, संकुचन और संसाधन पुन: उपयोग तक बढ़ें।
श्रृंखला की सामग्री
- पहला लेख (यह): एक न्यूनतम PDF लिखें (1 पृष्ठ + 1 पंक्ति पाठ), और इसे एक मानक PDF में पूरा करने के लिए उपकरण का उपयोग करें जिसे खोला जा सके
- दूसरा लेख: सामग्री स्ट्रीम में रेखाएँ/आयत बनाना (पथ, स्ट्रोक, भराई को समझना)
- तीसरा लेख: बहु-पृष्ठ PDF (Pages पेड़ कैसे बनता है)
- चौथा लेख: वास्तविक दुनिया के करीब (संकुचन स्ट्रीम, संसाधन पुन: उपयोग, वैकल्पिक संरचना आदि)
PDF की निचली संरचना को समझने की आवश्यकता क्यों है?
PDF (पोर्टेबल डॉक्यूमेंट फॉर्मेट) आज के सबसे लोकप्रिय पृष्ठ वर्णन भाषाओं में से एक है। यह HTML/CSS के "सामग्री और प्रस्तुति को अलग करने, पुनः प्रवाहित (Reflowable)" के विचार से भिन्न है, PDF अधिक फिक्स्ड लेआउट, जो देखा गया है वही प्राप्त करें पर जोर देता है - चाहे किसी भी डिवाइस पर खोला जाए, टाइपोग्राफी समान रहती है।
PDF की निचली संरचना को समझने के कई व्यावहारिक लाभ हैं:
- PDF निर्माण समस्याओं का डिबगिंग: जब आप कोड लाइब्रेरी का उपयोग करके PDF बनाते समय त्रुटि करते हैं, तो निचली संरचना को समझने से समस्या को जल्दी से पहचानने में मदद मिलती है
- स्वचालित प्रसंस्करण: पाठ निकालना, दस्तावेज़ों को मिलाना, वॉटरमार्क जोड़ना आदि जैसे कार्यों के लिए, संरचना को समझने के बाद ही सटीक संचालन किया जा सकता है
- सुरक्षा ऑडिट: यह समझना कि PDF में कौन-कौन सी सामग्री (JavaScript, अटैचमेंट, फ़ॉर्म आदि) एम्बेड की जा सकती है, सुरक्षा विश्लेषण में मदद करता है
- फ़ाइल प्रारूप डिज़ाइन सीखना: PDF का "ऑब्जेक्ट ग्राफ + रैंडम एक्सेस" डिज़ाइन एक क्लासिक उदाहरण है, जिसे सीखना चाहिए
तैयारी का काम
इस लेख में हम पहले एक "संरचना में अधूरा लेकिन तार्किक रूप से सही" hello-broken.pdf लिखेंगे, फिर pdftk का उपयोग करके महत्वपूर्ण संरचना को स्वचालित रूप से पूरा करेंगे और hello.pdf आउटपुट करेंगे।
- आवश्यक उपकरण: pdftk (नि:शुल्क कमांड लाइन उपकरण, Windows/macOS/Linux का समर्थन करता है)
- आउटपुट फ़ाइल:
hello-broken.pdf(हाथ से लिखित),hello.pdf(मरम्मत के बाद खोला जा सकता है)
मुख्य अवधारणा: PDF की तीन परतें
PDF को समझने के लिए सबसे महत्वपूर्ण है एक तीन परतों का मानसिक मॉडल स्थापित करना:

1. ऑब्जेक्ट लेयर (डॉक्यूमेंट सामग्री)
PDF दस्तावेज़ कई ऑब्जेक्ट्स से मिलकर बना होता है, जो अप्रत्यक्ष संदर्भ (जैसे 2 0 R) के माध्यम से एक चित्र में जुड़े होते हैं। सामान्य ऑब्जेक्ट प्रकार:
| प्रकार | उदाहरण | विवरण |
|---|---|---|
| नाम | /Page | / से शुरू होने वाला नाम |
| पूर्णांक/वास्तविक संख्या | 50、36.0 | संख्या |
| स्ट्रिंग | (Hello, World!) | गोल ब्रैकेट में लिपटा |
| ऐरे | [0 0 612 792] | क्रमबद्ध संग्रह |
| शब्दकोश | << /Type /Page >> | कुंजी-मूल्य जोड़ा संग्रह |
| अप्रत्यक्ष संदर्भ | 2 0 R | ऑब्जेक्ट 2 का संदर्भ (जनरेशन नंबर 0) |
| स्ट्रीम | stream...endstream | बाइनरी डेटा (जैसे ड्राइंग निर्देश, चित्र) |
2. सामग्री लेयर (पृष्ठ सामग्री)
वास्तव में "पृष्ठ पर पाठ/चित्र बनाने" के निर्देशों की श्रृंखला, जो आमतौर पर stream ... endstream में लिखी जाती है। प्रारूप है: ऑपरेटर पहले, ऑपरेटर बाद में।
/F0 36 Tf ← ऑपरेटर: /F0, 36 ऑपरेटर: Tf (फॉन्ट सेट करना)
(Hello, World!) Tj ← ऑपरेटर: स्ट्रिंग ऑपरेटर: Tj (पाठ बनाना)
3. फ़ाइल संरचना लेयर (File Structure)
पढ़ने वाले को त्वरित रैंडम एक्सेस की अनुमति देना ताकि उसे शुरुआत से अंत तक पढ़ने की आवश्यकता न हो:
| तत्व | कार्य |
|---|---|
%PDF-1.x | फ़ाइल हेडर, PDF संस्करण को पहचानता है |
xref | क्रॉस संदर्भ तालिका: ऑब्जेक्ट नंबर → बाइट ऑफसेट |
trailer | ट्रेलर शब्दकोश: मूल ऑब्जेक्ट /Root की ओर इशारा करता है |
startxref | xref तालिका की प्रारंभिक स्थिति को इंगित करता है |
%%EOF | फ़ाइल समाप्ति चिह्न |
न्यूनतम PDF के लिए किन ऑब्जेक्ट्स की आवश्यकता है?
एक "न्यूनतम लेकिन पाठ प्रदर्शित करने योग्य" PDF, ऑब्जेक्ट्स के बीच संदर्भ संबंध इस प्रकार हैं:

न्यूनतम ऑब्जेक्ट सूची:
| ऑब्जेक्ट | कार्य | प्रमुख फ़ील्ड |
|---|---|---|
| कैटलॉग | मूल ऑब्जेक्ट, दस्तावेज़ का प्रवेश | /Type /Catalog, /Pages |
| पृष्ठ | पृष्ठ पेड़ | /Type /Pages, /Kids, /Count |
| पृष्ठ | एकल पृष्ठ | /Type /Page, /MediaBox, /Resources, /Contents, /Parent |
| संसाधन | संसाधन कंटेनर | /Font (फॉन्ट शब्दकोश) |
| फॉन्ट | फॉन्ट परिभाषा | /Type /Font, /BaseFont, /Subtype |
| सामग्री | सामग्री स्ट्रीम | ड्राइंग निर्देशों की स्ट्रीम |
व्यावहारिक: hello-broken.pdf लिखना
नई फ़ाइल hello-broken.pdf बनाएं, और नीचे दी गई सामग्री को पूरी तरह से चिपकाएँ:
%PDF-1.0
1 0 obj
<< /Type /Pages
/Count 1
/Kids [2 0 R]
>>
endobj
2 0 obj
<< /Type /Page
/MediaBox [0 0 612 792]
/Resources 3 0 R
/Parent 1 0 R
/Contents [4 0 R]
>>
endobj
3 0 obj
<< /Font
<< /F0
<< /Type /Font
/BaseFont /Times-Italic
/Subtype /Type1 >>
>>
>>
endobj
4 0 obj
<< >>
stream
1. 0. 0. 1. 50. 700. cm
BT
/F0 36. Tf
(Hello, World!) Tj
ET
endstream
endobj
5 0 obj
<< /Type /Catalog
/Pages 1 0 R
>>
endobj
xref
0 6
trailer
<< /Size 6
/Root 5 0 R
>>
startxref
0
%%EOF
यह फ़ाइल "खराब" क्यों है?
हमने जानबूझकर निम्नलिखित सामग्री को छोड़ दिया या गलत भरा:
| अनुपस्थित/गलत आइटम | विवरण |
|---|---|
xref ऑफसेट | प्रत्येक ऑब्जेक्ट के वास्तविक बाइट ऑफसेट को नहीं भरा गया |
startxref | 0 भरा गया, यह xref का वास्तविक स्थान नहीं है |
/Length | सामग्री स्ट्रीम की लंबाई घोषित नहीं की गई |
| बाइनरी चिह्न | हेडर में बाइनरी पहचान पंक्ति की कमी |
ये सभी पढ़ने वाले के लिए आवश्यक महत्वपूर्ण जानकारी हैं, जिनकी अनुपस्थिति के कारण इसे खोलने में असमर्थता या केवल त्रुटि सहिष्णुता के साथ खोलने की स्थिति उत्पन्न हो सकती है।
महत्वपूर्ण सामग्री स्ट्रीम निर्देशों का विस्तृत विवरण
सामग्री स्ट्रीम ऑब्जेक्ट 4 0 obj के stream ... endstream के बीच है, पंक्ति दर पंक्ति व्याख्या:
1. 0. 0. 1. 50. 700. cm ← परिवर्तन मैट्रिक्स सेट करना (ध्यान दें 1. वास्तविक संख्या 1.0 का प्रतिनिधित्व करता है)
BT ← पाठ ऑब्जेक्ट शुरू करें
/F0 36. Tf ← फॉन्ट F0 का चयन करें, फ़ॉन्ट आकार 36pt
(Hello, World!) Tj ← स्ट्रिंग बनाना
ET ← पाठ ऑब्जेक्ट समाप्त करें
परिवर्तन मैट्रिक्स cm ऑपरेटर
1 0 0 1 50 700 cm एक 6-तत्व परिवर्तन मैट्रिक्स [a b c d e f] है, जो निम्नलिखित के अनुरूप है:
| a b 0 | | 1 0 0 |
| c d 0 | = | 0 1 0 |
| e f 1 | | 50 700 1 |
जब a=1, b=0, c=0, d=1 होता है, तो यह एक शुद्ध अनुवाद मैट्रिक्स है, जो समन्वय प्रणाली के मूल बिंदु (जो बाद में ड्राइंग ऑपरेशन का (0,0) बिंदु है) को (50, 700) पर ले जाता है। यदि इसे नहीं बदला गया, तो डिफ़ॉल्ट मूल बिंदु पृष्ठ के बाएँ नीचे होता है।
पाठ ऑपरेटर
| ऑपरेटर | अर्थ | उदाहरण |
|---|---|---|
BT | Begin Text, पाठ ऑब्जेक्ट शुरू करें | BT |
ET | End Text, पाठ ऑब्जेक्ट समाप्त करें | ET |
Tf | फॉन्ट और फ़ॉन्ट आकार सेट करें | /F0 36 Tf |
Tj | स्ट्रिंग बनाना | (Hello!) Tj |
pdftk का उपयोग करके इसे एक खोले जाने योग्य PDF में ठीक करें
hello-broken.pdf के स्थान पर निम्नलिखित कमांड चलाएँ:
pdftk hello-broken.pdf output hello.pdf
किसी भी PDF रीडर का उपयोग करके hello.pdf खोलें, आपको पृष्ठ पर "Hello, World!" (Times-Italic फ़ॉन्ट, 36pt, पृष्ठ के बाएँ ऊपर) दिखाई देना चाहिए।
pdftk ने आपको क्या पूरा किया?
| पूरा किया गया | विवरण |
|---|---|
| बाइनरी चिह्न पंक्ति | %PDF-1.0 के बाद एक अदृश्य वर्ण पंक्ति जोड़ें, सुनिश्चित करें कि इसे बाइनरी फ़ाइल के रूप में पहचाना जाए |
/Length | सामग्री स्ट्रीम के लिए बाइट लंबाई की गणना और जोड़ें |
xref तालिका | प्रत्येक ऑब्जेक्ट के बाइट ऑफसेट की गणना करें और भरें |
startxref | xref तालिका की वास्तविक प्रारंभ स्थिति भरें |
xref / trailer / startxref की आवश्यकता क्यों है?
मुख्य उद्देश्य: रैंडम एक्सेस
कल्पना करें कि एक 500 पृष्ठ का PDF है, यदि xref नहीं है, तो रीडर को 450 वें पृष्ठ को प्रदर्शित करने के लिए 449 वें पृष्ठ तक पढ़ना होगा - यह बहुत धीमा है।
xref के साथ, रीडर कर सकता है:
- पहले
startxrefपढ़ें → xref स्थिति खोजें trailerपढ़ें → मूल ऑब्जेक्ट/Rootखोजें- मूल ऑब्जेक्ट से क्रम से → सीधे 450 वें पृष्ठ के ऑब्जेक्ट पर जाएं
- xref के माध्यम से उस ऑब्जेक्ट के बाइट ऑफसेट की जांच करें → सीधे पढ़ने के लिए वहां जाएं
समय जटिलता O(n) से O(1) में घट जाती है।
इस लेख का अभ्यास
सुझाव है कि आप वास्तव में hello-broken.pdf में बदलाव करें, फिर pdftk का उपयोग करके इसे फिर से ठीक करें, और प्रभाव देखें:
| अभ्यास | संशोधन सामग्री | अवलोकन बिंदु |
|---|---|---|
| A | (Hello, World!) को अन्य अंग्रेजी वाक्यांश में बदलें | पाठ परिवर्तन |
| B | 36 को 12 या 72 में बदलें | फ़ॉन्ट आकार परिवर्तन |
| C | 50 700 को 50 100 में बदलें | स्थिति नीचे की ओर (PDF समन्वय प्रणाली का मूल बिंदु बाएँ नीचे है) |
| D | /Times-Italic को /Helvetica या /Courier में बदलें | फ़ॉन्ट परिवर्तन |
| E | /MediaBox [0 0 612 792] को [0 0 595 842] में बदलें | कागज US Letter से A4 में बदल गया |
संकेत: PDF समन्वय प्रणाली का मूल बिंदु पृष्ठ के बाएँ नीचे है, Y-अक्ष ऊपर की ओर है।
(50, 700)का अर्थ है बाएँ 50pt, नीचे से 700pt की दूरी।
सामान्य प्रश्न
प्रश्न: Type1 अंतर्निहित फ़ॉन्ट का उपयोग क्यों किया जाता है, TrueType नहीं?
उत्तर: Type1 के 14 मानक फ़ॉन्ट (Times, Helvetica, Courier आदि) PDF रीडर में अंतर्निहित होते हैं, फ़ॉन्ट फ़ाइल को एम्बेड करने की आवश्यकता नहीं होती है, यह सबसे सरल है। वास्तविक परिदृश्यों में आमतौर पर प्लेटफ़ॉर्म के बीच संगति सुनिश्चित करने के लिए फ़ॉन्ट एम्बेड करने की आवश्यकता होती है।
प्रश्न: /MediaBox [0 0 612 792] ये संख्याएँ क्या हैं?
उत्तर: इकाई बिंदु है (1 बिंदु = 1/72 इंच)। 612 × 792 बिंदु = 8.5 × 11 इंच = US Letter कागज। A4 595 × 842 बिंदु है।
प्रश्न: जनरेशन नंबर (जैसे 2 0 R में 0) क्या है?
उत्तर: यह वृद्धि अपडेट के लिए है। जब ऑब्जेक्ट को संशोधित किया जाता है, तो जनरेशन नंबर 1 से बढ़ता है। नए बनाए गए PDF में सभी ऑब्जेक्ट्स का जनरेशन नंबर आमतौर पर 0 होता है।
अगली लेख की पूर्वसूचना
दूसरे लेख में हम "सामग्री स्ट्रीम को हाथ से लिखने" के तरीके को जारी रखते हुए सबसे बुनियादी ग्राफिक्स पथ संचालन को जोड़ेंगे:
m(moveto),l(lineto): पथ को परिभाषित करनाS(stroke): स्ट्रोकre(rectangle),f(fill): आयत बनाना और भरना
आपको एक ही पृष्ठ पर एक साथ चित्रित करने की अनुमति देगा: शीर्षक पाठ + एक क्षैतिज विभाजन रेखा + एक आयताकार बॉक्स, "लिखने में सक्षम" से "चित्र बनाने में सक्षम" में उन्नति।
