src/reportlab/pdfbase/pdfutils.py
author robin <robin@reportlab.com>
Tue, 07 Mar 2017 10:00:34 +0000
changeset 4330 617ffa6bbdc8
parent 4302 f3ff56a22b2e
child 4370 823a8c33ce43
permissions -rwxr-xr-x
changes for release 3.4.0
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
4330
617ffa6bbdc8 changes for release 3.4.0
robin <robin@reportlab.com>
parents: 4302
diff changeset
     1
#Copyright ReportLab Europe Ltd. 2000-2017
494
54257447cfe9 Changed to indirect copyright
rgbecker
parents: 475
diff changeset
     2
#see license.txt for license details
2332
2a7ab4405e18 Remove $Header:, fix CopyRight & history
rgbecker
parents: 2273
diff changeset
     3
#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/pdfbase/pdfutils.py
4252
fe660f227cac changes for release 3.3.0
robin
parents: 4219
diff changeset
     4
__version__='3.3.0'
16
f9c7525619fb Docstring & other fixes
rgbecker
parents: 7
diff changeset
     5
__doc__=''
0
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
     6
# pdfutils.py - everything to do with images, streams,
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
     7
# compression, and some constants
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
     8
3723
99aa837b6703 second stage of port to Python 3.3; working hello world
rptlab
parents: 3721
diff changeset
     9
import sys
0
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
    10
import os
3723
99aa837b6703 second stage of port to Python 3.3; working hello world
rptlab
parents: 3721
diff changeset
    11
import binascii
1029
6bd2c408f7a1 Use rl_config.verbose
rgbecker
parents: 760
diff changeset
    12
from reportlab import rl_config
3835
8e35c471e0ee various: attempt to be more consistent about isStr
robin
parents: 3800
diff changeset
    13
from reportlab.lib.utils import getBytesIO, ImageReader, isUnicode, isPy3
4028
e58c01f26693 pdfutils.py: import from rl_accel not _rl_accel
robin
parents: 3975
diff changeset
    14
from reportlab.lib.rl_accel import asciiBase85Encode, asciiBase85Decode
0
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
    15
2229
99cb312c5269 Fix transparency & jpeg behaviour
rgbecker
parents: 2200
diff changeset
    16
def _chunker(src,dst=[],chunkSize=60):
3721
0c93dd8ff567 initial changes from 2to3-3.3
rptlab
parents: 3617
diff changeset
    17
    for i in range(0,len(src),chunkSize):
2229
99cb312c5269 Fix transparency & jpeg behaviour
rgbecker
parents: 2200
diff changeset
    18
        dst.append(src[i:i+chunkSize])
99cb312c5269 Fix transparency & jpeg behaviour
rgbecker
parents: 2200
diff changeset
    19
    return dst
99cb312c5269 Fix transparency & jpeg behaviour
rgbecker
parents: 2200
diff changeset
    20
0
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
    21
##########################################################
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
    22
#
567
0c7064b86e9e Modified docstrings.
dinu_gherman
parents: 494
diff changeset
    23
#  Image compression helpers.  Preprocessing a directory
0
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
    24
#  of images will offer a vast speedup.
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
    25
#
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
    26
##########################################################
2482
4ae04d1800af CMYK image improvements
rgbecker
parents: 2399
diff changeset
    27
_mode2cs = {'RGB':'RGB', 'CMYK': 'CMYK', 'L': 'G'}
2994
130866f26cb4 reportlab: fix some broken assertions
rgbecker
parents: 2964
diff changeset
    28
_mode2bpp = {'RGB': 3, 'CMYK':4, 'L':1}
4219
e42c9f82f08d improve jpeg detection; version-->3.2.6
robin
parents: 4028
diff changeset
    29
def makeA85Image(filename,IMG=None, detectJpeg=False):
2558
97ae9d8242cd pdfgen: fix badly drawn jpegs which are actually gifs
rgbecker
parents: 2482
diff changeset
    30
    import zlib
97ae9d8242cd pdfgen: fix badly drawn jpegs which are actually gifs
rgbecker
parents: 2482
diff changeset
    31
    img = ImageReader(filename)
4219
e42c9f82f08d improve jpeg detection; version-->3.2.6
robin
parents: 4028
diff changeset
    32
    if IMG is not None:
e42c9f82f08d improve jpeg detection; version-->3.2.6
robin
parents: 4028
diff changeset
    33
        IMG.append(img)
e42c9f82f08d improve jpeg detection; version-->3.2.6
robin
parents: 4028
diff changeset
    34
        if detectJpeg and img.jpeg_fh():
e42c9f82f08d improve jpeg detection; version-->3.2.6
robin
parents: 4028
diff changeset
    35
            return None
2558
97ae9d8242cd pdfgen: fix badly drawn jpegs which are actually gifs
rgbecker
parents: 2482
diff changeset
    36
97ae9d8242cd pdfgen: fix badly drawn jpegs which are actually gifs
rgbecker
parents: 2482
diff changeset
    37
    imgwidth, imgheight = img.getSize()
