def pdf_show(datei, seite): page_idx = int(seite) - 1 page = PDFcfg.doc.loadPage(page_idx) # get the page irect = page.bound().round() # integer rectangle representing it pix = fitz.Pixmap(fitz.Colorspace(fitz.CS_RGB), irect) # empty RGB pixmap of this size pix.clearWith(255) # clear it with color "white" dev = fitz.Device(pix) # create a "draw" device page.run(dev, fitz.Identity) # render the page pix.writePNG(datei) return
def pdf_show(pdf, page): page = pdf.loadPage(page - 1) # load the page irect = page.bound().round() # integer rectangle representing it pix = fitz.Pixmap(fitz.Colorspace(fitz.CS_RGB), irect) # create an empty RGB pixmap of this size pix.clearWith(255) # clear it with color "white" dev = fitz.Device(pix) # create a "draw" device page.run(dev, fitz.Identity) # render the page data = str(pix.samples) # pixel area. NEW: returns bytearray # this function needs "data" to be a string bitmap = wx.BitmapFromBufferRGBA(irect.width, irect.height, data) # turn in wx.Bitmap # If you experience issues with this function, try the following code. # It will use "wx.BitmapFromBuffer" and thus ignore the transparency (alpha). # data2 = "".join([data[4*i:4*i+3] for i in range(len(data)/4)]) # bitmap = wx.BitmapFromBuffer(width, height, data2) return bitmap
here we introduce the display list, which provides caching-mechanisms to reduce parsing of a page. first, we need to create a display list hand it over to a list device and then populate the display list by running the page through that device, with transformation applied ''' mediabox = page.rect dl = fitz.DisplayList(mediabox) dv = fitz.Device(dl) page.run(dv, trans) # get the page size, and then apply the transformation rect = mediabox.transform(trans) # create a pixmap with RGB as colorspace and bounded by irect pm = fitz.Pixmap(fitz.Colorspace(fitz.CS_RGB), rect.round()) # clear it with 0xff white pm.clearWith(0xff) # fitz.Device(pm, None) is a device for drawing # we run the display list above through this drawing device # with area provided dl.run(fitz.Device(pm, None), fitz.Identity, rect) # the drawing device save the result into the pixmap # and we save the pixmap as a PNG file pm.writePNG(sys.argv[5]) # and the page is no longer needed for drawing pixmap now # we can drop those resources page = None
punch(pm, x00, y01, x01, y02) # middle left pm.clearWith(0, ir) # clear center to black punch(pm, x02, y01, x03, y02) # middle right punch(pm, x00, y02, x01, y02) # bottom left punch(pm, x01, y02, x02, y03) # bottom middle punch(pm, x02, y02, x03, y03) # bottom right return #============================================================================== # main program #============================================================================== d = 3**6 # = 729, picture dimension in pixels # create a quadratic pixmap with origin (0,0), where width = height = d should # be a power of 3 t0 = time.clock() cs = fitz.Colorspace(fitz.CS_RGB) ir = fitz.IRect(0, 0, d, d) pm = fitz.Pixmap(cs, ir) # fill image area with "white" and then optionally tint and gamma it pm.clearWith(255) #pm.tintWith(10, 20, 100) # tint it with some sort of blue #pm.gammaWith(0.5) # lighten it up # now punch holes into it, down to 1 pixel granularity punch(pm, 0, 0, d, d) t1 = time.clock() pm.writePNG("sierpinski.png") t2 = time.clock() print("%f sec to create img" % (t1 - t0)) print("%f sec to save img" % (t2 - t1))
# ------------------------------------------------------------------------ # Copyright 2020-2021, Harald Lieder, mailto:[email protected] # License: GNU AFFERO GPL 3.0, https://www.gnu.org/licenses/agpl-3.0.html # # Part of "PyMuPDF", a Python binding for "MuPDF" (http://mupdf.com), a # lightweight PDF, XPS, and E-book viewer, renderer and toolkit which is # maintained and developed by Artifex Software, Inc. https://artifex.com. # ------------------------------------------------------------------------ import sys #from fitz import * import fitz from fitz_helper_defines import * # define the supported colorspaces for convenience fitz.csRGB = fitz.Colorspace(CS_RGB) fitz.csGRAY = fitz.Colorspace(CS_GRAY) fitz.csCMYK = fitz.Colorspace(CS_CMYK) fitz.csRGB = fitz.csRGB fitz.csGRAY = fitz.csGRAY fitz.csCMYK = fitz.csCMYK # create the TOOLS object #TOOLS = fitz.Tools() #fitz.TOOLS = TOOLS if fitz.VersionFitz != fitz.TOOLS.mupdf_version(): v1 = fitz.VersionFitz.split(".") v2 = fitz.TOOLS.mupdf_version().split(".") # fixme: reenable version checking. if 0 and v1[:-1] != v2[:-1]:
class Image: # Map colorspace names to their corresponding profile COLORSPACES = { 'DeviceRGB': fitz.Colorspace(fitz.CS_RGB), 'DeviceGray': fitz.Colorspace(fitz.CS_GRAY), 'DeviceCMYK': fitz.Colorspace(fitz.CS_CMYK), 'ICCBased': fitz.Colorspace(fitz.CS_RGB), } def __init__(self, page: Page, rendering: dict) -> None: self.page = page self.xref = rendering.get('xref') self.inline = rendering.get('inline') == True self.width = rendering['width'] self.height = rendering['height'] self.bpc = rendering['bpc'] self.colorspace_name = rendering.get('colorspace_name') self.bbox = fitz.Rect(rendering['bbox']) self.matrix = fitz.Matrix(rendering['transform']) # Memoized properties self._compressed_size = None # Perform necessary rotations if self.can_downsample(): # Adjust the bbox dimensions based on the page's rotation if self.page.rotation == 90: bbox = self.bbox self.bbox = fitz.Rect(bbox.y0, bbox.x0, bbox.y1, bbox.x1) # Calculate the original width / height of the image self.matrix_width = math.sqrt(self.matrix.a * self.matrix.a + self.matrix.b * self.matrix.b) or self.bbox.width self.matrix_height = math.sqrt(self.matrix.c * self.matrix.c + self.matrix.d * self.matrix.d) or self.bbox.height # If the width / height of the image don't match the rendered width / height, then # it was rotated. This is more reliable than looking at the rotation of the # Matrix itself. if (self.matrix_width > self.matrix_height and self.bbox.width < self.bbox.height) or (self.matrix_width < self.matrix_height and self.bbox.width > self.bbox.height): self.rotation = 90 else: self.rotation = 0 # If there was a rotation, then adjust the matrix and the image's dimensions so that # everything, including the bbox, is in alignment. if self.rotation == 90: self.matrix_width, self.matrix_height = self.matrix_height, self.matrix_width self.width, self.height = self.height, self.width # Can this image be downsampled? # # * Not inline # * Has a colorspace (i.e. is not a stencil) def can_downsample(self) -> bool: return not self.inline and self.xref and self.colorspace_name # The document this image belongs to @property def doc(self) -> Document: return self.page.doc # Whether pixels are interpolated when scaling up @property def interpolate(self) -> bool: return self.doc._doc.xref_get_key(self.xref, 'Interpolate') == 'true' # Image's x-resolution @property def ppi_x(self) -> int: return round(self.width * 72 / self.matrix_width) # Image's y-resolution @property def ppi_y(self) -> int: return round(self.height * 72 / self.matrix_height) # Number of components in the colorspace @property def color_components(self) -> int: # Colorspace info if self.colorspace_name in self.COLORSPACES: return self.COLORSPACES[self.colorspace_name].n else: return 1 # The actual horizontal dimensions of the image that are visible. @property def cropped_width(self) -> float: if int(self.bbox.width) > int(self.page.bbox.width): # The image is cropped -- adjust how wide it appears return round(self.width / (self.bbox.width / self.page.bbox.width)) else: return self.width # The actual vertical dimensions of the image that are visible. @property def cropped_height(self) -> float: if int(self.bbox.height) > int(self.page.bbox.height): # The image is cropped -- adjust how tall it appears return round(self.height / (self.bbox.height / self.page.bbox.height)) else: return self.height # The disk usage when compressed @property def compressed_size(self) -> int: if self._compressed_size is None: self._compressed_size = len(self.doc._doc.xref_stream_raw(self.xref)) return self._compressed_size # The disk usage when uncompressed @property def uncompressed_size(self) -> int: return self.width * self.height * self.color_components * self.bpc / 8 # The compression ratio for the image @property def compressed_ratio(self) -> float: return self.compressed_size / self.uncompressed_size # The original filter of the image @property def filter_name(self) -> str: key_type, filter_name = self.doc._doc.xref_get_key(self.xref, 'Filter') if key_type == 'array': filter_name = filter_name[1:-1].split('/')[-1] elif key_type == 'name': filter_name = filter_name[1:] else: filter_name = 'FlateDecode' return filter_name