2 पॉइंट द्वारा GN⁺ 2023-09-05 | 1 टिप्पणियां | WhatsApp पर शेयर करें
  • बिना किसी commercial PDF tool के PDF की text content बदलनी हो, तो compressed stream को unpack करना होगा, font-specific encoding को समझना होगा, और original text व replacement phrase को उसी तरीके से बदलना होगा
  • कई PDF असली document text को plain text की तरह नहीं बल्कि compressed stream और hex string जैसी दिखने वाली string के रूप में स्टोर करते हैं, और qpdf --qdf --object-streams=disable से इन्हें editing के लिए अपेक्षाकृत खुला रूप दिया जा सकता है
  • text block BT, Tf, Td, Tj, ET जैसे PDF commands से बनते हैं, और <002a004800570003003600480057> Tj जैसा मान साधारण Unicode codepoint नहीं भी हो सकता है
  • अगर PDF में font-specific ToUnicode mapping शामिल है, तो pdffonts से emb और uni के yes होने की जाँच की जा सकती है, और /ToUnicode 19 0 R जैसे reference को follow करके encoding table खोजी जा सकती है
  • PDF standard की जटिलता के कारण यह तरीका हर file पर सामान्य रूप से लागू नहीं होता, लेकिन कुछ खास PDF में original encoding ढूँढकर find-and-replace से text बदला जा सकता है

compressed PDF text stream को unpack करना

  • PDF को text editor में खोलने पर कुछ structure पढ़ा जा सकता है, लेकिन असली document text दिखाई नहीं भी दे सकता है
  • कई PDF text data को compressed form में स्टोर करते हैं
  • qpdf से compressed text stream को unpack करके देखा जा सकता है
    • Mac पर homebrew formula उपलब्ध है
    • Linux distributions में भी संबंधित tool उपयोग किए जा सकते हैं
qpdf --qdf --object-streams=disable in.pdf out.pdf
  • edit करने के बाद stream को फिर से compress किया जा सकता है
qpdf out-edited.pdf out-recompressed.pdf
  • recompress command ने error दिया, लेकिन बनी हुई PDF Preview में पढ़ी जा सकती थी

PDF commands के भीतर text ढूँढना

  • unpack करने के बाद भी text PDF command block के भीतर ही रहता है
  • एक basic text block कुछ ऐसा दिखता है
BT
  /Font_0 12 Tf
  288 720 Td
  <002a004800570003003600480057> Tj
ET
  • PDF Reference के अनुसार यह block क्रम से ये काम करता है
    • text object शुरू करता है
    • उपयोग होने वाला font और size सेट करता है
    • page पर शुरुआती position तय करता है
    • उस position पर string के glyph draw करता है
    • text object समाप्त करता है

text सीधे पढ़ा क्यों नहीं जाता

  • <002a004800570003003600480057> जैसा मान hex string जैसा दिखता है, लेकिन यह साधारण Unicode codepoint list नहीं भी हो सकता है
  • PDF में encoding बताने के कई तरीके होते हैं, और file के भीतर custom encoding भी शामिल हो सकती है
  • ऐसी encoding अधिकतर Unicode codepoint से map की जा सकती है
  • यह प्रक्रिया इस मान्यता पर आधारित है कि जिस PDF पर काम हो रहा है उसमें embedded encoding शामिल है
    • दूसरे मामलों को कैसे संभालना है, यह यहाँ शामिल नहीं है

font और Unicode mapping की जाँच

  • PDF का text encoding किसी खास font से जुड़ा होता है
  • pdffonts PDF के भीतर के fonts और encoding-संबंधित जानकारी दिखाता है
$ 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
  • यहाँ देखने लायक field ये हैं
    • emb: इसका मतलब font PDF में embedded है
    • uni: इसका मतलब Unicode mapping मौजूद है
  • अगर दोनों मान yes हैं, तो ज़रूरी mapping मिलने की संभावना है
  • /Font_0 जैसा font identifier कुछ मामलों में pdffonts output के font name से मेल खा सकता है
    • इस उदाहरण में /Font_0 CLDQZB+TrebuchetMS,Bold को संकेत कर रहा था