97ae9d8242cd pdfgen: fix badly drawn jpegs which are actually gifs
rgbecker
parents: 2482
diff changeset
    38
    raw = img.getRGBData()
97ae9d8242cd pdfgen: fix badly drawn jpegs which are actually gifs
rgbecker
parents: 2482
diff changeset
    39
97ae9d8242cd pdfgen: fix badly drawn jpegs which are actually gifs
rgbecker
parents: 2482
diff changeset
    40
    code = []
97ae9d8242cd pdfgen: fix badly drawn jpegs which are actually gifs
rgbecker
parents: 2482
diff changeset
    41
    append = code.append
97ae9d8242cd pdfgen: fix badly drawn jpegs which are actually gifs
rgbecker
parents: 2482
diff changeset
    42
    # this describes what is in the image itself
97ae9d8242cd pdfgen: fix badly drawn jpegs which are actually gifs
rgbecker
parents: 2482
diff changeset
    43
    append('BI')
97ae9d8242cd pdfgen: fix badly drawn jpegs which are actually gifs
rgbecker
parents: 2482
diff changeset
    44
    append('/W %s /H %s /BPC 8 /CS /%s /F [/A85 /Fl]' % (imgwidth, imgheight,_mode2cs[img.mode]))
97ae9d8242cd pdfgen: fix badly drawn jpegs which are actually gifs
rgbecker
parents: 2482
diff changeset
    45
    append('ID')
97ae9d8242cd pdfgen: fix badly drawn jpegs which are actually gifs
rgbecker
parents: 2482
diff changeset
    46
    #use a flate filter and Ascii Base 85
2994
130866f26cb4 reportlab: fix some broken assertions
rgbecker
parents: 2964
diff changeset
    47
    assert len(raw) == imgwidth * imgheight*_mode2bpp[img.mode], "Wrong amount of data for image"
2558
97ae9d8242cd pdfgen: fix badly drawn jpegs which are actually gifs
rgbecker
parents: 2482
diff changeset
    48
    compressed = zlib.compress(raw)   #this bit is very fast...
3781
df8b57380768 import from reportlab.lib.lib.rl_accel
robin
parents: 3765
diff changeset
    49
    encoded = asciiBase85Encode(compressed) #...sadly this may not be
2558
97ae9d8242cd pdfgen: fix badly drawn jpegs which are actually gifs
rgbecker
parents: 2482
diff changeset
    50
97ae9d8242cd pdfgen: fix badly drawn jpegs which are actually gifs
rgbecker
parents: 2482
diff changeset
    51
    #append in blocks of 60 characters
97ae9d8242cd pdfgen: fix badly drawn jpegs which are actually gifs
rgbecker
parents: 2482
diff changeset
    52
    _chunker(encoded,code)
97ae9d8242cd pdfgen: fix badly drawn jpegs which are actually gifs
rgbecker
parents: 2482
diff changeset
    53
97ae9d8242cd pdfgen: fix badly drawn jpegs which are actually gifs
rgbecker
parents: 2482
diff changeset
    54
    append('EI')
97ae9d8242cd pdfgen: fix badly drawn jpegs which are actually gifs
rgbecker
parents: 2482
diff changeset
    55
    return code
4219
e42c9f82f08d improve jpeg detection; version-->3.2.6
robin
parents: 4028
diff changeset
    56
def makeRawImage(filename,IMG=None,detectJpeg=False):
3359
171fa15695a8 reportlab: optional A85 patch contributed by Yoann Roman
rgbecker
parents: 3326
diff changeset
    57
    import zlib
171fa15695a8 reportlab: optional A85 patch contributed by Yoann Roman
rgbecker
parents: 3326
diff changeset
    58
    img = ImageReader(filename)
4219
e42c9f82f08d improve jpeg detection; version-->3.2.6
robin
parents: 4028
diff changeset
    59
    if IMG is not None:
e42c9f82f08d improve jpeg detection; version-->3.2.6
robin
parents: 4028
diff changeset
    60
        IMG.append(img)
e42c9f82f08d improve jpeg detection; version-->3.2.6
robin
parents: 4028
diff changeset
    61
        if detectJpeg and img.jpeg_fh():
e42c9f82f08d improve jpeg detection; version-->3.2.6
robin
parents: 4028
diff changeset
    62
            return None
3359
171fa15695a8 reportlab: optional A85 patch contributed by Yoann Roman
rgbecker
parents: 3326
diff changeset
    63
171fa15695a8 reportlab: optional A85 patch contributed by Yoann Roman
rgbecker
parents: 3326
diff changeset
    64
    imgwidth, imgheight = img.getSize()
171fa15695a8 reportlab: optional A85 patch contributed by Yoann Roman
rgbecker
parents: 3326
diff changeset
    65
    raw = img.getRGBData()
171fa15695a8 reportlab: optional A85 patch contributed by Yoann Roman
rgbecker
parents: 3326
diff changeset
    66
