Example #1
0
def get_pdf_gpts(m, poly):
    """
    Returns the GPTS array object containing the four corners of the
    map rect in map projection.
    The GPTS entry is an array of numbers, taken pairwise, defining
    points as latitude and longitude.
    m = mapnik map object
    poly = tuple of (x,y) tuples describing rect polygon - allows geocoding of rotated maps.
    """
    gpts = ArrayObject()

    proj = mapnik.Projection(m.srs)
    for x, y in poly:
        latlon_corner = proj.inverse(mapnik.Coord(x, y))
        # these are in lat,lon order according to the specification
        gpts.append(FloatObject(str(latlon_corner.y)))
        gpts.append(FloatObject(str(latlon_corner.x)))

    return gpts
Example #2
0
def get_pdf_measure(m, gcs, poly, bounds_default):
    """
    Returns the PDF Measure dictionary.
    The Measure dictionary is used in the viewport array
    and specifies the scale and units that apply to the output map.
    """
    measure = DictionaryObject()
    measure[NameObject('/Type')] = NameObject('/Measure')
    measure[NameObject('/Subtype')] = NameObject('/GEO')
    bounds = ArrayObject()
    """
    Returns the PDF BOUNDS array.
    The PDF's bounds array is equivalent to the map's neatline, i.e.,
    the border delineating the extent of geographic data on the output map.
    """
    for x in [0, 1, 0, 0, 1, 0, 1, 1]:
        bounds.append(FloatObject(str(x)))

    measure[NameObject('/Bounds')] = bounds
    measure[NameObject('/GPTS')] = get_pdf_gpts(m, poly)
    measure[NameObject('/LPTS')] = bounds
    measure[NameObject('/GCS')] = gcs
    return measure
Example #3
0
def merge_page(pdf,
               page_number: int,
               page2,
               page2transformation=None,
               ctm=None,
               expand=False):
    """
    Merge the given page number of the given PDF with another page.

    Note that the first PDF is assumed to be immutable, and its parsed content stream will
    be cached *indefinitely* to ensure that future renders are extremely fast (at least,
    as long as the other page, which we never cache, is relatively simple).

    Note that most of this code was taken from `PyPDF2.pdf.PageObject`'s
    `mergePage()` implementation.
    """

    # First we work on merging the resource dictionaries.  This allows us
    # to find out what symbols in the content streams we might need to
    # rename.

    page1 = pdf.getPage(page_number)
    newResources = DictionaryObject()
    rename = {}
    originalResources = page1["/Resources"].getObject()
    page2Resources = page2["/Resources"].getObject()
    newAnnots = ArrayObject()

    for page in (page1, page2):
        if "/Annots" in page:
            annots = page["/Annots"]
            if isinstance(annots, ArrayObject):
                for ref in annots:
                    newAnnots.append(ref)

    for res in (
            "/ExtGState",
            "/Font",
            "/XObject",
            "/ColorSpace",
            "/Pattern",
            "/Shading",
            "/Properties",
    ):
        new, newrename = PageObject._mergeResources(originalResources,
                                                    page2Resources, res)
        if new:
            newResources[NameObject(res)] = new
            rename.update(newrename)

    # Combine /ProcSet sets.
    newResources[NameObject("/ProcSet")] = ArrayObject(
        frozenset(
            originalResources.get("/ProcSet",
                                  ArrayObject()).getObject()).union(
                                      frozenset(
                                          page2Resources.get(
                                              "/ProcSet",
                                              ArrayObject()).getObject())))

    content_stream = get_cached_content_stream(pdf, page_number)

    page2Content = page2.getContents()
    if page2Content is not None:
        if page2transformation is not None:
            page2Content = page2transformation(page2Content)
        page2Content = PageObject._contentStreamRename(page2Content, rename,
                                                       page1.pdf)
        page2Content = PageObject._pushPopGS(page2Content, page1.pdf)
        content_stream = append_to_content_stream(content_stream, page2Content)

    # if expanding the page to fit a new page, calculate the new media box size
    if expand:
        corners1 = [
            page1.mediaBox.getLowerLeft_x().as_numeric(),
            page1.mediaBox.getLowerLeft_y().as_numeric(),
            page1.mediaBox.getUpperRight_x().as_numeric(),
            page1.mediaBox.getUpperRight_y().as_numeric(),
        ]
        corners2 = [
            page2.mediaBox.getLowerLeft_x().as_numeric(),
            page2.mediaBox.getLowerLeft_y().as_numeric(),
            page2.mediaBox.getUpperLeft_x().as_numeric(),
            page2.mediaBox.getUpperLeft_y().as_numeric(),
            page2.mediaBox.getUpperRight_x().as_numeric(),
            page2.mediaBox.getUpperRight_y().as_numeric(),
            page2.mediaBox.getLowerRight_x().as_numeric(),
            page2.mediaBox.getLowerRight_y().as_numeric(),
        ]
        if ctm is not None:
            ctm = [float(x) for x in ctm]
            new_x = [
                ctm[0] * corners2[i] + ctm[2] * corners2[i + 1] + ctm[4]
                for i in range(0, 8, 2)
            ]
            new_y = [
                ctm[1] * corners2[i] + ctm[3] * corners2[i + 1] + ctm[5]
                for i in range(0, 8, 2)
            ]
        else:
            new_x = corners2[0:8:2]
            new_y = corners2[1:8:2]
        lowerleft = [min(new_x), min(new_y)]
        upperright = [max(new_x), max(new_y)]
        lowerleft = [
            min(corners1[0], lowerleft[0]),
            min(corners1[1], lowerleft[1])
        ]
        upperright = [
            max(corners1[2], upperright[0]),
            max(corners1[3], upperright[1])
        ]

        page1.mediaBox.setLowerLeft(lowerleft)
        page1.mediaBox.setUpperRight(upperright)

    new_page = PageObject.createBlankPage(page1.pdf)

    new_page[NameObject("/Contents")] = content_stream
    new_page[NameObject("/Resources")] = newResources
    new_page[NameObject("/Annots")] = newAnnots

    return new_page