ToUnicode mapping table तक पहुँचना

  • text में इस्तेमाल हुए font का पूरा नाम मिलने के बाद PDF के भीतर उसी नाम को search किया जाता है
  • किसी खास जगह पर नीचे जैसा reference मिल सकता है
/ToUnicode 19 0 R
  • यह मान encoding table object ID की ओर इशारा करता है
  • फिर 19 0 obj खोजने पर संबंधित table मिल सकती थी

encoding table का उपयोग करके text replace करना

  • mapping table का मुख्य हिस्सा कुछ ऐसा हो सकता है
38 beginbfrange^M
<0036><0036><0053>^M
<0057><0057><0074>^M
<0044><0044><0061>^M
<0048><0048><0065>^M
<0050><0050><006D>^M
...
  • यह उदाहरण custom encoding point की range को Unicode point से map करता है
    • यहाँ range एक-एक character की है
    • 0036 Unicode point 0053 से map होता है
  • अगर table format अलग हो, तो ToUnicode mapping file tutorial देखा जा सकता है
  • automatic conversion के लिए Python से table को dictionary में बदला गया और सरल encoding/decoding functions लिखे गए
  • अंतिम replacement flow इस प्रकार है
    • जिस existing text को बदलना है उसका custom encoding value पता करें
    • replacement text को उसी तरीके से custom encoding में encode करें
    • PDF में find-and-replace करके पुराने value को बदल दें

