44Released under the GPL version 3, or (at your option) any later version.
55"""
66
7- import io
87import shutil
98import sys
109from abc import ABC , abstractmethod
1312from typing import IO
1413from warnings import warn
1514
16- from pypdf import PdfWriter , Transformation
17- from pypdf .annotations import PolyLine
15+ from pymupdf import Document , Matrix
1816
1917from .argparse import parserange
2018from .io import setup_input_and_output
@@ -384,20 +382,20 @@ def __init__(
384382 super ().__init__ ()
385383 self .outfile = outfile
386384 self .reader = reader
387- self .writer = PdfWriter ()
385+ self .writer = Document ()
388386 self .draw = draw
389387 self .specs = specs
390388
391389 if in_size is None :
392390 in_size = reader .size
393391 if size is None :
394392 size = in_size
395-
393+ assert size is not None
396394 self .size = size
397395 self .in_size = in_size
398396
399397 def pages (self ) -> int :
400- return len ( self .reader .pages )
398+ return self .reader .page_count
401399
402400 def write_header (self , maxpage : int , modulo : int ) -> None :
403401 pass
@@ -423,78 +421,60 @@ def write_page(
423421 len (page_specs ) == 1
424422 and not page_specs [0 ].has_transform ()
425423 and page_number < page_list .num_pages ()
426- and 0 <= real_page < len ( self .reader .pages )
424+ and 0 <= real_page < self .reader .page_count
427425 and self .draw == 0
428426 and self .size == self .in_size
429427 and (
430428 self .in_size .width is None
431429 or (
432- self .in_size .width == self .reader .pages [real_page ].mediabox .width
433- and self .in_size .height
434- == self .reader .pages [real_page ].mediabox .height
430+ self .in_size .width == self .reader [real_page ].mediabox .width
431+ and self .in_size .height == self .reader [real_page ].mediabox .height
435432 )
436433 )
437434 ):
438- self .writer .add_page (self .reader . pages [ real_page ] )
435+ self .writer .insert_pdf (self .reader , from_page = real_page , to_page = real_page )
439436 else :
440437 # Add a blank page of the correct size to the end of the document
441- outpdf_page = self .writer .add_blank_page (self .size .width , self .size .height )
438+ outpdf_page = self .writer .new_page (
439+ real_page , self .size .width , self .size .height
440+ )
442441 for spec in page_specs :
443442 page_number = page_index_to_page_number (spec , maxpage , modulo , pagebase )
444443 real_page = page_list .real_page (page_number )
445- if page_number < page_list .num_pages () and 0 <= real_page < len (
446- self .reader .pages
444+ if (
445+ page_number < page_list .num_pages ()
446+ and 0 <= real_page < self .reader .page_count
447447 ):
448448 # Calculate input page transformation
449- t = Transformation ()
449+ t = Matrix ()
450450 if spec .hflip :
451- t = t .transform (
452- Transformation ((- 1 , 0 , 0 , 1 , self .in_size .width , 0 ))
453- )
451+ t = t .concat (self , Matrix (- 1 , 0 , 0 , 1 , self .in_size .width , 0 ))
454452 elif spec .vflip :
455- t = t .transform (
456- Transformation ((1 , 0 , 0 , - 1 , 0 , self .in_size .height ))
457- )
458- if spec .rotate != 0 :
459- t = t .rotate (spec .rotate % 360 )
453+ t = t .concat (self , Matrix (1 , 0 , 0 , - 1 , 0 , self .in_size .height ))
460454 if spec .scale != 1.0 :
461- t = t .scale (spec .scale , spec .scale )
455+ t = t .prescale (spec .scale , spec .scale )
462456 if spec .off != Offset (0.0 , 0.0 ):
463- t = t .translate (spec .off .x , spec .off .y )
457+ t = t .pretranslate (spec .off .x , spec .off .y )
458+ # Transform input page mediabox
459+ mbox = self .reader [real_page ].mediabox .transform (t )
464460 # Merge input page into the output document
465- outpdf_page .merge_transformed_page (self .reader .pages [real_page ], t )
461+ outpdf_page .show_pdf_page (
462+ mbox , self .reader , real_page , rotate = spec .rotate % 360
463+ )
466464 if self .draw > 0 : # FIXME: draw the line at the requested width
467- mediabox = self .reader .pages [real_page ].mediabox
468- line = PolyLine (
469- vertices = [
470- (
471- mediabox .left + spec .off .x ,
472- mediabox .bottom + spec .off .y ,
473- ),
474- (mediabox .left + spec .off .x , mediabox .top + spec .off .y ),
475- (
476- mediabox .right + spec .off .x ,
477- mediabox .top + spec .off .y ,
478- ),
479- (
480- mediabox .right + spec .off .x ,
481- mediabox .bottom + spec .off .y ,
482- ),
483- (
484- mediabox .left + spec .off .x ,
485- mediabox .bottom + spec .off .y ,
486- ),
487- ],
488- )
489- self .writer .add_annotation (outpdf_page , line )
465+ line = [
466+ (mbox .x0 + spec .off .x , mbox .y1 + spec .off .y ),
467+ (mbox .x0 + spec .off .x , mbox .y0 + spec .off .y ),
468+ (mbox .x1 + spec .off .x , mbox .y0 + spec .off .y ),
469+ (mbox .x1 + spec .off .x , mbox .y1 + spec .off .y ),
470+ (mbox .x0 + spec .off .x , mbox .y1 + spec .off .y ),
471+ ]
472+ outpdf_page .draw_polyline (line )
490473
491474 def finalize (self ) -> None :
492- # PyPDF seeks, so write to a buffer first in case outfile is stdout.
493- buf = io .BytesIO ()
494- self .writer .write (buf )
495- buf .seek (0 )
496- self .outfile .write (buf .read ())
475+ self .outfile .write (self .writer .convert_to_pdf ())
497476 self .outfile .flush ()
477+ self .writer .close ()
498478
499479
500480def document_transform (
0 commit comments