171fa15695a8 reportlab: optional A85 patch contributed by Yoann Roman
rgbecker
parents: 3326
diff changeset
    67
    code = []
171fa15695a8 reportlab: optional A85 patch contributed by Yoann Roman
rgbecker
parents: 3326
diff changeset
    68
    append = code.append
171fa15695a8 reportlab: optional A85 patch contributed by Yoann Roman
rgbecker
parents: 3326
diff changeset
    69
    # this describes what is in the image itself
171fa15695a8 reportlab: optional A85 patch contributed by Yoann Roman
rgbecker
parents: 3326
diff changeset
    70
    append('BI')
171fa15695a8 reportlab: optional A85 patch contributed by Yoann Roman
rgbecker
parents: 3326
diff changeset
    71
    append('/W %s /H %s /BPC 8 /CS /%s /F [/Fl]' % (imgwidth, imgheight,_mode2cs[img.mode]))
171fa15695a8 reportlab: optional A85 patch contributed by Yoann Roman
rgbecker
parents: 3326
diff changeset
    72
    append('ID')
171fa15695a8 reportlab: optional A85 patch contributed by Yoann Roman
rgbecker
parents: 3326
diff changeset
    73
    #use a flate filter
171fa15695a8 reportlab: optional A85 patch contributed by Yoann Roman
rgbecker
parents: 3326
diff changeset
    74
    assert len(raw) == imgwidth * imgheight*_mode2bpp[img.mode], "Wrong amount of data for image"
171fa15695a8 reportlab: optional A85 patch contributed by Yoann Roman
rgbecker
parents: 3326
diff changeset
    75
    compressed = zlib.compress(raw)   #this bit is very fast...
171fa15695a8 reportlab: optional A85 patch contributed by Yoann Roman
rgbecker
parents: 3326
diff changeset
    76
171fa15695a8 reportlab: optional A85 patch contributed by Yoann Roman
rgbecker
parents: 3326
diff changeset
    77
    #append in blocks of 60 characters
171fa15695a8 reportlab: optional A85 patch contributed by Yoann Roman
rgbecker
parents: 3326
diff changeset
    78
    _chunker(compressed,code)
171fa15695a8 reportlab: optional A85 patch contributed by Yoann Roman
rgbecker
parents: 3326
diff changeset
    79
171fa15695a8 reportlab: optional A85 patch contributed by Yoann Roman
rgbecker
parents: 3326
diff changeset
    80
    append('EI')
171fa15695a8 reportlab: optional A85 patch contributed by Yoann Roman
rgbecker
parents: 3326
diff changeset
    81
    return code
2558
97ae9d8242cd pdfgen: fix badly drawn jpegs which are actually gifs
rgbecker
parents: 2482
diff changeset
    82
1772
ba6ba46e2370 Added A85 caching possibility to Image XObjects
rgbecker
parents: 1683
diff changeset
    83
def cacheImageFile(filename, returnInMemory=0, IMG=None):
567
0c7064b86e9e Modified docstrings.
dinu_gherman
parents: 494
diff changeset
    84
    "Processes image as if for encoding, saves to a file with .a85 extension."
660
243182bf7988 Removed commented encoding test functions.
dinu_gherman
parents: 658
diff changeset
    85
3359
171fa15695a8 reportlab: optional A85 patch contributed by Yoann Roman
rgbecker
parents: 3326
diff changeset
    86
    cachedname = os.path.splitext(filename)[0] + (rl_config.useA85 and '.a85' or '.bin')
1368
3d1d1f4f87cb Fixed silly case of caching .a85 when it exists
rgbecker
parents: 1219
diff changeset
    87
    if filename==cachedname:
3d1d1f4f87cb Fixed silly case of caching .a85 when it exists
rgbecker
parents: 1219
diff changeset
    88
        if cachedImageExists(filename):
2558
97ae9d8242cd pdfgen: fix badly drawn jpegs which are actually gifs
rgbecker
parents: 2482
diff changeset
    89
            from reportlab.lib.utils import open_for_read
3843
ee97902ffa44 pdfdoc.py, pdfform.py & pdfutils.py: eliminate LINEEND
robin
parents: 3835
diff changeset
    90
            if returnInMemory: return filter(None,open_for_read(cachedname).read().split('\r\n'))
1368
3d1d1f4f87cb Fixed silly case of caching .a85 when it exists
rgbecker
parents: 1219
diff changeset
    91
        else:
3721
0c93dd8ff567 initial changes from 2to3-3.3
rptlab
parents: 3617
diff changeset
    92
            raise IOError('No such cached image %s' % filename)
1368
3d1d1f4f87cb Fixed silly case of caching .a85 when it exists
rgbecker
parents: 1219
diff changeset
    93
    else:
3359
171fa15695a8 reportlab: optional A85 patch contributed by Yoann Roman
rgbecker
parents: 3326
diff changeset
    94
        if rl_config.useA85:
171fa15695a8 reportlab: optional A85 patch contributed by Yoann Roman
rgbecker
parents: 3326
diff changeset
    95
            code = makeA85Image(filename,IMG)