1 टिप्पणियां

 
GN⁺ 2023-09-05
Hacker News राय
  • PDF specification काफी खुरदरा है। इन दिनों मेरी पसंदीदा trivia यह है कि overlapping elements render करते समय यह Photoshop के सभी layer blend modes support करता है
    दूसरी पसंदीदा बात यह है कि बाद में append किया गया content पहले वाले content को modify कर सकता है, इसलिए एक ही file में represent किए गए अलग-अलग versions को forensic तरीके से देखना पड़ता है
    यह DRM की निरर्थकता दिखाने वाला उदाहरण भी है। specification में password-based encryption है, “owner” और “user” passwords अलग-अलग रखे जा सकते हैं, और “printing not allowed”, “text copying not allowed” जैसे bit fields भी हैं। लेकिन document पढ़ने के लिए आखिर decrypt करना ही पड़ता है, इसलिए “user” password से किसी non-compliant tool में encrypted PDF खोलकर unencrypted version के रूप में save कर दें, तो editable equivalent मिल जाता है
    [1] “More than just transparency” section of 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] Page 61 of https://opensource.adobe.com/dc-acrobat-sdk-docs/pdfstandard...
    [4] उदाहरण के लिए pypdf library इस्तेमाल करने वाली script

    • यह मूल रूप से proprietary format था, सबके लिए व्यापक रूप से publicly available नहीं था, और उस दौर में बनाया गया था जब encryption export laws से कड़ाई से नियंत्रित था—इस context में ऐसी security through obscurity बहुत आम थी
      उस समय के famous cracking tutorials में से एक तरीका official reader के DRM को हटाने के लिए permissions check करने वाले function को patch करना था
    • तरीका: https://www.cyberciti.biz/faq/removing-password-from-pdf-on-...
    • क्या supported blend modes बस Porter-Duff compositing modes नहीं हैं? यह ज़्यादा लग सकता है, लेकिन दूसरे rendering pipelines जो provide करते हैं उनसे बहुत अच्छी तरह match करता है, और PDF generate करने का workload घटाने में काफी मदद करता है
    • permissions field में गहराई से उतरें तो कुछ PDF writers specification का पालन कैसे नहीं करते, और अलग-अलग PDF readers या libraries में मौजूद या गैर-मौजूद workarounds कैसे होते हैं—इस rabbit hole में चले जाते हैं
    • निष्पक्ष रूप से कहें तो अगर text copying रोकनी हो, तो font की ToUnicode mapping हटाना सबसे आसान है। फिर लोगों को उसे खुद manual तरीके से फिर से बनाना पड़ता है
  • यह topic समय-समय पर आता रहता है, और ज्यादातर लोग PDF को crack करना मुश्किल binary format समझते हैं, लेकिन असल में ऐसा नहीं है
    PDF अलग-अलग types का object graph है, और types खुद official specification में अच्छी तरह समझाए गए हैं। मुझे उसे मज़े के लिए पढ़ने जैसा एक painful taste है
    मेरी हमेशा सलाह रहती है कि लेखक की तरह PDF को ऐसी version में convert करें जिसमें compressed data न हो। पसंदीदा tool mutool है, और mutool clean -d in.pdf out.pdf इस्तेमाल कर सकते हैं। फिर उसमें खोजबीन करें तो हैरानी होगी कि उम्मीद से ज्यादा चीजें follow की जा सकती हैं
    लेख में page object देखकर resources check करने वाला step छूट गया है। content stream में इस्तेमाल होने वाला font name असली child object से जहां जुड़ता है, वह वही जगह है
    एक और महत्वपूर्ण बात छूटी है कि ज्यादातर fonts PDF के अंदर subset के रूप में शामिल होते हैं। font में सिर्फ जरूरी glyphs रखे जाते हैं। re-encoding आम तौर पर शायद यहीं होती है, और ToUnicode text copying या PDF search enable करने के लिए रखा जाता है। यह users के लिए अच्छा तत्व है, और मेरे अनुभव में ज्यादातर मौजूद और सही होता है

    • अगर “मज़े के लिए पढ़ते हैं” तो आप sadist नहीं बल्कि masochist के करीब हैं। अगर आप specification लिखने में शामिल थे या दूसरों से पढ़वाया था, तो sadist होते
    • यह अफसोस की बात है कि Adobe ने इतना मुश्किल format design किया कि जो basic task होना चाहिए, उसे कोई कर दे तो लोग हैरान होते हैं
      शुरुआत से ही read-only format बनाने की design philosophy गलत थी। लोगों की सबसे पहली मांग कौन-सी feature होगी, यह साफ नहीं था क्या
    • दर्द झेलने में आनंद मिले तो masochist, और दूसरों को दर्द देने में आनंद मिले तो sadist। आप लोगों की मदद करने की तरफ दिखते हैं, इसलिए पहले वाले के करीब हैं। mutool वाली सलाह के लिए धन्यवाद
    • PDF parsing के लिए मैं Amazon Textract पर काफी निर्भर हूं
      cloud provider के बिना native तरीके से इसे अच्छी तरह handle करने पर कोई और insight है क्या? खासकर tables handle करते समय
  • यह इस तरह किया जा सकता है:
    pdf2ps a.pdf से PostScript a.ps में बदलें
    vim a.ps से PostScript को सीधे edit करें
    ps2pdf a.ps से फिर से PDF में बदलें
    जिन complex PDF में embedded JavaScript या animation जैसी चीज़ें होती हैं, वे इस round-trip के बाद कभी-कभी ठीक से काम नहीं करतीं। फिर भी साधारण documents के लिए यह काफी अच्छे से काम करता है। watermark हटाना, शब्द और नंबर बदलना आसान है, और spacing ठीक करना ज्यादा मुश्किल है। बेशक PostScript की कुछ समझ होनी चाहिए

    • जिस mail-processing company में मैं पहले काम करता था, वहाँ कुछ print-prep work लगभग इसी तरह किया जाता था। आम तौर पर printing के लिए documents सही tools से बनाए जाते थे, लेकिन कभी-कभी customers खुद को ज्यादा जानकार समझकर PDF भेज देते थे, और आम तौर पर उनमें ज्यादा manual work लगता था और error की संभावना भी ज्यादा होती थी
      output सही हो तब भी pages reorder करना, mailing machine processing और mail sorting के लिए barcode लगाना, और reports generate करना जरूरी होता था। आम तौर पर Perl और दूसरे tools से pages से text scrape करके address निकाले जाते थे, और PDF की तुलना में PS आम तौर पर बहुत आसान था, लेकिन बहुत unstable cases भी होते थे, जैसे जब “secure” PDF में सही glyph mapping नहीं होती थी
      सबसे बुरे case में customers single-document PDFs भेजते थे, और इन्हें merge करने पर output में subset fonts की बाढ़ आ जाती थी, जिससे printer memory भरकर printer मर जाता था। जब मैंने वह काम छोड़ा, तब भी मुझे नहीं लगता कि उसी original font से आए subset fonts को consolidate/merge करने वाला कोई उपयोगी tool था। यह संभव होना चाहिए था और बहुत उपयोगी होता, लेकिन मेरे पास इसे देखने का समय या knowledge नहीं था
    • अगर PDF में JavaScript और animation डाले जा सकते हैं, तो उसके अंदर frontend बनाने से रोकता क्या है? PDF से क्या-क्या किया जा सकता है, इसकी boundaries जानने की जिज्ञासा है
      सच कहूँ तो PDF की complexity से फायदा उठाने वाले सिर्फ malware creators ही लगते हैं
  • लगता है एक अहम बात छूट गई है। PDF के अंत में file के अंदर कई objects के byte offsets store करने वाली table होती है, यानी cross-reference table
    file के अंदर कुछ modify करने पर आम तौर पर ये offsets बदल जाते हैं और file टूट जाती है। लेख शायद सिर्फ एक number को दूसरे number से बदलने में interested था, इसलिए position शायद नहीं बदली होगी
    लेकिन आम तौर पर file के बीच में add/delete/modify करने पर xref table को फिर से calculate करना पड़ता है, इसलिए direct text editing की तुलना में library इस्तेमाल करना कहीं आसान हो जाता है

    • इसलिए qpdf से decode करके बाद में फिर encode किया जाता है। तब qpdf वह हिस्सा संभालता है
      qpdf लगता है original PDF structure को reconstruct करता है, और object numbers भी वैसे ही रखने की कोशिश करता है, लेकिन offsets पूरी तरह फिर से calculate होते हैं
    • मेरे हिसाब से PDF specification का यही सबसे अजीब हिस्सा है। binary और text मिले हुए हैं, और byte offsets text के रूप में specified हैं
      अगर authors कभी इसके बारे में बताएं, तो मैं पढ़ना चाहूँगा कि format ऐसा क्यों बनाया गया। लगता है शुरुआत में इसे पूरी तरह text format के रूप में सोचा गया था, फिर बाद में binary को ज्यादा efficient माना गया। हालांकि xref table entries की length fixed रखनी पड़ती है, यह बात उस assumption के साथ भी थोड़ी अजीब तरह से जुड़ती है
    • मेरे अनुभव में xref table को बस तोड़ देना और उसे ठीक करने के लिए mutool clean जैसी चीज़ चलाना सबसे आसान है। चूँकि इसे content से पूरी तरह derive किया जा सकता है, इसलिए यह safe है
    • यह compiled binary edit करने जैसा काफी है
      जब तक length preserve करें, binary में मनचाहे changes कर सकते हैं
      पहले इस्तेमाल होने वाला एक software server पर authenticate करता था, लेकिन सारी processing client पर होती थी। client सीधे server पर SQL execute करता था, और server बस यह check करता था कि यह client खरीदी गई licenses की संख्या से ज्यादा तो नहीं जा रहा
      disassembler में चलाकर check करने वाला हिस्सा ढूँढ सकते थे, उस हिस्से को सीधे JMP में बदल सकते थे, और बची हुई जगह NOP से भर सकते थे
  • qpdf के --qdf mode का इस्तेमाल करते समय लगता है एक अहम step छूट गया है। editing खत्म होने के बाद file को fix-pdf utility से pass कराना चाहिए ताकि सभी object offsets फिर से calculate हों और file के अंत की cross-reference table फिर से बने। हाँ, अगर आपने bytes add या remove नहीं किए और सिर्फ inplace बदलाव किए, तो exception है
    PDF के top 3 मजेदार facts ये हैं

    1. PDF documents आम तौर पर 8-bit binary files होते हैं, लेकिन ASCII85 filter इस्तेमाल करके images समेत valid UTF-8 plaintext PDF बनाया जा सकता है
    2. PDF 3D objects, JavaScript, embedded Flash objects के अंदर video, invisible annotations जैसी अजीबोगरीब features की भारी संख्या allow करता है। PDF/A ज्यादा sane और safe subset है
    3. PDF specification widgets, जैसे form controls, को XHTML और CSS के subset यानी rich text में लिखने देता है। हालांकि official Adobe Reader के बाहर इस feature का support बहुत दुर्लभ है
      [0] उदाहरण: https://lab6.com/2
    • editing खत्म होने के बाद, लेख के शुरुआती हिस्से में बताए अनुसार इसे बिना parameters के qpdf से pass करा दें। इससे data फिर से compress होगा और xref table भी फिर से बनेगी। किसी दूसरे tool की जरूरत नहीं है
  • PDF journey जारी रखते हुए अगर और सीखना चाहते हैं, तो हाल में तैयार किया गया file dissection document पढ़ सकते हैं:
    https://pdfsyntax.dev/introduction_pdf_syntax.html

  • PDF के बारे में लोग अक्सर जो बात चूक जाते हैं, वह यह है कि कुछ मायनों में यह Word document से ज़्यादा image format के करीब है। document editing में Word document, PDF और image वैसे ही हैं जैसे music में DAW project, MIDI और MP3; और software में Java source code, JVM bytecode और pure x86 machine code
    PDF file का मुख्य उद्देश्य यह है कि वास्तविक image की तुलना में बहुत कम bytes में पूरी स्पष्टता से बताया जाए कि क्या दिखाना या print करना है। यह इस बात का फायदा उठाता है कि document बनाने वाला document structure के patterns जानता है, ताकि सही ढंग से व्यक्त करने पर यह वास्तविक image compression algorithms से कहीं बेहतर compress हो सके। उदाहरण के लिए, अगर वास्तविक font तक access हो, तो हर अक्षर की उपस्थिति को image के हिस्से के रूप में डालकर compression algorithm से repetition कम करने की उम्मीद करने के बजाय, “इन characters को इन coordinates पर इस spacing के साथ रखो” कहना बेहतर है। कौन सा character किस word से जुड़ा है, या यहां तक कि कौन सा Unicode codepoint किस font glyph से मेल खाता है, अगर लक्ष्य सिर्फ document image को efficiently deliver करना है तो मूल रूप से महत्वपूर्ण नहीं है
    editable document में representation के साथ-साथ content की semantic structure कहीं ज़्यादा महत्वपूर्ण हो जाती है। text में कोई खास break कई spaces है, table का अगला column है, या image की वजह से बना अजीब page layout—यह महत्वपूर्ण है। हर page के नीचे का text लेखक ने कई बार डाला है, या एक बार type करके footer के रूप में set किया है—यह भी महत्वपूर्ण है। अगर नया paragraph जोड़कर page layout बदलना है, तो यह बात महत्वपूर्ण है कि इस page का आखिरी paragraph footnote है और उसे अगले page पर नहीं जाना चाहिए। section title अगर दूसरे page पर चला जाए तो table of contents अपने-आप update होना चाहिए—यह महत्वपूर्ण है; यह सिर्फ लेखक द्वारा manually type किया गया text नहीं होना चाहिए
    printer या screen के नज़रिए से इन बातों का कोई मतलब नहीं। उसे जैसा निर्देश मिला है, वैसा print या display करना है। PDF में footnote, section title, footer, table of contents का special होना ज़रूरी नहीं; वे अर्थहीन formatting वाला text भी हो सकते हैं। इसलिए display या printing के अलावा किसी उद्देश्य के लिए PDF इस्तेमाल करने की कोशिश करें तो यह 100% accurate नहीं हो सकता। बेशक, इसे सुधारने की कोशिशें हैं, और PDF generation programs मनचाहा metadata स्वतंत्र रूप से डाल सकते हैं, लेकिन यह अनिवार्य नहीं है
    हो सकता है PDF लेखकों का intended mental model यह न रहा हो, लेकिन PDF वैसा क्यों है यह समझने के लिए यह उपयोगी दृष्टिकोण है

    • PDF का मूल लक्ष्य portable print-fidelity copy बनाना था। असली WYSIWYG। PDF file को laser printer, Linotype, या screen—कहीं भी भेजें, उसे एक जैसा दिखना था
      PostScript printer पर output करने पर यह बिल्कुल वैसा ही दिखता था, और Type 1 fonts इस्तेमाल करने पर कभी-कभी और बेहतर भी होता था
  • जो व्यक्ति यह करना चाहता है, वह PDF की मुख्य बात चूक रहा है। PDF एक page description format है, इसलिए यह document structure नहीं बल्कि page पर दिखने वाले marks को ही दर्शाता है
    PDF को edit करने की कोशिश न करें; उस original document को edit करें जिससे PDF बना था

    • लोग मुझे वे PDF भेजना बंद कर दें जिन्हें मैं edit करना चाहता हूं, तो मैं भी PDF editing बंद कर दूंगा
      किसी तरह edit करने के लिए बने documents को सीधे भेजना “professional नहीं” माना जाने लगा, और आखिरकार यही स्थिति बन गई
    • PDF में logical document structure information शामिल करने की सुविधा भी support होती है। इसे Tagged PDF कहा जाता है
      यह optional है, लेकिन accessibility के लिए recommended है। उदाहरण के लिए PDF/UA है। [1] के sections 14.7–14.8 देखें
      [1] https://opensource.adobe.com/dc-acrobat-sdk-docs/pdfstandard...
    • यहां “ऐसा नहीं करना चाहिए” कहना खास मायने नहीं रखता। असल दुनिया में किसी-न-किसी तरह PDF editing की मांग वाली स्थितियां बहुत हैं
    • एक मुश्किल यह है कि ऐसे corrections mark करना जो original document में वापस जाने चाहिए। typesetter से proof मिलता है, और उन्हें ठीक करने के लिए mark करना होता है
      PDF text को सीधे बदल नहीं सकते। क्योंकि typesetter वह change नहीं देखेगा। Acrobat के markup tools भयानक नहीं हैं, लेकिन वे कागज और लाल pencil वाले दिनों जितने अच्छे नहीं। जब तक आप Acrobat का “pencil” tool न इस्तेमाल करें। अच्छा होगा अगर यह हिस्सा बेहतर हो जाए
    • अगर यह “page description format” है और document structure नहीं, बल्कि सिर्फ page पर दिखाई देने वाली चीज़ों को दर्शाता है, तो नाम Portable Document Format की जगह Page Description Format होना चाहिए था, नहीं?
  • 20 साल पहले मैं एक newspaper company में printing plate in-charge के तौर पर काम करता था। हमारे पास million-dollar वाली दो Kodak plate “printers” थीं, हालांकि printer कहना ठीक नहीं है। अगर मेरी याद सही है, तो plate की emulsion ultraviolet light पड़ने पर chemical bath में dissolve होती थी
    Kodak equipment अक्सर fail हो जाता था, और मेरे boss PostScript या EPS files को सीधे खोलकर layout software द्वारा भेजे गए headers या गलत हिस्सों को ठीक करते थे। फिर यह फिर से ठीक चलने लगता था। वैसे, हमारी विशाल German offset web press Linux चलाती थी
    शायद मेरे boss का नाम Bill था। वह अच्छा इंसान था, जिसने 17 साल के मुझे Sigur Ros concert में ले गया था। PDF से unrelated दो बातें हो गईं

  • अच्छा लेख है। पिछले करीब 5 वर्षों में DocSpring [1] बनाते हुए मैंने PDF specification काफी पढ़ी है, फिर भी लगता है कि अभी सिर्फ सतह ही खुरची है। qpdf शानदार tool है, और मेरा एक और पसंदीदा tool RUPS [2] है, जिससे PDF structure को गहराई से explore किया जा सकता है
    [1] https://docspring.com
    [2] https://github.com/itext/i7j-rups