xpra icon
Bug tracker and wiki

This bug tracker and wiki are being discontinued
please use https://github.com/Xpra-org/xpra instead.


Ticket #1230: pdfium-poc.patch

File pdfium-poc.patch, 15.1 KB (added by Antoine Martin, 5 years ago)

poc that prints a pdf file using pdfium

  • tests/xpra/pdfium/__init__.py

     
     1#!/usr/bin/env python
     2# This file is part of Xpra.
     3# Copyright (C) 2017 Antoine Martin <antoine@devloop.org.uk>
     4 No newline at end of file
  • tests/xpra/pdfium/pdfium.py

    Property changes on: tests/xpra/pdfium/__init__.py
    ___________________________________________________________________
    Added: svn:executable
    ## -0,0 +1 ##
    +*
    \ No newline at end of property
     
     1#!/usr/bin/env python
     2
     3import sys
     4
     5from tests.xpra.pdfium.print_to_hdc import hdc_print, log, error, DOCINFO, StartDocA, EndDoc, LPCSTR
     6
     7from xpra.platform.win32.common import GetDeviceCaps
     8from xpra.platform.win32 import win32con
     9from ctypes import WinDLL, c_void_p, Structure, c_int, c_uint, c_ulong, c_char_p, cast, pointer, POINTER
     10from ctypes.wintypes import HDC
     11
     12class FPDF_LIBRARY_CONFIG(Structure):
     13        _fields_ = [
     14                ("m_pUserFontPaths",    c_void_p),
     15                ("version",                             c_int),
     16                ("m_pIsolate",                  c_void_p),
     17                ("m_v8EmbedderSlot",    c_uint),
     18                ]
     19
     20FPDF_DOCUMENT = c_void_p
     21FPDF_PAGE = c_void_p
     22
     23pdfium = WinDLL('E:\\libpdfium.dll', use_last_error=True)
     24log("pdfium=%s", pdfium)
     25FPDF_DestroyLibrary = pdfium.FPDF_DestroyLibrary
     26FPDF_InitLibraryWithConfig = pdfium.FPDF_InitLibraryWithConfig
     27FPDF_InitLibraryWithConfig.argtypes = [POINTER(FPDF_LIBRARY_CONFIG)]
     28FPDF_GetLastError = pdfium.FPDF_GetLastError
     29FPDF_GetLastError.restype = c_ulong
     30FPDF_GetPageCount = pdfium.FPDF_GetPageCount
     31FPDF_GetPageCount.argtypes = [FPDF_DOCUMENT]
     32FPDF_GetPageCount.restype = c_int
     33FPDF_LoadPage = pdfium.FPDF_LoadPage
     34FPDF_LoadPage.argtypes = [FPDF_DOCUMENT, c_int]
     35FPDF_RenderPage = pdfium.FPDF_RenderPage
     36FPDF_RenderPage.argtypes = [HDC, FPDF_PAGE, c_int, c_int, c_int, c_int, c_int, c_int]
     37FPDF_LoadMemDocument = pdfium.FPDF_LoadMemDocument
     38FPDF_LoadMemDocument.restype = FPDF_DOCUMENT
     39FPDF_LoadMemDocument.argtypes = [c_void_p, c_int, c_void_p]
     40FPDF_CloseDocument = pdfium.FPDF_CloseDocument
     41FPDF_CloseDocument.argtypes = [FPDF_DOCUMENT]
     42
     43
     44FPDF_ERR_SUCCESS = 0    # No error.
     45FPDF_ERR_UNKNOWN = 1    # Unknown error.
     46FPDF_ERR_FILE = 2               # File not found or could not be opened.
     47FPDF_ERR_FORMAT = 3     # File not in PDF format or corrupted.
     48FPDF_ERR_PASSWORD = 4   # Password required or incorrect password.
     49FPDF_ERR_SECURITY = 5   # Unsupported security scheme.
     50FPDF_ERR_PAGE = 6       # Page not found or content error.
     51FPDF_ERR_XFALOAD = 7    # Load XFA error.
     52FPDF_ERR_XFALAYOUT = 8  # Layout XFA error.
     53
     54ERROR_STR = {
     55        #FPDF_ERR_SUCCESS : No error.
     56        FPDF_ERR_UNKNOWN        : "Unknown error",
     57        FPDF_ERR_FILE           : "File not found or could not be opened",
     58        FPDF_ERR_FORMAT         : "File not in PDF format or corrupted",
     59        FPDF_ERR_PASSWORD       : "Password required or incorrect password",
     60        FPDF_ERR_SECURITY       : "Unsupported security scheme",
     61        FPDF_ERR_PAGE           : "Page not found or content error",
     62        FPDF_ERR_XFALOAD        : "Load XFA error",
     63        FPDF_ERR_XFALAYOUT      : "Layout XFA error",
     64        }
     65
     66FPDF_ANNOT = 0x01
     67FPDF_LCD_TEXT = 0x02
     68FPDF_NO_NATIVETEXT = 0x04
     69FPDF_GRAYSCALE = 0x08
     70FPDF_DEBUG_INFO = 0x80
     71FPDF_NO_CATCH = 0x100
     72FPDF_RENDER_LIMITEDIMAGECACHE = 0x200
     73FPDF_RENDER_FORCEHALFTONE = 0x400
     74FPDF_PRINTING = 0x800
     75FPDF_RENDER_NO_SMOOTHTEXT = 0x1000
     76FPDF_RENDER_NO_SMOOTHIMAGE = 0x2000
     77FPDF_RENDER_NO_SMOOTHPATH = 0x4000
     78FPDF_REVERSE_BYTE_ORDER = 0x10
     79
     80def get_error():
     81        global ERROR_STR
     82        v = FPDF_GetLastError()
     83        return ERROR_STR.get(v, v)
     84
     85def print_to_hdc(hdc, title="PDF Print Test", pdf_data=None):
     86        assert pdf_data, "no pdf data"
     87        buf = c_char_p(pdf_data)
     88        log("pdf data buffer: %s", buf)
     89        log("FPDF_InitLibraryWithConfig=%s", FPDF_InitLibraryWithConfig)
     90        config = FPDF_LIBRARY_CONFIG()
     91        config.m_pUserFontPaths = None
     92        config.version = 2
     93        config.m_pIsolate = None
     94        config.m_v8EmbedderSlot = 0
     95        FPDF_InitLibraryWithConfig(config)
     96
     97        x = 0
     98        y = 0
     99        w = GetDeviceCaps(hdc, win32con.HORZRES)
     100        h = GetDeviceCaps(hdc, win32con.VERTRES)
     101        rotate = 0
     102        log("printer device size: %ix%i", w, h)
     103        flags = FPDF_PRINTING | FPDF_DEBUG_INFO
     104        try:
     105                doc = FPDF_LoadMemDocument(cast(buf, c_void_p), len(pdf_data), None)
     106                if not doc:
     107                        error("FPDF_LoadMemDocument failed, error: %s", get_error())
     108                        return 1
     109                log("FPDF_LoadMemDocument(..)=%s", doc)
     110                count = FPDF_GetPageCount(doc)
     111                log("FPDF_GetPageCount(%s)=%s", doc, count)
     112
     113                docinfo = DOCINFO()
     114                docinfo.lpszDocName = LPCSTR("%s\0" % title)
     115                r = StartDocA(hdc, pointer(docinfo))
     116                if r<0:
     117                        log("StartDocA failed: %i", r)
     118                        return r
     119                log("StartDocA()=%i" % r)
     120
     121                try:
     122                        for i in range(count):
     123                                page = FPDF_LoadPage(doc, i)
     124                                if not page:
     125                                        log("FPDF_LoadPage failed for page %i, error: %s", i, get_error())
     126                                        return 1
     127                                log("FPDF_LoadPage()=%s page %i loaded", page, i)
     128                                FPDF_RenderPage(hdc, page, x, y, w, h, rotate, flags)
     129                                log("FPDF_RenderPage page %i rendered", i)
     130                finally:
     131                        EndDoc(hdc)
     132        finally:
     133                FPDF_DestroyLibrary()
     134        return 0
     135
     136
     137def main():
     138        if len(sys.argv)!=2:
     139                print("usage: %s /path/to/document.pdf" % sys.argv[0])
     140                return 1
     141        with open(sys.argv[1], 'rb') as f:
     142                pdf_data = f.read()
     143
     144        def print_cb(hdc):
     145                print_to_hdc(hdc, pdf_data=pdf_data)
     146        hdc_print(print_cb)
     147
     148if __name__ == "__main__":
     149        sys.exit(main())
  • tests/xpra/pdfium/print_to_hdc.py

    Property changes on: tests/xpra/pdfium/pdfium.py
    ___________________________________________________________________
    Added: svn:executable
    ## -0,0 +1 ##
    +*
    \ No newline at end of property
     
     1#!/usr/bin/env python
     2
     3import sys
     4
     5from xpra.platform.win32.common import CreateDCA, gdi32
     6from xpra.platform.win32.printing import get_printers
     7
     8from ctypes import cdll, WinDLL, c_void_p, Structure, cast, c_char, c_int, pointer
     9from ctypes.wintypes import POINTER, HDC
     10from ctypes.wintypes import HANDLE, BOOL, BYTE, LPCSTR, DWORD, WORD
     11CHAR = BYTE
     12LPHANDLE = PHANDLE = POINTER(HANDLE)
     13LPBYTE = POINTER(BYTE)
     14LPDWORD = POINTER(DWORD)
     15LPPRINTER_DEFAULTS = c_void_p
     16PSECURITY_DESCRIPTOR = HANDLE
     17
     18msvcrt = cdll.msvcrt
     19winspool = WinDLL('winspool.drv', use_last_error=True)
     20OpenPrinterA = winspool.OpenPrinterA
     21OpenPrinterA.restype = BOOL
     22ClosePrinter = winspool.ClosePrinter
     23ClosePrinter.restype = BOOL
     24ClosePrinter.argtypes = [HANDLE]
     25OpenPrinterA.argtypes = [LPCSTR, LPHANDLE, LPPRINTER_DEFAULTS]
     26GetPrinterA = winspool.GetPrinterA
     27GetPrinterA.restype = BOOL
     28GetPrinterA.argtypes = [HANDLE, DWORD, c_void_p, DWORD, LPDWORD]
     29
     30class DOCINFO(Structure):
     31        _fields_ = [
     32                ("cbSize",              c_int),
     33                ("lpszDocName", LPCSTR),
     34                ("lpszOutput",  LPCSTR),
     35                ("lpszDatatype",LPCSTR),
     36                ("fwType",              DWORD),
     37                ]
     38
     39LPDOCINFO = POINTER(DOCINFO)
     40StartDocA = gdi32.StartDocA
     41StartDocA.argtypes = [HDC, LPDOCINFO]
     42EndDoc = gdi32.EndDoc
     43EndDoc.argtypes = [HDC]
     44EndDoc.restype = int
     45StartPage = gdi32.StartPage
     46StartPage.argtypes = [HDC]
     47EndPage = gdi32.EndPage
     48EndPage.argtypes = [HDC]
     49TextOutA = gdi32.TextOutA
     50TextOutA.restype = BOOL
     51TextOutA.argtypes = [HDC, c_int, c_int, LPCSTR, c_int]
     52
     53CCHDEVICENAME = 32
     54
     55class DEVMODE(Structure):
     56        _fields_ = [
     57                ("dmDeviceName",        c_char*CCHDEVICENAME),
     58                ("dmSpecVersion",       WORD),
     59                ("dmDriverVersion",     WORD),
     60                ("dmSize",                      WORD),
     61                ("dmDriverExtra",       WORD),
     62                ("dmFields",            DWORD),
     63                ]
     64LPDEVMODE = POINTER(DEVMODE)
     65
     66class PRINTER_INFO_1(Structure):
     67        _fields_ = [
     68                ("Flags",                       DWORD),
     69                ("pDescription",        LPCSTR),
     70                ("pName",                       LPCSTR),
     71                ("pComment",            LPCSTR),
     72                ]
     73
     74class PRINTER_INFO_2(Structure):
     75        _fields_ = [
     76                ("pServerName",                 LPCSTR),
     77                ("pPrinterName",                LPCSTR),
     78                ("pShareName",                  LPCSTR),
     79                ("pPortName",                   LPCSTR),
     80                ("pDriverName",                 LPCSTR),
     81                ("pComment",                    LPCSTR),
     82                ("pLocation",                   LPCSTR),
     83                ("pDevMode",                    LPDEVMODE),
     84                ("pSepFile",                    LPCSTR),
     85                ("pPrintProcessor",             LPCSTR),
     86                ("pDatatype",                   LPCSTR),
     87                ("pParameters",                 LPCSTR),
     88                ("pSecurityDescriptor", PSECURITY_DESCRIPTOR),
     89                ("Attributes",                  DWORD),
     90                ("Priority",                    DWORD),
     91                ("DefaultPriority",             DWORD),
     92                ("StartTime",                   DWORD),
     93                ("UntilTime",                   DWORD),
     94                ("Status",                              DWORD),
     95                ("cJobs",                               DWORD),
     96                ("AveragePPM",                  DWORD),
     97                ]
     98
     99class PRINTER_INFO_8(Structure):
     100        _fields_ = [
     101                ("pDevMode",                    LPDEVMODE),
     102                ]
     103PRINTER_INFO_9 = PRINTER_INFO_8
     104
     105
     106def log(msg, *args):
     107        sys.stdout.write(msg % args)
     108        sys.stdout.write("\n")
     109        sys.stdout.flush()
     110
     111def error(msg, *args):
     112        print(("Error: "+msg) % args)
     113
     114
     115def print_document(hdc, title="Test", print_doc_fn=None):
     116        docinfo = DOCINFO()
     117        docinfo.lpszDocName = LPCSTR("%s\0" % title)
     118        r = StartDocA(hdc, pointer(docinfo))
     119        if r<0:
     120                log("StartDocA failed: %i", r)
     121                return r
     122        log("StartDocA()=%i" % r)
     123
     124        r = StartPage(hdc)
     125        if r<0:
     126                log("StartPage failed: %i", r)
     127                return r
     128
     129        if print_doc_fn:
     130                r = print_doc_fn(hdc)
     131                if r!=0:
     132                        return r
     133
     134        r = EndPage(hdc)
     135        if r<0:
     136                log("EndPage failed: %i", r)
     137                return r
     138
     139        r = EndDoc(hdc)
     140        if r<0:
     141                log("EndDoc failed: %i" % r)
     142                return r
     143        log("EndDoc()=%i" % r)
     144        return 0
     145
     146def print_to_hdc(hdc):
     147        def print_doc_fn(hdc):
     148                x = 100
     149                y = 100
     150                import datetime
     151                s = "test: %s" % (datetime.datetime.now())
     152                if not TextOutA(hdc, x, y, LPCSTR(s), len(s)):
     153                        log("TextOutA failed")
     154                        return 1
     155                return 0
     156        return print_document(hdc, print_doc_fn=print_doc_fn)
     157
     158
     159def hdc_print(print_fn):
     160        printers = get_printers()
     161        log("printers: %s", printers)
     162        name = LPCSTR(printers.keys()[0])
     163        handle = HANDLE()
     164        if not OpenPrinterA(name, pointer(handle), None):
     165                error("failed to open printer %s" % name)
     166                return 1
     167        try:
     168                log("OpenPrinter: handle=%#x" % handle.value)
     169                size = DWORD()
     170                GetPrinterA(handle, 1, None, 0, pointer(size))
     171                log("GetPrinter: PRINTER_INFO_1 size=%i" % size.value)
     172                buf = msvcrt.malloc(size.value)
     173                if not GetPrinterA(handle, 1, buf, size.value, pointer(size)):
     174                        error("GetPrinterA failed for %s", name)
     175                        return 1
     176                info = cast(buf, POINTER(PRINTER_INFO_1))
     177                log(" flags=%#x" % info[0].Flags)
     178                log(" name=%#s" % info[0].pName)
     179                log(" description=%s" % info[0].pDescription)
     180                log(" comment=%s" % info[0].pComment)
     181                msvcrt.free(buf)
     182       
     183                GetPrinterA(handle, 2, None, 0, pointer(size))
     184                log("GetPrinter: PRINTER_INFO_2 size=%i" % size.value)
     185                buf = msvcrt.malloc(size.value)
     186                if GetPrinterA(handle, 2, buf, size.value, pointer(size)):
     187                        info = cast(buf, POINTER(PRINTER_INFO_2))
     188                        log(" driver=%#s" % info[0].pDriverName)
     189                msvcrt.free(buf)
     190       
     191                GetPrinterA(handle, 8, None, 0, pointer(size))
     192                log("GetPrinter: PRINTER_INFO_8 size=%i" % size.value)
     193                info8 = msvcrt.malloc(size.value)
     194                devmode = None
     195                try:
     196                        if GetPrinterA(handle, 8, buf, size.value, pointer(size)):
     197                                info = cast(buf, POINTER(PRINTER_INFO_8))
     198                                devmode = cast(info[0].pDevMode, POINTER(DEVMODE))
     199                                log("devmode=%s" % devmode)
     200                                log("device name=%s" % devmode[0].dmDeviceName)
     201       
     202                        GetPrinterA(handle, 9, None, 0, pointer(size))
     203                        log("GetPrinter: PRINTER_INFO_9 size=%i" % size.value)
     204                        info9 = msvcrt.malloc(size.value)
     205                        if GetPrinterA(handle, 9, buf, size.value, pointer(size)):
     206                                info = cast(buf, POINTER(PRINTER_INFO_9))
     207                                if info[0].pDevMode:
     208                                        devmode = cast(info[0].pDevMode, POINTER(DEVMODE))
     209                                        log("devmode=%s" % devmode)
     210                                        log("device name=%s" % devmode[0].dmDeviceName)
     211                        assert devmode
     212       
     213                        hdc = CreateDCA(None, name, None, devmode)
     214                        log("CreateDCA()=%#x" % hdc)
     215
     216                        return print_fn(hdc)
     217                finally:
     218                        msvcrt.free(info8)
     219                        msvcrt.free(info9)
     220        finally:
     221                ClosePrinter(handle)
     222        return 0
     223
     224
     225def main():
     226        return hdc_print(print_to_hdc)
     227
     228
     229if __name__ == "__main__":
     230        sys.exit(main())
  • xpra/platform/win32/common.py

    Property changes on: tests/xpra/pdfium/print_to_hdc.py
    ___________________________________________________________________
    Added: svn:executable
    ## -0,0 +1 ##
    +*
    \ No newline at end of property
     
    66
    77import ctypes
    88
    9 from ctypes import WinDLL, Structure, c_ulong, c_ushort, c_ubyte, c_int, c_long
     9from ctypes import WinDLL, Structure, c_ulong, c_ushort, c_ubyte, c_int, c_long, c_void_p
    1010from ctypes.wintypes import HWND, DWORD, WPARAM, LPARAM, HDC, HMONITOR, HMODULE, SHORT, ATOM, POINTER, RECT
    11 from ctypes.wintypes import HANDLE, LPCWSTR, UINT, INT, WINFUNCTYPE, BOOL, HGDIOBJ, LONG, LPVOID, HBITMAP
     11from ctypes.wintypes import HANDLE, LPCWSTR, UINT, INT, WINFUNCTYPE, BOOL, HGDIOBJ, LONG, LPVOID, HBITMAP, LPCSTR
    1212LRESULT = c_long
     13DEVMODE = c_void_p
    1314
    1415kernel32 = WinDLL("kernel32", use_last_error=True)
    1516SetConsoleTitleA = kernel32.SetConsoleTitleA
     
    119120DeleteDC = gdi32.DeleteDC
    120121DeleteDC.restype = BOOL
    121122DeleteDC.argtypes = [HDC]
     123CreateDCA = gdi32.CreateDCA
     124CreateDCA.restype = HDC
     125CreateDCA.argtypes = [LPCSTR, LPCSTR, LPCSTR, DEVMODE]
    122126
    123 
    124127#wrap EnumDisplayMonitors to hide the callback function:
    125128MonitorEnumProc = ctypes.WINFUNCTYPE(BOOL, HMONITOR, HDC, POINTER(RECT), LPARAM)
    126129_EnumDisplayMonitors = EnumDisplayMonitors
  • xpra/platform/win32/printing.py

     
    163163def get_printers():
    164164    global PRINTER_ENUMS, PRINTER_ENUM_VALUES, SKIPPED_PRINTERS, PRINTER_LEVEL, GSVIEW_DIR
    165165    printers = {}
    166     if not GSVIEW_DIR:
    167         #without gsprint, we can't handle printing!
    168         log("get_printers() gsview is missing, not querying any printers")
    169         return printers
     166    #if not GSVIEW_DIR:
     167    #    #without gsprint, we can't handle printing!
     168    #    log("get_printers() gsview is missing, not querying any printers")
     169    #    return printers
    170170    #default_printer = GetDefaultPrinter()
    171171    for penum in PRINTER_ENUMS:
    172172        try:
     
    179179            for p in EnumPrinters(enum_val, None, PRINTER_LEVEL):
    180180                flags, desc, name, comment = p
    181181                if name in SKIPPED_PRINTERS:
    182                     log("skipped printer: %s, %s, %s, %s", flags, desc, name, comment)
     182                    log("skipped printer: %#x, %s, %s, %s", flags, desc, name, comment)
    183183                    continue
    184184                if name in printers:
    185                     log("skipped duplicate printer: %s, %s, %s, %s", flags, desc, name, comment)
     185                    log("skipped duplicate printer: %#x, %s, %s, %s", flags, desc, name, comment)
    186186                    continue
    187                 log("found printer: %s, %s, %s, %s", flags, desc, name, comment)
     187                log("found printer: %#x, %s, %s, %s", flags, desc, name, comment)
    188188                #strip duplicated and empty strings from the description:
    189189                desc_els = []
    190190                [desc_els.append(x) for x in desc.split(",") if (x and not desc_els.count(x))]