171fa15695a8 reportlab: optional A85 patch contributed by Yoann Roman
rgbecker
parents: 3326
diff changeset
    96
        else:
171fa15695a8 reportlab: optional A85 patch contributed by Yoann Roman
rgbecker
parents: 3326
diff changeset
    97
            code = makeRawImage(filename,IMG)
1368
3d1d1f4f87cb Fixed silly case of caching .a85 when it exists
rgbecker
parents: 1219
diff changeset
    98
        if returnInMemory: return code
760
0e51a12a0e39 Changed to PIL_Image
rgbecker
parents: 677
diff changeset
    99
1368
3d1d1f4f87cb Fixed silly case of caching .a85 when it exists
rgbecker
parents: 1219
diff changeset
   100
        #save it to a file
3d1d1f4f87cb Fixed silly case of caching .a85 when it exists
rgbecker
parents: 1219
diff changeset
   101
        f = open(cachedname,'wb')
3843
ee97902ffa44 pdfdoc.py, pdfform.py & pdfutils.py: eliminate LINEEND
robin
parents: 3835
diff changeset
   102
        f.write('\r\n'.join(code)+'\r\n')
1368
3d1d1f4f87cb Fixed silly case of caching .a85 when it exists
rgbecker
parents: 1219
diff changeset
   103
        f.close()
1530
1dedd3370a99 rl_config._verbose ==> verbose
rgbecker
parents: 1421
diff changeset
   104
        if rl_config.verbose:
3721
0c93dd8ff567 initial changes from 2to3-3.3
rptlab
parents: 3617
diff changeset
   105
            print('cached image as %s' % cachedname)
0
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
   106
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
   107
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
   108
def preProcessImages(spec):
567
0c7064b86e9e Modified docstrings.
dinu_gherman
parents: 494
diff changeset
   109
    """Preprocesses one or more image files.
0c7064b86e9e Modified docstrings.
dinu_gherman
parents: 494
diff changeset
   110
4302
f3ff56a22b2e bump version --> 3.3.25
robin
parents: 4252
diff changeset
   111
    Accepts either a filespec ('C:\\mydir\\*.jpg') or a list
0
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
   112
    of image filenames, crunches them all to save time.  Run this
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
   113
    to save huge amounts of time when repeatedly building image
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
   114
    documents."""
660
243182bf7988 Removed commented encoding test functions.
dinu_gherman
parents: 658
diff changeset
   115
3800
e8547b00eb59 attempt to remove old type testing
robin
parents: 3781
diff changeset
   116
    import glob
660
243182bf7988 Removed commented encoding test functions.
dinu_gherman
parents: 658
diff changeset
   117
3800
e8547b00eb59 attempt to remove old type testing
robin
parents: 3781
diff changeset
   118
    if isinstance(spec,str):
0
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
   119
        filelist = glob.glob(spec)
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
   120
    else:  #list or tuple OK
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
   121
        filelist = spec
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
   122
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
   123
    for filename in filelist:
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
   124
        if cachedImageExists(filename):
1530
1dedd3370a99 rl_config._verbose ==> verbose
rgbecker
parents: 1421
diff changeset
   125
            if rl_config.verbose:
3721
0c93dd8ff567 initial changes from 2to3-3.3
rptlab
parents: 3617
diff changeset
   126
                print('cached version of %s already exists' % filename)
0
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
   127
        else:
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
   128
            cacheImageFile(filename)
1683
7fa753e4420a Removed all trailing whitespace
andy_robinson
parents: 1621
diff changeset
   129
0
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
   130
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
   131
def cachedImageExists(filename):
567
0c7064b86e9e Modified docstrings.
dinu_gherman
parents: 494
diff changeset
   132
    """Determines if a cached image already exists for a given file.
0c7064b86e9e Modified docstrings.
dinu_gherman
parents: 494
diff changeset
   133
0c7064b86e9e Modified docstrings.
dinu_gherman
parents: 494
diff changeset
   134
    Determines if a cached image exists which has the same name
0c7064b86e9e Modified docstrings.
dinu_gherman
parents: 494
diff changeset
   135
    and equal or newer date to the given file."""
3431
b92783cd5a73 pdfutils.py: fix 2.5'ism
rgbecker
parents: 3363
diff changeset
   136
    cachedname = os.path.splitext(filename)[0] + (rl_config.useA85 and '.a85' or 'bin')
0
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
   137
    if os.path.isfile(cachedname):
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
   138
        #see if it is newer
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
   139
        original_date = os.stat(filename)[8]
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
   140
        cached_date = os.stat(cachedname)[8]
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
   141
        if original_date > cached_date:
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
   142
            return 0
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
   143
        else:
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
   144
            return 1
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
   145
    else:
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
   146
        return 0
1683
7fa753e4420a Removed all trailing whitespace
andy_robinson
parents: 1621
diff changeset
   147
0
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
   148
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
   149
##############################################################
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
   150
#
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
   151
#            PDF Helper functions
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
   152