Example #4
0
def add_geospatial_pdf_header(m, f, f2, map_bounds, poly, epsg=None, wkt=None):
    """
        Adds geospatial PDF information to the PDF file as per:
            AdobeĀ® Supplement to the ISO 32000 PDF specification
            BaseVersion: 1.7
            ExtensionLevel: 3
            (June 2008)
        Notes:
            The epsg code or the wkt text of the projection must be provided.
            Must be called *after* the page has had .finish() called.
        """
    if not HAS_PYPDF2:
        raise RuntimeError(
            "PyPDF2 not available; PyPDF2 required to add geospatial header to PDF"
        )

    if not any((epsg, wkt)):
        raise RuntimeError(
            "EPSG or WKT required to add geospatial header to PDF")

    file_reader = PdfFileReader(f)
    file_writer = PdfFileWriter()

    # preserve OCProperties at document root if we have one
    if NameObject('/OCProperties'
                  ) in file_reader.trailer['/Root']:  #Python3-friendly
        file_writer._root_object[NameObject(
            '/OCProperties')] = file_reader.trailer['/Root'].getObject()[
                NameObject('/OCProperties')]

    for page in file_reader.pages:
        gcs = DictionaryObject()
        gcs[NameObject('/Type')] = NameObject('/PROJCS')

        if epsg:
            gcs[NameObject('/EPSG')] = NumberObject(int(epsg))
        if wkt:
            gcs[NameObject('/WKT')] = TextStringObject(wkt)

        measure = get_pdf_measure(m, gcs, poly, map_bounds)
        """
            Returns the PDF's VP array.
            The VP entry is an array of viewport dictionaries. A viewport is basiscally
            a rectangular region on the PDF page. The only required entry is the BBox which
            specifies the location of the viewport on the page.
            """
        viewport = DictionaryObject()
        viewport[NameObject('/Type')] = NameObject('/Viewport')

        bbox = ArrayObject()
        for x in (0, int(page.mediaBox[3]), int(page.mediaBox[2]), 0):  #in pts
            bbox.append(FloatObject(str(x)))  #Fixed

        viewport[NameObject('/BBox')] = bbox
        #viewport[NameObject('/Name')] = TextStringObject('OOMAP')
        viewport[NameObject('/Measure')] = measure

        vp_array = ArrayObject()
        vp_array.append(viewport)
        page[NameObject('/VP')] = vp_array
        file_writer.addPage(page)

    file_writer.write(f2)
    return (f2)
Example #5
0
def make_content_stream(pdf, content) -> ContentStream:
    arr = ArrayObject()
    arr.append(content)
    return ContentStream(arr, pdf)