An extension of the wonderful pdfrw library that adds handling of content streams (and all the objects referenced therein, eg images, fonts etc.) while keeping it as simple as possible.
فلماذا تمديد PDFRW عندما تكون هناك مكتبات PDF كاملة مثل PYPDF؟ فكر في الأمر بهذه الطريقة: تحاول معظم مكتبات PDF توفير وظائف تبسيط مهام معالجة PDF الشائعة. هذه المكتبات جيدة جدًا فيما يفعلون ، ولكن مرة واحدة من حين لآخر ، تتطلب مهمة تتطلب وظيفة جديدة. الآن ، إذا كنت مطورًا في مثل هذا الموقف ، فيجب عليك البدء في الحفر في كميات كبيرة من التعليمات البرمجية المصدر لهذه المكتبات.
نهج PDFRW مختلف: دعنا نتحلى قدر الإمكان PDF ، مع الحفاظ على النتيجة بسيطة قدر الإمكان. Not a bad idea, especially given the fact that the PDF object model (which is just a bunch of dictionaries with some of their values being references to other dictionaries) is very well suited for mapping to standard Python dictionaries. On top of that, pdfrw implements an idea behind another wonderful package attrdict to make traversing PDF objects even simpler: accessing page fonts, for example, can now be done like this:
for fontName , fontDict in page . Resources . Font . items ():
( do something )The next step is to try to parse the dictionary streams — these are special entries in the dictionaries which contain the interesting stuff: text, images, vector graphics etc. pdfrw doesn't do any of that, and it doesn't do it on purpose: in accordance with its Unix-like philosophy, it does what it does very well, and doesn't do a bit extra. تكتمل بنية البيانات التي تنتجها: أنه يحتوي على جميع PDF ، وهو ما يكفي لأي مهمة معالجة محتملة. And it is simple enough so the developer could start coding right away, spending more time enjoying the passages in the Adobe's magnum opus, and none — learning another complicated library. وفي الواقع ، تعد PDFRW أداة مثالية للمساعدة في تعلم بناء جملة PDF من خلال اللعب معه!
حسنًا ، إذا وصلت إلى هذه النقطة ، فمن المحتمل أن تتساءل: إذن ، من أين أذهب من هنا؟ على وجه التحديد: كيف يمكنني تحليل تدفقات القاموس؟ هذا هو المكان الذي يمكن أن يساعد فيه PDFRWX : يمكن أن يحلل تدفقات القاموس والقيام بأشياء أخرى مفيدة. لكن أول الأشياء أولاً:
يحاول PDFRWX أولاً وقبل كل شيء الحفاظ على فلسفة PDFRW المذكورة أعلاه. إلى هذا ، يضيف ملاحظة أنه في العديد من مهام معالجة PDF يتم قضاء معظم الوقت في تطوير حل البرمجيات ، وليس عند تشغيله. هذا يؤدي إلى خيارات التصميم:
نحن الآن مستعدون لمعرفة ما يفعله PDFRWX وكيف يحققه:
فيما يلي أمثلة/مثال pdfstream.py الذي يقرأ مثال.
from pdfrw import PdfReader , PdfWriter , PdfArray
from pdfrwx . pdffilter import PdfFilter
from pdfrwx . pdfstreamparser import PdfStream
toArray = lambda obj : obj if isinstance ( obj , PdfArray )
else PdfArray ([ obj ]) if obj != None else PdfArray ()
pdfIn = PdfReader ( 'example.pdf' )
pdfOut = PdfWriter ( 'example-out.pdf' )
for page in pdfIn . pages :
contentsArray = toArray ( page . Contents )
for contents in contentsArray :
stream = PdfFilter . uncompress ( contents ). stream
treeIn = PdfStream . stream_to_tree ( stream )
treeOut = []
for leaf in treeIn :
cmd , args = leaf [: 2 ]
if cmd != 'BT' : treeOut . append ( leaf )
contents . stream = PdfStream . tree_to_stream ( treeOut )
contents . Filter = None
pdfOut . addPage ( page )
pdfOut . write ()As you can see, the code runs over pages, then over contents of every page, then uncompresses the contents, as it may be compressed, then parses the contents stream into a tree, removes the BT/ET text blocks, and then parses the resulting tree back to stream. The meaning of each line of code above should be clear apart from, possibly, the toArray lambda function: it's there because a page in PDF can have more than one Contents dictionary, in which case page.Contents is a PdfArray, and each of its elements has to be processed separately. And so, the toArray lambda function makes the situation with page contents more uniform by turning page.Contents that are not arrays into PdfArray with one element.
هناك بعض الأشياء الأخرى يجب الإشارة إليها أيضًا. First, note that in order to acomplish the task the code uses just two new classes from pdfrwx : PdfFilter and PdfStream, with one/two function calls from each. ثانياً ، الشجرة المحسورة أنا مجرد قائمة بيثون قياسية متداخلة للتنسيق التافلي التالي:
[
['q', []],
['cm', ['1','0','0','1','0','0']],
...
['BT', [], [ /a tree list of text operators/ ]],
...
['Q', []]
]
So, each leaf (element) of the tree list is itself a list of 2 or 3 elements: the first two elements are the command and the list of arguments (an empty list if the command has no arguments), while the third optional argument is present in the case where the leaf is a block of commands, in which case it is the tree list of the commands that make up the block. By design, there are just two types of blocks: the BT/ET text block, which uses command name 'BT' in the parsed tree, and the BI/ID/EI inline image block, which uses the command name 'BI' in the parsed tree. لاحظ أنه في دفق PDF الأصلي هناك مجرد سلسلة من الأوامر ؛ إنه محلل PDFStream الذي يخلق هذه الكتل في إخراجها للراحة. To further familiarize yourself with the structure of the output of the stream parser, try inserting a command like pprint(treeIn) right after the call to the parser.
Note also that the toArray function, however useful, has not been implemented in the module, and so you have to code it every time you do the parsing. قد يبدو هذا غريباً ، لكنه نتيجة لنفس مبادئ التصميم: الوحدة النمطية فقط تخيل الدفق ؛ الأمر متروك للمطور لترميز كل شيء آخر.
The PdfStream parser class is implemented in pure Python using just about 300 lines of code with the help of the popular (and pure Python!) SLY parser generator library by David Beazley — check out his lectures on YT, he is terrific! For the curious: the parser uses two parser states (ie two different parsers with different grammars that switch between themselves as they operate), one for parsing PDF literal strings (ie strings that are in parentheses), and the other — for everything else. Yep, in order for the literal strings to support encoding parentheses as part of the string the format of the PDF literal strings has been made so intricate that it required a separate parser just to parse those. So, if for some reason (speed?) you will ever want to implement the stream parser using another parser generator library make sure it supports a stack for parser states.
يحل الخطوط الجحيم. مستندات قريبا ، ترقبوا.
المرشحات المدعومة:
تعبت من حشرات منتجات Adobe الخاصة عندما يتعلق الأمر بدقة اللون في تصدير الصور؟ ثم وصلت إلى المكان الصحيح! تهدف إلى أن تكون فئة معالجة صورة PDF الأكثر دقة للجميع. مستندات قريبا ، ترقبوا.
برامج الترميز المدعومة (الترميز/فك الشفرة):
مسافات الألوان المدعومة:
زائد:
The module is perfectly usable at this time, and has been run through a multitude of tests to make sure it does what it promises to do correctly. ومع ذلك ، فهو ليس بأي حال من الأحوال بالقرب من ألفا: لم يتم الانتهاء من الواجهات بالكامل بعد. علاوة على ذلك ، يتم كسر معالجة الأخطاء (من المحتمل أن يتم إصلاحه قريبًا ويشبه كيفية التعامل مع الأخطاء في PDFRW ). لذا، العب على مسؤوليتك الخاصة في أي خطر ، لا تتوقع أن تكون من جودة الإنتاج بعد.