#
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
   153
##############################################################
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
   154
3843
ee97902ffa44 pdfdoc.py, pdfform.py & pdfutils.py: eliminate LINEEND
robin
parents: 3835
diff changeset
   155
def _normalizeLineEnds(text,desired='\r\n',unlikely='\x00\x01\x02\x03'):
567
0c7064b86e9e Modified docstrings.
dinu_gherman
parents: 494
diff changeset
   156
    """Normalizes different line end character(s).
0c7064b86e9e Modified docstrings.
dinu_gherman
parents: 494
diff changeset
   157
0c7064b86e9e Modified docstrings.
dinu_gherman
parents: 494
diff changeset
   158
    Ensures all instances of CR, LF and CRLF end up as
0c7064b86e9e Modified docstrings.
dinu_gherman
parents: 494
diff changeset
   159
    the specified one."""
2767
2ba5a1d26ad0 reportlab: make a85 wrap optional, add _reset to rl_config
rgbecker
parents: 2558
diff changeset
   160
    
2ba5a1d26ad0 reportlab: make a85 wrap optional, add _reset to rl_config
rgbecker
parents: 2558
diff changeset
   161
    return (text
3363
f329def8b08f pdfutils.py: fix bad code
rgbecker
parents: 3359
diff changeset
   162
            .replace('\r\n', unlikely)
f329def8b08f pdfutils.py: fix bad code
rgbecker
parents: 3359
diff changeset
   163
            .replace('\r', unlikely)
f329def8b08f pdfutils.py: fix bad code
rgbecker
parents: 3359
diff changeset
   164
            .replace('\n', unlikely)
f329def8b08f pdfutils.py: fix bad code
rgbecker
parents: 3359
diff changeset
   165
            .replace(unlikely, desired))
567
0c7064b86e9e Modified docstrings.
dinu_gherman
parents: 494
diff changeset
   166
0
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
   167
def _AsciiHexEncode(input):
567
0c7064b86e9e Modified docstrings.
dinu_gherman
parents: 494
diff changeset
   168
    """Encodes input using ASCII-Hex coding.
0c7064b86e9e Modified docstrings.
dinu_gherman
parents: 494
diff changeset
   169
0c7064b86e9e Modified docstrings.
dinu_gherman
parents: 494
diff changeset
   170
    This is a verbose encoding used for binary data within
0c7064b86e9e Modified docstrings.
dinu_gherman
parents: 494
diff changeset
   171
    a PDF file.  One byte binary becomes two bytes of ASCII.
0c7064b86e9e Modified docstrings.
dinu_gherman
parents: 494
diff changeset
   172
    Helper function used by images."""
3731
b233dd0577ff another round of changes mostly type related
rptlab
parents: 3723
diff changeset
   173
    if isUnicode(input):
3723
99aa837b6703 second stage of port to Python 3.3; working hello world
rptlab
parents: 3721
diff changeset
   174
        input = input.encode('utf-8')
99aa837b6703 second stage of port to Python 3.3; working hello world
rptlab
parents: 3721
diff changeset
   175
    output = getBytesIO()
99aa837b6703 second stage of port to Python 3.3; working hello world
rptlab
parents: 3721
diff changeset
   176
    output.write(binascii.b2a_hex(input))
99aa837b6703 second stage of port to Python 3.3; working hello world
rptlab
parents: 3721
diff changeset
   177
    output.write(b'>')
1621
0b7238e56cae Remove stringio reset
rgbecker
parents: 1582
diff changeset
   178
    return output.getvalue()
0
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
   179
567
0c7064b86e9e Modified docstrings.
dinu_gherman
parents: 494
diff changeset
   180
0
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
   181
def _AsciiHexDecode(input):
567
0c7064b86e9e Modified docstrings.
dinu_gherman
parents: 494
diff changeset
   182
    """Decodes input using ASCII-Hex coding.
0c7064b86e9e Modified docstrings.
dinu_gherman
parents: 494
diff changeset
   183
0c7064b86e9e Modified docstrings.
dinu_gherman
parents: 494
diff changeset
   184
    Not used except to provide a test of the inverse function."""
660
243182bf7988 Removed commented encoding test functions.
dinu_gherman
parents: 658
diff changeset
   185
0
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
   186
    #strip out all whitespace
3835
8e35c471e0ee various: attempt to be more consistent about isStr
robin
parents: 3800
diff changeset
   187
    if not isUnicode(input):
3723
99aa837b6703 second stage of port to Python 3.3; working hello world
rptlab
parents: 3721
diff changeset
   188
        input = input.decode('utf-8')
2767
2ba5a1d26ad0 reportlab: make a85 wrap optional, add _reset to rl_config
rgbecker
parents: 2558
diff changeset
   189
    stripped = ''.join(input.split())
0
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
   190
    assert stripped[-1] == '>', 'Invalid terminator for Ascii Hex Stream'
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
   191
    stripped = stripped[:-1]  #chop off terminator
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
   192
    assert len(stripped) % 2 == 0, 'Ascii Hex stream has odd number of bytes'
