jbig2pdf
view src/jbig2pdf/jbig2pdf.py @ 4:0ed3a4d9bbc6
Removed unused function.
| author | VanL <van.lindberg@gmail.com> |
|---|---|
| date | Wed Oct 28 15:28:09 2009 +0000 (9 months ago) |
| parents | 556c7301cac4 |
| children |
line source
1 """
2 jbig2pdf.jbig2pdf
4 Support for JBIG2 encoded data in Reportlab-produced PDFs.
6 (c) 2009 Van Lindberg; licensed under the Affero GPL v3. See LICENSE.
8 """
9 import struct
10 from os.path import splitext, exists
11 from reportlab.pdfbase import pdfutils, pdfdoc
12 from reportlab.pdfbase.pdfdoc import PDFObjectReference, PDFError
13 from reportlab.pdfbase.pdfdoc import PDFDocument, PDFImageXObject, PDFStream
14 from reportlab.pdfgen.pdfimages import PDFImage
15 from reportlab.pdfgen.canvas import Canvas
16 from reportlab.lib.pagesizes import letter
17 from reportlab.lib.utils import open_for_read, _digester, fp_str
20 class JBIG2Canvas(Canvas):
21 """
22 Canvas class that understands JBIG2 files.
23 """
24 def __init__(self, *args, **kwargs):
25 self._symboltable = {}
26 Canvas.__init__(self, *args, **kwargs)
28 def _getSymbolTable(self, symboltable):
29 """
30 Embed a symboltable in the pdf and return a reference. The
31 symboltable can be either a filename or a file-like object.
32 """
33 if not hasattr(symboltable, 'read'):
34 symboltable = open_for_read(symboltable)
35 symbols = symboltable.read()
36 digest = _digester(symbols)
37 if self._symboltable:
38 # We have already embedded a symboltable. Is it the same?
39 try: return self._symboltable[digest]
40 except KeyError:
41 raise PDFError('Only one JBIG2 symboltable allowed per document.')
42 else:
43 # Embed this symboltable and save a reference
44 S = PDFStream(content=symbols)
45 self._symboltable[digest] = self._doc.Reference(S, name=digest)
46 return self._symboltable[digest]
48 def drawImage(self, image, x, y, width=None, height=None, mask=None,
49 preserveAspectRatio=False, anchor='c', symboltable=None):
51 # Defer to superclass if this isn't JBIG2 specific
52 if not hasattr(self, '_symboltable'):
53 return Canvas.drawImage(self, image, x, y, width, height,
54 mask, preserveAspectRatio,
55 anchor)
56 # JBIG2
57 # Do we have the symboltable loaded?
58 if not self._symboltable:
59 # No: Were we given one?
60 if symboltable:
61 symboltable_ref = self._getSymbolTable(symboltable)
62 else:
63 # Try to load one based on the image filename
64 if hasattr(image, 'name'):
65 symboltable = splitext(image.name)[0] + '.sym'
66 else:
67 symboltable = splitext(image)[0] + '.sym'
68 symboltable_ref = self._getSymbolTable(symboltable)
70 # Now deal with the current page
71 self._currentPageHasImages = 1
72 # first, generate a unique name/signature for the image. If ANYTHING
73 # is different, even the mask, this should be different.
75 if hasattr(image, 'seek'):
76 # File-like
77 image.seek(0)
78 name = _digester('%s%s' % (image.read(), mask))
79 else:
80 # Filename
81 name = _digester('%s%s' % (image, mask))
83 # in the pdf document, this will be prefixed with something to
84 # say it is an XObject. Does it exist yet?
85 regName = self._doc.getXObjectName(name)
86 imgObj = self._doc.idToObject.get(regName, None)
87 if not imgObj:
88 #first time seen, create and register the JBIG2 Image object
89 imgObj = JBIG2Image(image, symboltable_ref, x, y, width, height)
90 imgObj.name = name
91 self._setXObjects(imgObj)
92 self._doc.Reference(imgObj, regName)
93 self._doc.addForm(name, imgObj)
94 smask = getattr(imgObj,'_smask',None)
95 if smask: #set up the softmask obtained above
96 mRegName = self._doc.getXObjectName(smask.name)
97 mImgObj = self._doc.idToObject.get(mRegName, None)
98 if not mImgObj:
99 self._setXObjects(smask)
100 imgObj.smask = self._doc.Reference(smask,mRegName)
101 else:
102 imgObj.smask = pdfdoc.PDFObjectReference(mRegName)
103 del imgObj._smask
105 # No scaling for JBIG2. Draw.
106 self.saveState()
107 imgObj.drawInlineImage(self, preserveAspectRatio=True, anchor=anchor)
108 self.restoreState()
110 # track what's been used on this page
111 self._formsinuse.append(name)
112 return (imgObj.width, imgObj.height)
114 class JBIG2Image(PDFImage, PDFImageXObject):
115 __PDFObject__ = True
116 def __init__(self, image, symboltable, x, y, width=None, height=None):
117 self.image = image
118 self.x = x
119 self.y = y
120 self.width = width
121 self.height = height
122 self.filename = None
123 self.imageCaching = None
124 self.mask = None
125 self.colorSpace = 'DeviceGray'
126 self.bitsPerComponent = 1
127 self._filters = ['JBIG2Decode']
128 self.source = 'JBIG2'
129 self.symboltable = symboltable
130 self._useAsciiBase85Encoding = False
131 self.getImageData()
132 self.name = 'Im1'
134 def jbig2_imagedata(self):
135 #directly process JBIG2 files
136 fp = open_for_read(self.image, 'rb')
137 try:
138 result = self._jbig2_imagedata(fp)
139 finally:
140 fp.close()
141 return result
143 def _jbig2_imagedata(self,imageFile):
144 metadata = imageFile.read(57)
145 imgwidth, imgheight = struct.unpack('>II', metadata[11:19])
146 imageFile.seek(0) #reset file pointer
147 imagedata = []
148 imagedesc = 'BI /Width %d /Height %d ' % (imgwidth, imgheight)
149 imagedesc += '/BitsPerComponent %s ' % (self.bitsPerComponent)
150 imagedesc += '/ColorSpace /%s ' % (self.colorSpace)
151 if self._useAsciiBase85Encoding:
152 imagedesc += '/Filter [/A85 /JBIG2Decode] '
153 else:
154 imagedesc += '/Filter /JBIG2Decode '
155 imagedesc += '/DecodeParms << /JBIG2Globals %s >>' % (self.symboltable)
156 imagedata.append(imagedesc)
157 #write in blocks of (??) 60 characters per line to a list
158 compressed = imageFile.read()
159 if self._useAsciiBase85Encoding:
160 self._filters.insert(0, 'ASCII85Decode')
161 encoded = pdfutils._AsciiBase85Encode(compressed)
162 pdfutils._chunker(encoded,imagedata)
163 imagedata.append('EI')
164 else:
165 imagedata.append(compressed)
166 return (imagedata, imgwidth, imgheight)
168 def getImageData(self,preserveAspectRatio=False):
169 "Gets data, height, width - whatever type of image"
170 # Defer to superclass if this isn't JBIG2 specific
171 if not hasattr(self, 'symboltable'):
172 return PDFImage.getImageData(self, preserveAspectRatio)
173 # JBIG2
174 image = self.image
175 imagedata, imgwidth, imgheight = self.jbig2_imagedata()
176 self.imageData = imagedata
177 self.imgwidth = imgwidth
178 self.imgheight = imgheight
179 self.width = self.width or imgwidth
180 self.height = self.height or imgheight
183 def drawInlineImage(self, canvas, preserveAspectRatio=False, anchor='sw'):
184 """Draw an Image into the specified rectangle. If width and
185 height are omitted, they are calculated from the image size.
186 Also allow file names as well as images. This allows a
187 caching mechanism"""
188 # Defer to superclass if this isn't JBIG2 specific
189 if not hasattr(self, 'symboltable'):
190 return PDFImage.drawInlineImage(self, canvas, preserveAspectRatio, anchor)
191 # JBIG2
192 # I am not sure how to scale a jbig2 image, so you get what you get.
193 width = self.width
194 height = self.height
195 if width<1e-6 or height<1e-6: return False
196 if self._useAsciiBase85Encoding:
197 canvas._code.append('q %s 0 0 %s cm' % (fp_str(self.width),
198 fp_str(self.height,
199 x, y)))
200 for line in self.imageData:
201 canvas._code.append(line)
202 canvas._code.append('Q')
203 else:
204 canvas._code.append('q %s 0 0 %s cm /%s Do Q' % (fp_str(self.width),
205 fp_str(self.height,
206 self.x, self.y),
207 self.name))
208 return True
211 def _pdfstream(self):
212 dict = pdfdoc.PDFDictionary()
213 dict['Type'] = pdfdoc.PDFName('XObject')
214 dict['Subtype'] = pdfdoc.PDFName('Image')
215 dict['Width'] = self.width
216 dict['Height'] = self.height
217 dict['BitsPerComponent'] = self.bitsPerComponent
218 dict['ColorSpace'] = pdfdoc.PDFName(self.colorSpace)
219 dict["Filter"] = pdfdoc.PDFArray(map(pdfdoc.PDFName,self._filters))
220 content = '\n'.join(self.imageData[3:-1]) + '\n'
221 dict["Length"] = len(content)
222 strm = pdfdoc.PDFStream(dictionary=dict, content=content)
223 return strm
225 def format(self, document):
226 """Allow it to be used within pdfdoc framework. This only
227 defines how it is stored, not how it is drawn later."""
228 strm = self._pdfstream()
229 return strm.format(document)
