mirror of
				https://github.com/python-pillow/Pillow.git
				synced 2025-11-04 09:57:43 +03:00 
			
		
		
		
	Added PDF multipage saving
This commit is contained in:
		
							parent
							
								
									eecd489ccf
								
							
						
					
					
						commit
						4e31fb745f
					
				| 
						 | 
					@ -51,17 +51,21 @@ def _endobj(fp):
 | 
				
			||||||
    fp.write("endobj\n")
 | 
					    fp.write("endobj\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def _save_all(im, fp, filename):
 | 
				
			||||||
 | 
					    _save(im, fp, filename, save_all=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
##
 | 
					##
 | 
				
			||||||
# (Internal) Image save plugin for the PDF format.
 | 
					# (Internal) Image save plugin for the PDF format.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def _save(im, fp, filename):
 | 
					def _save(im, fp, filename, save_all=False):
 | 
				
			||||||
    resolution = im.encoderinfo.get("resolution", 72.0)
 | 
					    resolution = im.encoderinfo.get("resolution", 72.0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #
 | 
					    #
 | 
				
			||||||
    # make sure image data is available
 | 
					    # make sure image data is available
 | 
				
			||||||
    im.load()
 | 
					    im.load()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    xref = [0]*(5+1)  # placeholders
 | 
					    xref = [0]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class TextWriter(object):
 | 
					    class TextWriter(object):
 | 
				
			||||||
        def __init__(self, fp):
 | 
					        def __init__(self, fp):
 | 
				
			||||||
| 
						 | 
					@ -78,11 +82,6 @@ def _save(im, fp, filename):
 | 
				
			||||||
    fp.write("%PDF-1.2\n")
 | 
					    fp.write("%PDF-1.2\n")
 | 
				
			||||||
    fp.write("% created by PIL PDF driver " + __version__ + "\n")
 | 
					    fp.write("% created by PIL PDF driver " + __version__ + "\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #
 | 
					 | 
				
			||||||
    # Get image characteristics
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    width, height = im.size
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # FIXME: Should replace ASCIIHexDecode with RunLengthDecode (packbits)
 | 
					    # FIXME: Should replace ASCIIHexDecode with RunLengthDecode (packbits)
 | 
				
			||||||
    # or LZWDecode (tiff/lzw compression).  Note that PDF 1.2 also supports
 | 
					    # or LZWDecode (tiff/lzw compression).  Note that PDF 1.2 also supports
 | 
				
			||||||
    # Flatedecode (zip compression).
 | 
					    # Flatedecode (zip compression).
 | 
				
			||||||
| 
						 | 
					@ -125,7 +124,7 @@ def _save(im, fp, filename):
 | 
				
			||||||
    #
 | 
					    #
 | 
				
			||||||
    # catalogue
 | 
					    # catalogue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    xref[1] = fp.tell()
 | 
					    xref.append(fp.tell())
 | 
				
			||||||
    _obj(
 | 
					    _obj(
 | 
				
			||||||
        fp, 1,
 | 
					        fp, 1,
 | 
				
			||||||
        Type="/Catalog",
 | 
					        Type="/Catalog",
 | 
				
			||||||
| 
						 | 
					@ -134,15 +133,27 @@ def _save(im, fp, filename):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #
 | 
					    #
 | 
				
			||||||
    # pages
 | 
					    # pages
 | 
				
			||||||
 | 
					    numberOfPages = 1
 | 
				
			||||||
 | 
					    if save_all:
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            numberOfPages = im.n_frames
 | 
				
			||||||
 | 
					        except AttributeError:
 | 
				
			||||||
 | 
					            # Image format does not have n_frames. It is a single frame image
 | 
				
			||||||
 | 
					            pass
 | 
				
			||||||
 | 
					    pages = [str(pageNumber*3+4)+" 0 R"
 | 
				
			||||||
 | 
					             for pageNumber in range(0, numberOfPages)]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    xref[2] = fp.tell()
 | 
					    xref.append(fp.tell())
 | 
				
			||||||
    _obj(
 | 
					    _obj(
 | 
				
			||||||
        fp, 2,
 | 
					        fp, 2,
 | 
				
			||||||
        Type="/Pages",
 | 
					        Type="/Pages",
 | 
				
			||||||
        Count=1,
 | 
					        Count=len(pages),
 | 
				
			||||||
        Kids="[4 0 R]")
 | 
					        Kids="["+"\n".join(pages)+"]")
 | 
				
			||||||
    _endobj(fp)
 | 
					    _endobj(fp)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for pageNumber in range(0, numberOfPages):
 | 
				
			||||||
 | 
					        im.seek(pageNumber)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        #
 | 
					        #
 | 
				
			||||||
        # image
 | 
					        # image
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -165,9 +176,14 @@ def _save(im, fp, filename):
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            raise ValueError("unsupported PDF filter (%s)" % filter)
 | 
					            raise ValueError("unsupported PDF filter (%s)" % filter)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    xref[3] = fp.tell()
 | 
					        #
 | 
				
			||||||
 | 
					        # Get image characteristics
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        width, height = im.size
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        xref.append(fp.tell())
 | 
				
			||||||
        _obj(
 | 
					        _obj(
 | 
				
			||||||
        fp, 3,
 | 
					            fp, pageNumber*3+3,
 | 
				
			||||||
            Type="/XObject",
 | 
					            Type="/XObject",
 | 
				
			||||||
            Subtype="/Image",
 | 
					            Subtype="/Image",
 | 
				
			||||||
            Width=width,  # * 72.0 / resolution,
 | 
					            Width=width,  # * 72.0 / resolution,
 | 
				
			||||||
| 
						 | 
					@ -187,16 +203,18 @@ def _save(im, fp, filename):
 | 
				
			||||||
        #
 | 
					        #
 | 
				
			||||||
        # page
 | 
					        # page
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    xref[4] = fp.tell()
 | 
					        xref.append(fp.tell())
 | 
				
			||||||
    _obj(fp, 4)
 | 
					        _obj(fp, pageNumber*3+4)
 | 
				
			||||||
        fp.write(
 | 
					        fp.write(
 | 
				
			||||||
            "<<\n/Type /Page\n/Parent 2 0 R\n"
 | 
					            "<<\n/Type /Page\n/Parent 2 0 R\n"
 | 
				
			||||||
            "/Resources <<\n/ProcSet [ /PDF %s ]\n"
 | 
					            "/Resources <<\n/ProcSet [ /PDF %s ]\n"
 | 
				
			||||||
        "/XObject << /image 3 0 R >>\n>>\n"
 | 
					            "/XObject << /image %d 0 R >>\n>>\n"
 | 
				
			||||||
        "/MediaBox [ 0 0 %d %d ]\n/Contents 5 0 R\n>>\n" % (
 | 
					            "/MediaBox [ 0 0 %d %d ]\n/Contents %d 0 R\n>>\n" % (
 | 
				
			||||||
                procset,
 | 
					                procset,
 | 
				
			||||||
 | 
					                pageNumber*3+3,
 | 
				
			||||||
                int(width * 72.0 / resolution),
 | 
					                int(width * 72.0 / resolution),
 | 
				
			||||||
            int(height * 72.0 / resolution)))
 | 
					                int(height * 72.0 / resolution),
 | 
				
			||||||
 | 
					                pageNumber*3+5))
 | 
				
			||||||
        _endobj(fp)
 | 
					        _endobj(fp)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        #
 | 
					        #
 | 
				
			||||||
| 
						 | 
					@ -209,8 +227,8 @@ def _save(im, fp, filename):
 | 
				
			||||||
                int(width * 72.0 / resolution),
 | 
					                int(width * 72.0 / resolution),
 | 
				
			||||||
                int(height * 72.0 / resolution)))
 | 
					                int(height * 72.0 / resolution)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    xref[5] = fp.tell()
 | 
					        xref.append(fp.tell())
 | 
				
			||||||
    _obj(fp, 5, Length=len(op.fp.getvalue()))
 | 
					        _obj(fp, pageNumber*3+5, Length=len(op.fp.getvalue()))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        fp.write("stream\n")
 | 
					        fp.write("stream\n")
 | 
				
			||||||
        fp.fp.write(op.fp.getvalue())
 | 
					        fp.fp.write(op.fp.getvalue())
 | 
				
			||||||
| 
						 | 
					@ -232,6 +250,7 @@ def _save(im, fp, filename):
 | 
				
			||||||
# --------------------------------------------------------------------
 | 
					# --------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Image.register_save("PDF", _save)
 | 
					Image.register_save("PDF", _save)
 | 
				
			||||||
 | 
					Image.register_save_all("PDF", _save_all)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Image.register_extension("PDF", ".pdf")
 | 
					Image.register_extension("PDF", ".pdf")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,16 +1,19 @@
 | 
				
			||||||
from helper import unittest, PillowTestCase, hopper
 | 
					from helper import unittest, PillowTestCase, hopper
 | 
				
			||||||
 | 
					from PIL import Image
 | 
				
			||||||
import os.path
 | 
					import os.path
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TestFilePdf(PillowTestCase):
 | 
					class TestFilePdf(PillowTestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def helper_save_as_pdf(self, mode):
 | 
					    def helper_save_as_pdf(self, mode, save_all=False):
 | 
				
			||||||
        # Arrange
 | 
					        # Arrange
 | 
				
			||||||
        im = hopper(mode)
 | 
					        im = hopper(mode)
 | 
				
			||||||
        outfile = self.tempfile("temp_" + mode + ".pdf")
 | 
					        outfile = self.tempfile("temp_" + mode + ".pdf")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Act
 | 
					        # Act
 | 
				
			||||||
 | 
					        if save_all:
 | 
				
			||||||
 | 
					            im.save(outfile, save_all=True)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
            im.save(outfile)
 | 
					            im.save(outfile)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Assert
 | 
					        # Assert
 | 
				
			||||||
| 
						 | 
					@ -58,6 +61,19 @@ class TestFilePdf(PillowTestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.assertRaises(ValueError, lambda: im.save(outfile))
 | 
					        self.assertRaises(ValueError, lambda: im.save(outfile))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_save_all(self):
 | 
				
			||||||
 | 
					        # Single frame image
 | 
				
			||||||
 | 
					        self.helper_save_as_pdf("RGB", save_all=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Multiframe image
 | 
				
			||||||
 | 
					        im = Image.open("Tests/images/dispose_bgnd.gif")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        outfile = self.tempfile('temp.pdf')
 | 
				
			||||||
 | 
					        im.save(outfile, save_all=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertTrue(os.path.isfile(outfile))
 | 
				
			||||||
 | 
					        self.assertGreater(os.path.getsize(outfile), 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if __name__ == '__main__':
 | 
					if __name__ == '__main__':
 | 
				
			||||||
    unittest.main()
 | 
					    unittest.main()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user