660
243182bf7988 Removed commented encoding test functions.
dinu_gherman
parents: 658
diff changeset
   193
3721
0c93dd8ff567 initial changes from 2to3-3.3
rptlab
parents: 3617
diff changeset
   194
    return ''.join([chr(int(stripped[i:i+2],16)) for i in range(0,len(stripped),2)])
2853
69fab4f9a4ad pdfutils.py: improvements to en/decoders
rgbecker
parents: 2767
diff changeset
   195
        
0
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
   196
def _wrap(input, columns=60):
3843
ee97902ffa44 pdfdoc.py, pdfform.py & pdfutils.py: eliminate LINEEND
robin
parents: 3835
diff changeset
   197
    "Wraps input at a given column size by inserting \r\n characters."
0
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
   198
    output = []
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
   199
    length = len(input)
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
   200
    i = 0
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
   201
    pos = columns * i
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
   202
    while pos < length:
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
   203
        output.append(input[pos:pos+columns])
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
   204
        i = i + 1
f19e0a2433ab Initial revision
gmcm
parents:
diff changeset
   205
        pos = columns * i
2767
2ba5a1d26ad0 reportlab: make a85 wrap optional, add _reset to rl_config
rgbecker
parents: 2558
diff changeset
   206
    #avoid HP printer problem
2ba5a1d26ad0 reportlab: make a85 wrap optional, add _reset to rl_config
rgbecker
parents: 2558
diff changeset
   207
    if len(output[-1])==1:
2ba5a1d26ad0 reportlab: make a85 wrap optional, add _reset to rl_config
rgbecker
parents: 2558
diff changeset
   208
        output[-2:] = [output[-2][:-1],output[-2][-1]+output[-1]]
3843
ee97902ffa44 pdfdoc.py, pdfform.py & pdfutils.py: eliminate LINEEND
robin
parents: 3835
diff changeset
   209
    return '\r\n'.join(output)
657
75f09848334a Commented one test function.
dinu_gherman
parents: 567
diff changeset
   210
1683
7fa753e4420a Removed all trailing whitespace
andy_robinson
parents: 1621
diff changeset
   211
224
764725e69f94 readJPEGinfo moved from canvas to pdfutils;
andy_robinson
parents: 34
diff changeset
   212
#########################################################################
764725e69f94 readJPEGinfo moved from canvas to pdfutils;
andy_robinson
parents: 34
diff changeset
   213
#
764725e69f94 readJPEGinfo moved from canvas to pdfutils;
andy_robinson
parents: 34
diff changeset
   214
#  JPEG processing code - contributed by Eric Johnson
764725e69f94 readJPEGinfo moved from canvas to pdfutils;
andy_robinson
parents: 34
diff changeset
   215
#
764725e69f94 readJPEGinfo moved from canvas to pdfutils;
andy_robinson
parents: 34
diff changeset
   216
#########################################################################
764725e69f94 readJPEGinfo moved from canvas to pdfutils;
andy_robinson
parents: 34
diff changeset
   217
764725e69f94 readJPEGinfo moved from canvas to pdfutils;
andy_robinson
parents: 34
diff changeset
   218
# Read data from the JPEG file. We should probably be using PIL to
764725e69f94 readJPEGinfo moved from canvas to pdfutils;
andy_robinson
parents: 34
diff changeset
   219
# get this information for us -- but this way is more fun!
764725e69f94 readJPEGinfo moved from canvas to pdfutils;
andy_robinson
parents: 34
diff changeset
   220
# Returns (width, height, color components) as a triple
764725e69f94 readJPEGinfo moved from canvas to pdfutils;
andy_robinson
parents: 34
diff changeset
   221
# This is based on Thomas Merz's code from GhostScript (viewjpeg.ps)
764725e69f94 readJPEGinfo moved from canvas to pdfutils;
andy_robinson
parents: 34
diff changeset
   222
def readJPEGInfo(image):
567
0c7064b86e9e Modified docstrings.
dinu_gherman
parents: 494
diff changeset
   223
    "Read width, height and number of components from open JPEG file."
660
243182bf7988 Removed commented encoding test functions.
dinu_gherman
parents: 658
diff changeset
   224
224
764725e69f94 readJPEGinfo moved from canvas to pdfutils;
andy_robinson
parents: 34
diff changeset
   225
    import struct
3975
4a3599863c11 eliminate from . imports in favour of absolutes to allow running modules
robin
parents: 3843
diff changeset
   226
    from reportlab.pdfbase.pdfdoc import PDFError
224
764725e69f94 readJPEGinfo moved from canvas to pdfutils;
andy_robinson
parents: 34
diff changeset
   227
764725e69f94 readJPEGinfo moved from canvas to pdfutils;
andy_robinson
parents: 34
diff changeset
   228
    #Acceptable JPEG Markers:
764725e69f94 readJPEGinfo moved from canvas to pdfutils;
andy_robinson
parents: 34
diff changeset
   229
    #  SROF0=baseline, SOF1=extended sequential or SOF2=progressive
764725e69f94 readJPEGinfo moved from canvas to pdfutils;
andy_robinson
parents: 34
diff changeset
   230
    validMarkers = [0xC0, 0xC1, 0xC2]
764725e69f94 readJPEGinfo moved from canvas to pdfutils;
andy_robinson
parents: 34
diff changeset
   231
764725e69f94 readJPEGinfo moved from canvas to pdfutils;
andy_robinson
parents: 34
diff changeset
   232
    #JPEG markers without additional parameters
764725e69f94 readJPEGinfo moved from canvas to pdfutils;
andy_robinson
parents: 34
diff changeset
   233
    noParamMarkers = \
764725e69f94 readJPEGinfo moved from canvas to pdfutils;
andy_robinson
parents: 34
diff changeset
   234
        [ 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0x01 ]
764725e69f94 readJPEGinfo moved from canvas to pdfutils;
andy_robinson
parents: 34
diff changeset
   235
764725e69f94 readJPEGinfo moved from canvas to pdfutils;
andy_robinson
parents: 34
diff changeset
   236
    #Unsupported JPEG Markers
764725e69f94 readJPEGinfo moved from canvas to pdfutils;
andy_robinson
parents: 34
diff changeset
   237
    unsupportedMarkers = \
764725e69f94 readJPEGinfo moved from canvas to pdfutils;
andy_robinson
parents: 34
diff changeset
   238
        [ 0xC3, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCD, 0xCE, 0xCF ]
764725e69f94 readJPEGinfo moved from canvas to pdfutils;
andy_robinson
parents: 34
diff changeset
   239
764725e69f94 readJPEGinfo moved from canvas to pdfutils;
andy_robinson
parents: 34
diff changeset
   240
    #read JPEG marker segments until we find SOFn marker or EOF
764725e69f94 readJPEGinfo moved from canvas to pdfutils;
andy_robinson
parents: 34
diff changeset
   241
    done = 0
764725e69f94 readJPEGinfo moved from canvas to pdfutils;
andy_robinson
parents: 34
diff changeset
   242
    while not done:
764725e69f94 readJPEGinfo moved from canvas to pdfutils;
andy_robinson
parents: 34
diff changeset
   243
        x = struct.unpack('B', image.read(1))
764725e69f94 readJPEGinfo moved from canvas to pdfutils;
andy_robinson
parents: 34
diff changeset
   244
        if x[0] == 0xFF:                    #found marker
764725e69f94 readJPEGinfo moved from canvas to pdfutils;
andy_robinson
parents: 34
diff changeset
   245
            x = struct.unpack('B', image.read(1))
764725e69f94 readJPEGinfo moved from canvas to pdfutils;
andy_robinson
parents: 34
diff changeset
   246
            #print "Marker: ", '%0.2x' % x[0]
764725e69f94 readJPEGinfo moved from canvas to pdfutils;
andy_robinson
parents: 34
diff changeset
   247
            #check marker type is acceptable and process it
764725e69f94 readJPEGinfo moved from canvas to pdfutils;
andy_robinson
parents: 34
diff changeset
   248
            if x[0] in validMarkers:
764725e69f94 readJPEGinfo moved from canvas to pdfutils;
andy_robinson
parents: 34
diff changeset
   249
                image.seek(2, 1)            #skip segment length
764725e69f94 readJPEGinfo moved from canvas to pdfutils;
andy_robinson
parents: 34
diff changeset
   250
                x = struct.unpack('B', image.read(1)) #data precision
764725e69f94 readJPEGinfo moved from canvas to pdfutils;
andy_robinson
parents: 34
diff changeset
   251
                if x[0] != 8:
2558
97ae9d8242cd pdfgen: fix badly drawn jpegs which are actually gifs
rgbecker
parents: 2482
diff changeset
   252
                    raise PDFError('JPEG must have 8 bits per component')
224
764725e69f94 readJPEGinfo moved from canvas to pdfutils;
andy_robinson
parents: 34
diff changeset
   253
                y = struct.unpack('BB', image.read(2))
1683
7fa753e4420a Removed all trailing whitespace
andy_robinson
parents: 1621
diff changeset
   254
                height = (y[0] << 8) + y[1]
224
764725e69f94 readJPEGinfo moved from canvas to pdfutils;
andy_robinson
parents: 34
diff changeset
   255
                y = struct.unpack('BB', image.read(2))
764725e69f94 readJPEGinfo moved from canvas to pdfutils;
andy_robinson
parents: 34
diff changeset
   256
                width =  (y[0] << 8) + y[1]
764725e69f94 readJPEGinfo moved from canvas to pdfutils;
andy_robinson
parents: 34
diff changeset
   257
                y = struct.unpack('B', image.read(1))
764725e69f94 readJPEGinfo moved from canvas to pdfutils;
andy_robinson
parents: 34
diff changeset
   258
                color =  y[0]
764725e69f94 readJPEGinfo moved from canvas to pdfutils;
andy_robinson
parents: 34
diff changeset
   259
                return width, height, color
764725e69f94 readJPEGinfo moved from canvas to pdfutils;
andy_robinson
parents: 34
diff changeset
   260
            elif x[0] in unsupportedMarkers:
2558
97ae9d8242cd pdfgen: fix badly drawn jpegs which are actually gifs
rgbecker
parents: 2482
diff changeset
   261
                raise PDFError('JPEG Unsupported JPEG marker: %0.2x' % x[0])
224
764725e69f94 readJPEGinfo moved from canvas to pdfutils;
andy_robinson
parents: 34
diff changeset
   262
            elif x[0] not in noParamMarkers:
764725e69f94 readJPEGinfo moved from canvas to pdfutils;
andy_robinson
parents: 34
diff changeset
   263
                #skip segments with parameters
764725e69f94 readJPEGinfo moved from canvas to pdfutils;
andy_robinson
parents: 34
diff changeset
   264
                #read length and skip the data
764725e69f94 readJPEGinfo moved from canvas to pdfutils;
andy_robinson
parents: 34
diff changeset
   265
                x = struct.unpack('BB', image.read(2))
1772
ba6ba46e2370 Added A85 caching possibility to Image XObjects
rgbecker
parents: 1683
diff changeset
   266
                image.seek( (x[0] << 8) + x[1] - 2, 1)
2399
41c1b1d88a33 pdfutils.py: added _fusc
rgbecker
parents: 2332
diff changeset
   267
41c1b1d88a33 pdfutils.py: added _fusc
rgbecker
parents: 2332
diff changeset
   268
class _fusc:
41c1b1d88a33 pdfutils.py: added _fusc
rgbecker
parents: 2332
diff changeset
   269
    def __init__(self,k, n):
41c1b1d88a33 pdfutils.py: added _fusc
rgbecker
parents: 2332
diff changeset
   270
        assert k, 'Argument k should be a non empty string'
41c1b1d88a33 pdfutils.py: added _fusc
rgbecker
parents: 2332
diff changeset
   271
        self._k = k
41c1b1d88a33 pdfutils.py: added _fusc
rgbecker
parents: 2332
diff changeset
   272
        self._klen = len(k)
41c1b1d88a33 pdfutils.py: added _fusc
rgbecker
parents: 2332
diff changeset
   273
        self._n = int(n) or 7
41c1b1d88a33 pdfutils.py: added _fusc
rgbecker
parents: 2332
diff changeset
   274
41c1b1d88a33 pdfutils.py: added _fusc
rgbecker
parents: 2332
diff changeset
   275
    def encrypt(self,s):
3781
df8b57380768 import from reportlab.lib.lib.rl_accel
robin
parents: 3765
diff changeset
   276
        return self.__rotate(asciiBase85Encode(''.join(map(chr,self.__fusc(list(map(ord,s)))))),self._n)
2399
41c1b1d88a33 pdfutils.py: added _fusc
rgbecker
parents: 2332
diff changeset
   277
41c1b1d88a33 pdfutils.py: added _fusc
rgbecker
parents: 2332
diff changeset
   278
    def decrypt(self,s):
3781
df8b57380768 import from reportlab.lib.lib.rl_accel
robin
parents: 3765
diff changeset
   279
        return ''.join(map(chr,self.__fusc(list(map(ord,asciiBase85Decode(self.__rotate(s,-self._n)))))))
2399
41c1b1d88a33 pdfutils.py: added _fusc
rgbecker
parents: 2332
diff changeset
   280
41c1b1d88a33 pdfutils.py: added _fusc
rgbecker
parents: 2332
diff changeset
   281
    def __rotate(self,s,n):
41c1b1d88a33 pdfutils.py: added _fusc
rgbecker
parents: 2332
diff changeset
   282
        l = len(s)
41c1b1d88a33 pdfutils.py: added _fusc
rgbecker
parents: 2332
diff changeset
   283
        if n<0: n = l+n
41c1b1d88a33 pdfutils.py: added _fusc
rgbecker
parents: 2332
diff changeset
   284
        n %= l
41c1b1d88a33 pdfutils.py: added _fusc
rgbecker
parents: 2332
diff changeset
   285
        if not n: return s
41c1b1d88a33 pdfutils.py: added _fusc
rgbecker
parents: 2332
diff changeset
   286
        return s[-n:]+s[:l-n]
41c1b1d88a33 pdfutils.py: added _fusc
rgbecker
parents: 2332
diff changeset
   287
41c1b1d88a33 pdfutils.py: added _fusc
rgbecker
parents: 2332
diff changeset
   288
    def __fusc(self,s):
41c1b1d88a33 pdfutils.py: added _fusc
rgbecker
parents: 2332
diff changeset
   289
        slen = len(s)
3721
0c93dd8ff567 initial changes from 2to3-3.3
rptlab
parents: 3617
diff changeset
   290
        return list(map(lambda x,y: x ^ y,s,list(map(ord,((int(slen/self._klen)+1)*self._k)[:slen]))))