png.py 103 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784
  1. #!/usr/bin/env python
  2. # png.py - PNG encoder/decoder in pure Python
  3. #
  4. # Copyright (C) 2006 Johann C. Rocholl <johann@browsershots.org>
  5. # Portions Copyright (C) 2009 David Jones <drj@pobox.com>
  6. # And probably portions Copyright (C) 2006 Nicko van Someren <nicko@nicko.org>
  7. #
  8. # Original concept by Johann C. Rocholl.
  9. #
  10. # LICENCE (MIT)
  11. #
  12. # Permission is hereby granted, free of charge, to any person
  13. # obtaining a copy of this software and associated documentation files
  14. # (the "Software"), to deal in the Software without restriction,
  15. # including without limitation the rights to use, copy, modify, merge,
  16. # publish, distribute, sublicense, and/or sell copies of the Software,
  17. # and to permit persons to whom the Software is furnished to do so,
  18. # subject to the following conditions:
  19. #
  20. # The above copyright notice and this permission notice shall be
  21. # included in all copies or substantial portions of the Software.
  22. #
  23. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  24. # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  25. # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  26. # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  27. # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  28. # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  29. # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  30. # SOFTWARE.
  31. """
  32. Pure Python PNG Reader/Writer
  33. This Python module implements support for PNG images (see PNG
  34. specification at http://www.w3.org/TR/2003/REC-PNG-20031110/ ). It reads
  35. and writes PNG files with all allowable bit depths
  36. (1/2/4/8/16/24/32/48/64 bits per pixel) and colour combinations:
  37. greyscale (1/2/4/8/16 bit); RGB, RGBA, LA (greyscale with alpha) with
  38. 8/16 bits per channel; colour mapped images (1/2/4/8 bit).
  39. Adam7 interlacing is supported for reading and
  40. writing. A number of optional chunks can be specified (when writing)
  41. and understood (when reading): ``tRNS``, ``bKGD``, ``gAMA``.
  42. For help, type ``import png; help(png)`` in your python interpreter.
  43. A good place to start is the :class:`Reader` and :class:`Writer`
  44. classes.
  45. Requires Python 2.3. Limited support is available for Python 2.2, but
  46. not everything works. Best with Python 2.4 and higher. Installation is
  47. trivial, but see the ``README.txt`` file (with the source distribution)
  48. for details.
  49. This file can also be used as a command-line utility to convert
  50. `Netpbm <http://netpbm.sourceforge.net/>`_ PNM files to PNG, and the
  51. reverse conversion from PNG to PNM. The interface is similar to that
  52. of the ``pnmtopng`` program from Netpbm. Type ``python png.py --help``
  53. at the shell prompt for usage and a list of options.
  54. A note on spelling and terminology
  55. ----------------------------------
  56. Generally British English spelling is used in the documentation. So
  57. that's "greyscale" and "colour". This not only matches the author's
  58. native language, it's also used by the PNG specification.
  59. The major colour models supported by PNG (and hence by PyPNG) are:
  60. greyscale, RGB, greyscale--alpha, RGB--alpha. These are sometimes
  61. referred to using the abbreviations: L, RGB, LA, RGBA. In this case
  62. each letter abbreviates a single channel: *L* is for Luminance or Luma
  63. or Lightness which is the channel used in greyscale images; *R*, *G*,
  64. *B* stand for Red, Green, Blue, the components of a colour image; *A*
  65. stands for Alpha, the opacity channel (used for transparency effects,
  66. but higher values are more opaque, so it makes sense to call it
  67. opacity).
  68. A note on formats
  69. -----------------
  70. When getting pixel data out of this module (reading) and presenting
  71. data to this module (writing) there are a number of ways the data could
  72. be represented as a Python value. Generally this module uses one of
  73. three formats called "flat row flat pixel", "boxed row flat pixel", and
  74. "boxed row boxed pixel". Basically the concern is whether each pixel
  75. and each row comes in its own little tuple (box), or not.
  76. Consider an image that is 3 pixels wide by 2 pixels high, and each pixel
  77. has RGB components:
  78. Boxed row flat pixel::
  79. list([R,G,B, R,G,B, R,G,B],
  80. [R,G,B, R,G,B, R,G,B])
  81. Each row appears as its own list, but the pixels are flattened so
  82. that three values for one pixel simply follow the three values for
  83. the previous pixel. This is the most common format used, because it
  84. provides a good compromise between space and convenience. PyPNG regards
  85. itself as at liberty to replace any sequence type with any sufficiently
  86. compatible other sequence type; in practice each row is an array (from
  87. the array module), and the outer list is sometimes an iterator rather
  88. than an explicit list (so that streaming is possible).
  89. Flat row flat pixel::
  90. [R,G,B, R,G,B, R,G,B,
  91. R,G,B, R,G,B, R,G,B]
  92. The entire image is one single giant sequence of colour values.
  93. Generally an array will be used (to save space), not a list.
  94. Boxed row boxed pixel::
  95. list([ (R,G,B), (R,G,B), (R,G,B) ],
  96. [ (R,G,B), (R,G,B), (R,G,B) ])
  97. Each row appears in its own list, but each pixel also appears in its own
  98. tuple. A serious memory burn in Python.
  99. In all cases the top row comes first, and for each row the pixels are
  100. ordered from left-to-right. Within a pixel the values appear in the
  101. order, R-G-B-A (or L-A for greyscale--alpha).
  102. There is a fourth format, mentioned because it is used internally,
  103. is close to what lies inside a PNG file itself, and has some support
  104. from the public API. This format is called packed. When packed,
  105. each row is a sequence of bytes (integers from 0 to 255), just as
  106. it is before PNG scanline filtering is applied. When the bit depth
  107. is 8 this is essentially the same as boxed row flat pixel; when the
  108. bit depth is less than 8, several pixels are packed into each byte;
  109. when the bit depth is 16 (the only value more than 8 that is supported
  110. by the PNG image format) each pixel value is decomposed into 2 bytes
  111. (and `packed` is a misnomer). This format is used by the
  112. :meth:`Writer.write_packed` method. It isn't usually a convenient
  113. format, but may be just right if the source data for the PNG image
  114. comes from something that uses a similar format (for example, 1-bit
  115. BMPs, or another PNG file).
  116. And now, my famous members
  117. --------------------------
  118. """
  119. # http://www.python.org/doc/2.2.3/whatsnew/node5.html
  120. from __future__ import generators
  121. __version__ = "0.0.18"
  122. from array import array
  123. try: # See :pyver:old
  124. import itertools
  125. except ImportError:
  126. pass
  127. import math
  128. # http://www.python.org/doc/2.4.4/lib/module-operator.html
  129. import operator
  130. import struct
  131. import sys
  132. import zlib
  133. # http://www.python.org/doc/2.4.4/lib/module-warnings.html
  134. import warnings
  135. try:
  136. # `cpngfilters` is a Cython module: it must be compiled by
  137. # Cython for this import to work.
  138. # If this import does work, then it overrides pure-python
  139. # filtering functions defined later in this file (see `class
  140. # pngfilters`).
  141. import cpngfilters as pngfilters
  142. except ImportError:
  143. pass
  144. __all__ = ['Image', 'Reader', 'Writer', 'write_chunks', 'from_array']
  145. # The PNG signature.
  146. # http://www.w3.org/TR/PNG/#5PNG-file-signature
  147. _signature = struct.pack('8B', 137, 80, 78, 71, 13, 10, 26, 10)
  148. _adam7 = ((0, 0, 8, 8),
  149. (4, 0, 8, 8),
  150. (0, 4, 4, 8),
  151. (2, 0, 4, 4),
  152. (0, 2, 2, 4),
  153. (1, 0, 2, 2),
  154. (0, 1, 1, 2))
  155. def group(s, n):
  156. # See http://www.python.org/doc/2.6/library/functions.html#zip
  157. return zip(*[iter(s)]*n)
  158. def isarray(x):
  159. """Same as ``isinstance(x, array)`` except on Python 2.2, where it
  160. always returns ``False``. This helps PyPNG work on Python 2.2.
  161. """
  162. try:
  163. return isinstance(x, array)
  164. except TypeError:
  165. # Because on Python 2.2 array.array is not a type.
  166. return False
  167. try:
  168. array.tobytes
  169. except AttributeError:
  170. try: # see :pyver:old
  171. array.tostring
  172. except AttributeError:
  173. def tostring(row):
  174. l = len(row)
  175. return struct.pack('%dB' % l, *row)
  176. else:
  177. def tostring(row):
  178. """Convert row of bytes to string. Expects `row` to be an
  179. ``array``.
  180. """
  181. return row.tostring()
  182. else:
  183. def tostring(row):
  184. """ Python3 definition, array.tostring() is deprecated in Python3
  185. """
  186. return row.tobytes()
  187. # Conditionally convert to bytes. Works on Python 2 and Python 3.
  188. try:
  189. bytes('', 'ascii')
  190. def strtobytes(x): return bytes(x, 'iso8859-1')
  191. def bytestostr(x): return str(x, 'iso8859-1')
  192. except (NameError, TypeError):
  193. # We get NameError when bytes() does not exist (most Python
  194. # 2.x versions), and TypeError when bytes() exists but is on
  195. # Python 2.x (when it is an alias for str() and takes at most
  196. # one argument).
  197. strtobytes = str
  198. bytestostr = str
  199. def interleave_planes(ipixels, apixels, ipsize, apsize):
  200. """
  201. Interleave (colour) planes, e.g. RGB + A = RGBA.
  202. Return an array of pixels consisting of the `ipsize` elements of
  203. data from each pixel in `ipixels` followed by the `apsize` elements
  204. of data from each pixel in `apixels`. Conventionally `ipixels`
  205. and `apixels` are byte arrays so the sizes are bytes, but it
  206. actually works with any arrays of the same type. The returned
  207. array is the same type as the input arrays which should be the
  208. same type as each other.
  209. """
  210. itotal = len(ipixels)
  211. atotal = len(apixels)
  212. newtotal = itotal + atotal
  213. newpsize = ipsize + apsize
  214. # Set up the output buffer
  215. # See http://www.python.org/doc/2.4.4/lib/module-array.html#l2h-1356
  216. out = array(ipixels.typecode)
  217. # It's annoying that there is no cheap way to set the array size :-(
  218. out.extend(ipixels)
  219. out.extend(apixels)
  220. # Interleave in the pixel data
  221. for i in range(ipsize):
  222. out[i:newtotal:newpsize] = ipixels[i:itotal:ipsize]
  223. for i in range(apsize):
  224. out[i+ipsize:newtotal:newpsize] = apixels[i:atotal:apsize]
  225. return out
  226. def check_palette(palette):
  227. """Check a palette argument (to the :class:`Writer` class)
  228. for validity. Returns the palette as a list if okay; raises an
  229. exception otherwise.
  230. """
  231. # None is the default and is allowed.
  232. if palette is None:
  233. return None
  234. p = list(palette)
  235. if not (0 < len(p) <= 256):
  236. raise ValueError("a palette must have between 1 and 256 entries")
  237. seen_triple = False
  238. for i,t in enumerate(p):
  239. if len(t) not in (3,4):
  240. raise ValueError(
  241. "palette entry %d: entries must be 3- or 4-tuples." % i)
  242. if len(t) == 3:
  243. seen_triple = True
  244. if seen_triple and len(t) == 4:
  245. raise ValueError(
  246. "palette entry %d: all 4-tuples must precede all 3-tuples" % i)
  247. for x in t:
  248. if int(x) != x or not(0 <= x <= 255):
  249. raise ValueError(
  250. "palette entry %d: values must be integer: 0 <= x <= 255" % i)
  251. return p
  252. def check_sizes(size, width, height):
  253. """Check that these arguments, in supplied, are consistent.
  254. Return a (width, height) pair.
  255. """
  256. if not size:
  257. return width, height
  258. if len(size) != 2:
  259. raise ValueError(
  260. "size argument should be a pair (width, height)")
  261. if width is not None and width != size[0]:
  262. raise ValueError(
  263. "size[0] (%r) and width (%r) should match when both are used."
  264. % (size[0], width))
  265. if height is not None and height != size[1]:
  266. raise ValueError(
  267. "size[1] (%r) and height (%r) should match when both are used."
  268. % (size[1], height))
  269. return size
  270. def check_color(c, greyscale, which):
  271. """Checks that a colour argument for transparent or
  272. background options is the right form. Returns the colour
  273. (which, if it's a bar integer, is "corrected" to a 1-tuple).
  274. """
  275. if c is None:
  276. return c
  277. if greyscale:
  278. try:
  279. len(c)
  280. except TypeError:
  281. c = (c,)
  282. if len(c) != 1:
  283. raise ValueError("%s for greyscale must be 1-tuple" %
  284. which)
  285. if not isinteger(c[0]):
  286. raise ValueError(
  287. "%s colour for greyscale must be integer" % which)
  288. else:
  289. if not (len(c) == 3 and
  290. isinteger(c[0]) and
  291. isinteger(c[1]) and
  292. isinteger(c[2])):
  293. raise ValueError(
  294. "%s colour must be a triple of integers" % which)
  295. return c
  296. class Error(Exception):
  297. def __str__(self):
  298. return self.__class__.__name__ + ': ' + ' '.join(self.args)
  299. class FormatError(Error):
  300. """Problem with input file format. In other words, PNG file does
  301. not conform to the specification in some way and is invalid.
  302. """
  303. class ChunkError(FormatError):
  304. pass
  305. class Writer:
  306. """
  307. PNG encoder in pure Python.
  308. """
  309. def __init__(self, width=None, height=None,
  310. size=None,
  311. greyscale=False,
  312. alpha=False,
  313. bitdepth=8,
  314. palette=None,
  315. transparent=None,
  316. background=None,
  317. gamma=None,
  318. compression=None,
  319. interlace=False,
  320. bytes_per_sample=None, # deprecated
  321. planes=None,
  322. colormap=None,
  323. maxval=None,
  324. chunk_limit=2**20,
  325. x_pixels_per_unit = None,
  326. y_pixels_per_unit = None,
  327. unit_is_meter = False):
  328. """
  329. Create a PNG encoder object.
  330. Arguments:
  331. width, height
  332. Image size in pixels, as two separate arguments.
  333. size
  334. Image size (w,h) in pixels, as single argument.
  335. greyscale
  336. Input data is greyscale, not RGB.
  337. alpha
  338. Input data has alpha channel (RGBA or LA).
  339. bitdepth
  340. Bit depth: from 1 to 16.
  341. palette
  342. Create a palette for a colour mapped image (colour type 3).
  343. transparent
  344. Specify a transparent colour (create a ``tRNS`` chunk).
  345. background
  346. Specify a default background colour (create a ``bKGD`` chunk).
  347. gamma
  348. Specify a gamma value (create a ``gAMA`` chunk).
  349. compression
  350. zlib compression level: 0 (none) to 9 (more compressed);
  351. default: -1 or None.
  352. interlace
  353. Create an interlaced image.
  354. chunk_limit
  355. Write multiple ``IDAT`` chunks to save memory.
  356. x_pixels_per_unit (pHYs chunk)
  357. Number of pixels a unit along the x axis
  358. y_pixels_per_unit (pHYs chunk)
  359. Number of pixels a unit along the y axis
  360. With x_pixel_unit, give the pixel size ratio
  361. unit_is_meter (pHYs chunk)
  362. Indicates if unit is meter or not
  363. The image size (in pixels) can be specified either by using the
  364. `width` and `height` arguments, or with the single `size`
  365. argument. If `size` is used it should be a pair (*width*,
  366. *height*).
  367. `greyscale` and `alpha` are booleans that specify whether
  368. an image is greyscale (or colour), and whether it has an
  369. alpha channel (or not).
  370. `bitdepth` specifies the bit depth of the source pixel values.
  371. Each source pixel value must be an integer between 0 and
  372. ``2**bitdepth-1``. For example, 8-bit images have values
  373. between 0 and 255. PNG only stores images with bit depths of
  374. 1,2,4,8, or 16. When `bitdepth` is not one of these values,
  375. the next highest valid bit depth is selected, and an ``sBIT``
  376. (significant bits) chunk is generated that specifies the
  377. original precision of the source image. In this case the
  378. supplied pixel values will be rescaled to fit the range of
  379. the selected bit depth.
  380. The details of which bit depth / colour model combinations the
  381. PNG file format supports directly, are somewhat arcane
  382. (refer to the PNG specification for full details). Briefly:
  383. "small" bit depths (1,2,4) are only allowed with greyscale and
  384. colour mapped images; colour mapped images cannot have bit depth
  385. 16.
  386. For colour mapped images (in other words, when the `palette`
  387. argument is specified) the `bitdepth` argument must match one of
  388. the valid PNG bit depths: 1, 2, 4, or 8. (It is valid to have a
  389. PNG image with a palette and an ``sBIT`` chunk, but the meaning
  390. is slightly different; it would be awkward to press the
  391. `bitdepth` argument into service for this.)
  392. The `palette` option, when specified, causes a colour mapped
  393. image to be created: the PNG colour type is set to 3; greyscale
  394. must not be set; alpha must not be set; transparent must not be
  395. set; the bit depth must be 1,2,4, or 8. When a colour mapped
  396. image is created, the pixel values are palette indexes and
  397. the `bitdepth` argument specifies the size of these indexes
  398. (not the size of the colour values in the palette).
  399. The palette argument value should be a sequence of 3- or
  400. 4-tuples. 3-tuples specify RGB palette entries; 4-tuples
  401. specify RGBA palette entries. If both 4-tuples and 3-tuples
  402. appear in the sequence then all the 4-tuples must come
  403. before all the 3-tuples. A ``PLTE`` chunk is created; if there
  404. are 4-tuples then a ``tRNS`` chunk is created as well. The
  405. ``PLTE`` chunk will contain all the RGB triples in the same
  406. sequence; the ``tRNS`` chunk will contain the alpha channel for
  407. all the 4-tuples, in the same sequence. Palette entries
  408. are always 8-bit.
  409. If specified, the `transparent` and `background` parameters must
  410. be a tuple with three integer values for red, green, blue, or
  411. a simple integer (or singleton tuple) for a greyscale image.
  412. If specified, the `gamma` parameter must be a positive number
  413. (generally, a float). A ``gAMA`` chunk will be created.
  414. Note that this will not change the values of the pixels as
  415. they appear in the PNG file, they are assumed to have already
  416. been converted appropriately for the gamma specified.
  417. The `compression` argument specifies the compression level to
  418. be used by the ``zlib`` module. Values from 1 to 9 specify
  419. compression, with 9 being "more compressed" (usually smaller
  420. and slower, but it doesn't always work out that way). 0 means
  421. no compression. -1 and ``None`` both mean that the default
  422. level of compession will be picked by the ``zlib`` module
  423. (which is generally acceptable).
  424. If `interlace` is true then an interlaced image is created
  425. (using PNG's so far only interace method, *Adam7*). This does
  426. not affect how the pixels should be presented to the encoder,
  427. rather it changes how they are arranged into the PNG file.
  428. On slow connexions interlaced images can be partially decoded
  429. by the browser to give a rough view of the image that is
  430. successively refined as more image data appears.
  431. .. note ::
  432. Enabling the `interlace` option requires the entire image
  433. to be processed in working memory.
  434. `chunk_limit` is used to limit the amount of memory used whilst
  435. compressing the image. In order to avoid using large amounts of
  436. memory, multiple ``IDAT`` chunks may be created.
  437. """
  438. # At the moment the `planes` argument is ignored;
  439. # its purpose is to act as a dummy so that
  440. # ``Writer(x, y, **info)`` works, where `info` is a dictionary
  441. # returned by Reader.read and friends.
  442. # Ditto for `colormap`.
  443. width, height = check_sizes(size, width, height)
  444. del size
  445. if width <= 0 or height <= 0:
  446. raise ValueError("width and height must be greater than zero")
  447. if not isinteger(width) or not isinteger(height):
  448. raise ValueError("width and height must be integers")
  449. # http://www.w3.org/TR/PNG/#7Integers-and-byte-order
  450. if width > 2**32-1 or height > 2**32-1:
  451. raise ValueError("width and height cannot exceed 2**32-1")
  452. if alpha and transparent is not None:
  453. raise ValueError(
  454. "transparent colour not allowed with alpha channel")
  455. if bytes_per_sample is not None:
  456. warnings.warn('please use bitdepth instead of bytes_per_sample',
  457. DeprecationWarning)
  458. if bytes_per_sample not in (0.125, 0.25, 0.5, 1, 2):
  459. raise ValueError(
  460. "bytes per sample must be .125, .25, .5, 1, or 2")
  461. bitdepth = int(8*bytes_per_sample)
  462. del bytes_per_sample
  463. if not isinteger(bitdepth) or bitdepth < 1 or 16 < bitdepth:
  464. raise ValueError("bitdepth (%r) must be a positive integer <= 16" %
  465. bitdepth)
  466. self.rescale = None
  467. palette = check_palette(palette)
  468. if palette:
  469. if bitdepth not in (1,2,4,8):
  470. raise ValueError("with palette, bitdepth must be 1, 2, 4, or 8")
  471. if transparent is not None:
  472. raise ValueError("transparent and palette not compatible")
  473. if alpha:
  474. raise ValueError("alpha and palette not compatible")
  475. if greyscale:
  476. raise ValueError("greyscale and palette not compatible")
  477. else:
  478. # No palette, check for sBIT chunk generation.
  479. if alpha or not greyscale:
  480. if bitdepth not in (8,16):
  481. targetbitdepth = (8,16)[bitdepth > 8]
  482. self.rescale = (bitdepth, targetbitdepth)
  483. bitdepth = targetbitdepth
  484. del targetbitdepth
  485. else:
  486. assert greyscale
  487. assert not alpha
  488. if bitdepth not in (1,2,4,8,16):
  489. if bitdepth > 8:
  490. targetbitdepth = 16
  491. elif bitdepth == 3:
  492. targetbitdepth = 4
  493. else:
  494. assert bitdepth in (5,6,7)
  495. targetbitdepth = 8
  496. self.rescale = (bitdepth, targetbitdepth)
  497. bitdepth = targetbitdepth
  498. del targetbitdepth
  499. if bitdepth < 8 and (alpha or not greyscale and not palette):
  500. raise ValueError(
  501. "bitdepth < 8 only permitted with greyscale or palette")
  502. if bitdepth > 8 and palette:
  503. raise ValueError(
  504. "bit depth must be 8 or less for images with palette")
  505. transparent = check_color(transparent, greyscale, 'transparent')
  506. background = check_color(background, greyscale, 'background')
  507. # It's important that the true boolean values (greyscale, alpha,
  508. # colormap, interlace) are converted to bool because Iverson's
  509. # convention is relied upon later on.
  510. self.width = width
  511. self.height = height
  512. self.transparent = transparent
  513. self.background = background
  514. self.gamma = gamma
  515. self.greyscale = bool(greyscale)
  516. self.alpha = bool(alpha)
  517. self.colormap = bool(palette)
  518. self.bitdepth = int(bitdepth)
  519. self.compression = compression
  520. self.chunk_limit = chunk_limit
  521. self.interlace = bool(interlace)
  522. self.palette = palette
  523. self.x_pixels_per_unit = x_pixels_per_unit
  524. self.y_pixels_per_unit = y_pixels_per_unit
  525. self.unit_is_meter = bool(unit_is_meter)
  526. self.color_type = 4*self.alpha + 2*(not greyscale) + 1*self.colormap
  527. assert self.color_type in (0,2,3,4,6)
  528. self.color_planes = (3,1)[self.greyscale or self.colormap]
  529. self.planes = self.color_planes + self.alpha
  530. # :todo: fix for bitdepth < 8
  531. self.psize = (self.bitdepth/8) * self.planes
  532. def make_palette(self):
  533. """Create the byte sequences for a ``PLTE`` and if necessary a
  534. ``tRNS`` chunk. Returned as a pair (*p*, *t*). *t* will be
  535. ``None`` if no ``tRNS`` chunk is necessary.
  536. """
  537. p = array('B')
  538. t = array('B')
  539. for x in self.palette:
  540. p.extend(x[0:3])
  541. if len(x) > 3:
  542. t.append(x[3])
  543. p = tostring(p)
  544. t = tostring(t)
  545. if t:
  546. return p,t
  547. return p,None
  548. def write(self, outfile, rows):
  549. """Write a PNG image to the output file. `rows` should be
  550. an iterable that yields each row in boxed row flat pixel
  551. format. The rows should be the rows of the original image,
  552. so there should be ``self.height`` rows of ``self.width *
  553. self.planes`` values. If `interlace` is specified (when
  554. creating the instance), then an interlaced PNG file will
  555. be written. Supply the rows in the normal image order;
  556. the interlacing is carried out internally.
  557. .. note ::
  558. Interlacing will require the entire image to be in working
  559. memory.
  560. """
  561. if self.interlace:
  562. fmt = 'BH'[self.bitdepth > 8]
  563. a = array(fmt, itertools.chain(*rows))
  564. return self.write_array(outfile, a)
  565. nrows = self.write_passes(outfile, rows)
  566. if nrows != self.height:
  567. raise ValueError(
  568. "rows supplied (%d) does not match height (%d)" %
  569. (nrows, self.height))
  570. def write_passes(self, outfile, rows, packed=False):
  571. """
  572. Write a PNG image to the output file.
  573. Most users are expected to find the :meth:`write` or
  574. :meth:`write_array` method more convenient.
  575. The rows should be given to this method in the order that
  576. they appear in the output file. For straightlaced images,
  577. this is the usual top to bottom ordering, but for interlaced
  578. images the rows should have already been interlaced before
  579. passing them to this function.
  580. `rows` should be an iterable that yields each row. When
  581. `packed` is ``False`` the rows should be in boxed row flat pixel
  582. format; when `packed` is ``True`` each row should be a packed
  583. sequence of bytes.
  584. """
  585. # http://www.w3.org/TR/PNG/#5PNG-file-signature
  586. outfile.write(_signature)
  587. # http://www.w3.org/TR/PNG/#11IHDR
  588. write_chunk(outfile, 'IHDR',
  589. struct.pack("!2I5B", self.width, self.height,
  590. self.bitdepth, self.color_type,
  591. 0, 0, self.interlace))
  592. # See :chunk:order
  593. # http://www.w3.org/TR/PNG/#11gAMA
  594. if self.gamma is not None:
  595. write_chunk(outfile, 'gAMA',
  596. struct.pack("!L", int(round(self.gamma*1e5))))
  597. # See :chunk:order
  598. # http://www.w3.org/TR/PNG/#11sBIT
  599. if self.rescale:
  600. write_chunk(outfile, 'sBIT',
  601. struct.pack('%dB' % self.planes,
  602. *[self.rescale[0]]*self.planes))
  603. # :chunk:order: Without a palette (PLTE chunk), ordering is
  604. # relatively relaxed. With one, gAMA chunk must precede PLTE
  605. # chunk which must precede tRNS and bKGD.
  606. # See http://www.w3.org/TR/PNG/#5ChunkOrdering
  607. if self.palette:
  608. p,t = self.make_palette()
  609. write_chunk(outfile, 'PLTE', p)
  610. if t:
  611. # tRNS chunk is optional. Only needed if palette entries
  612. # have alpha.
  613. write_chunk(outfile, 'tRNS', t)
  614. # http://www.w3.org/TR/PNG/#11tRNS
  615. if self.transparent is not None:
  616. if self.greyscale:
  617. write_chunk(outfile, 'tRNS',
  618. struct.pack("!1H", *self.transparent))
  619. else:
  620. write_chunk(outfile, 'tRNS',
  621. struct.pack("!3H", *self.transparent))
  622. # http://www.w3.org/TR/PNG/#11bKGD
  623. if self.background is not None:
  624. if self.greyscale:
  625. write_chunk(outfile, 'bKGD',
  626. struct.pack("!1H", *self.background))
  627. else:
  628. write_chunk(outfile, 'bKGD',
  629. struct.pack("!3H", *self.background))
  630. # http://www.w3.org/TR/PNG/#11pHYs
  631. if self.x_pixels_per_unit is not None and self.y_pixels_per_unit is not None:
  632. tup = (self.x_pixels_per_unit, self.y_pixels_per_unit, int(self.unit_is_meter))
  633. write_chunk(outfile, 'pHYs', struct.pack("!LLB",*tup))
  634. # http://www.w3.org/TR/PNG/#11IDAT
  635. if self.compression is not None:
  636. compressor = zlib.compressobj(self.compression)
  637. else:
  638. compressor = zlib.compressobj()
  639. # Choose an extend function based on the bitdepth. The extend
  640. # function packs/decomposes the pixel values into bytes and
  641. # stuffs them onto the data array.
  642. data = array('B')
  643. if self.bitdepth == 8 or packed:
  644. extend = data.extend
  645. elif self.bitdepth == 16:
  646. # Decompose into bytes
  647. def extend(sl):
  648. fmt = '!%dH' % len(sl)
  649. data.extend(array('B', struct.pack(fmt, *sl)))
  650. else:
  651. # Pack into bytes
  652. assert self.bitdepth < 8
  653. # samples per byte
  654. spb = int(8/self.bitdepth)
  655. def extend(sl):
  656. a = array('B', sl)
  657. # Adding padding bytes so we can group into a whole
  658. # number of spb-tuples.
  659. l = float(len(a))
  660. extra = math.ceil(l / float(spb))*spb - l
  661. a.extend([0]*int(extra))
  662. # Pack into bytes
  663. l = group(a, spb)
  664. l = map(lambda e: reduce(lambda x,y:
  665. (x << self.bitdepth) + y, e), l)
  666. data.extend(l)
  667. if self.rescale:
  668. oldextend = extend
  669. factor = \
  670. float(2**self.rescale[1]-1) / float(2**self.rescale[0]-1)
  671. def extend(sl):
  672. oldextend(map(lambda x: int(round(factor*x)), sl))
  673. # Build the first row, testing mostly to see if we need to
  674. # changed the extend function to cope with NumPy integer types
  675. # (they cause our ordinary definition of extend to fail, so we
  676. # wrap it). See
  677. # http://code.google.com/p/pypng/issues/detail?id=44
  678. enumrows = enumerate(rows)
  679. del rows
  680. # First row's filter type.
  681. data.append(0)
  682. # :todo: Certain exceptions in the call to ``.next()`` or the
  683. # following try would indicate no row data supplied.
  684. # Should catch.
  685. i,row = enumrows.next()
  686. try:
  687. # If this fails...
  688. extend(row)
  689. except:
  690. # ... try a version that converts the values to int first.
  691. # Not only does this work for the (slightly broken) NumPy
  692. # types, there are probably lots of other, unknown, "nearly"
  693. # int types it works for.
  694. def wrapmapint(f):
  695. return lambda sl: f(map(int, sl))
  696. extend = wrapmapint(extend)
  697. del wrapmapint
  698. extend(row)
  699. for i,row in enumrows:
  700. # Add "None" filter type. Currently, it's essential that
  701. # this filter type be used for every scanline as we do not
  702. # mark the first row of a reduced pass image; that means we
  703. # could accidentally compute the wrong filtered scanline if
  704. # we used "up", "average", or "paeth" on such a line.
  705. data.append(0)
  706. extend(row)
  707. if len(data) > self.chunk_limit:
  708. compressed = compressor.compress(tostring(data))
  709. if len(compressed):
  710. write_chunk(outfile, 'IDAT', compressed)
  711. # Because of our very witty definition of ``extend``,
  712. # above, we must re-use the same ``data`` object. Hence
  713. # we use ``del`` to empty this one, rather than create a
  714. # fresh one (which would be my natural FP instinct).
  715. del data[:]
  716. if len(data):
  717. compressed = compressor.compress(tostring(data))
  718. else:
  719. compressed = strtobytes('')
  720. flushed = compressor.flush()
  721. if len(compressed) or len(flushed):
  722. write_chunk(outfile, 'IDAT', compressed + flushed)
  723. # http://www.w3.org/TR/PNG/#11IEND
  724. write_chunk(outfile, 'IEND')
  725. return i+1
  726. def write_array(self, outfile, pixels):
  727. """
  728. Write an array in flat row flat pixel format as a PNG file on
  729. the output file. See also :meth:`write` method.
  730. """
  731. if self.interlace:
  732. self.write_passes(outfile, self.array_scanlines_interlace(pixels))
  733. else:
  734. self.write_passes(outfile, self.array_scanlines(pixels))
  735. def write_packed(self, outfile, rows):
  736. """
  737. Write PNG file to `outfile`. The pixel data comes from `rows`
  738. which should be in boxed row packed format. Each row should be
  739. a sequence of packed bytes.
  740. Technically, this method does work for interlaced images but it
  741. is best avoided. For interlaced images, the rows should be
  742. presented in the order that they appear in the file.
  743. This method should not be used when the source image bit depth
  744. is not one naturally supported by PNG; the bit depth should be
  745. 1, 2, 4, 8, or 16.
  746. """
  747. if self.rescale:
  748. raise Error("write_packed method not suitable for bit depth %d" %
  749. self.rescale[0])
  750. return self.write_passes(outfile, rows, packed=True)
  751. def convert_pnm(self, infile, outfile):
  752. """
  753. Convert a PNM file containing raw pixel data into a PNG file
  754. with the parameters set in the writer object. Works for
  755. (binary) PGM, PPM, and PAM formats.
  756. """
  757. if self.interlace:
  758. pixels = array('B')
  759. pixels.fromfile(infile,
  760. (self.bitdepth/8) * self.color_planes *
  761. self.width * self.height)
  762. self.write_passes(outfile, self.array_scanlines_interlace(pixels))
  763. else:
  764. self.write_passes(outfile, self.file_scanlines(infile))
  765. def convert_ppm_and_pgm(self, ppmfile, pgmfile, outfile):
  766. """
  767. Convert a PPM and PGM file containing raw pixel data into a
  768. PNG outfile with the parameters set in the writer object.
  769. """
  770. pixels = array('B')
  771. pixels.fromfile(ppmfile,
  772. (self.bitdepth/8) * self.color_planes *
  773. self.width * self.height)
  774. apixels = array('B')
  775. apixels.fromfile(pgmfile,
  776. (self.bitdepth/8) *
  777. self.width * self.height)
  778. pixels = interleave_planes(pixels, apixels,
  779. (self.bitdepth/8) * self.color_planes,
  780. (self.bitdepth/8))
  781. if self.interlace:
  782. self.write_passes(outfile, self.array_scanlines_interlace(pixels))
  783. else:
  784. self.write_passes(outfile, self.array_scanlines(pixels))
  785. def file_scanlines(self, infile):
  786. """
  787. Generates boxed rows in flat pixel format, from the input file
  788. `infile`. It assumes that the input file is in a "Netpbm-like"
  789. binary format, and is positioned at the beginning of the first
  790. pixel. The number of pixels to read is taken from the image
  791. dimensions (`width`, `height`, `planes`) and the number of bytes
  792. per value is implied by the image `bitdepth`.
  793. """
  794. # Values per row
  795. vpr = self.width * self.planes
  796. row_bytes = vpr
  797. if self.bitdepth > 8:
  798. assert self.bitdepth == 16
  799. row_bytes *= 2
  800. fmt = '>%dH' % vpr
  801. def line():
  802. return array('H', struct.unpack(fmt, infile.read(row_bytes)))
  803. else:
  804. def line():
  805. scanline = array('B', infile.read(row_bytes))
  806. return scanline
  807. for y in range(self.height):
  808. yield line()
  809. def array_scanlines(self, pixels):
  810. """
  811. Generates boxed rows (flat pixels) from flat rows (flat pixels)
  812. in an array.
  813. """
  814. # Values per row
  815. vpr = self.width * self.planes
  816. stop = 0
  817. for y in range(self.height):
  818. start = stop
  819. stop = start + vpr
  820. yield pixels[start:stop]
  821. def array_scanlines_interlace(self, pixels):
  822. """
  823. Generator for interlaced scanlines from an array. `pixels` is
  824. the full source image in flat row flat pixel format. The
  825. generator yields each scanline of the reduced passes in turn, in
  826. boxed row flat pixel format.
  827. """
  828. # http://www.w3.org/TR/PNG/#8InterlaceMethods
  829. # Array type.
  830. fmt = 'BH'[self.bitdepth > 8]
  831. # Value per row
  832. vpr = self.width * self.planes
  833. for xstart, ystart, xstep, ystep in _adam7:
  834. if xstart >= self.width:
  835. continue
  836. # Pixels per row (of reduced image)
  837. ppr = int(math.ceil((self.width-xstart)/float(xstep)))
  838. # number of values in reduced image row.
  839. row_len = ppr*self.planes
  840. for y in range(ystart, self.height, ystep):
  841. if xstep == 1:
  842. offset = y * vpr
  843. yield pixels[offset:offset+vpr]
  844. else:
  845. row = array(fmt)
  846. # There's no easier way to set the length of an array
  847. row.extend(pixels[0:row_len])
  848. offset = y * vpr + xstart * self.planes
  849. end_offset = (y+1) * vpr
  850. skip = self.planes * xstep
  851. for i in range(self.planes):
  852. row[i::self.planes] = \
  853. pixels[offset+i:end_offset:skip]
  854. yield row
  855. def write_chunk(outfile, tag, data=strtobytes('')):
  856. """
  857. Write a PNG chunk to the output file, including length and
  858. checksum.
  859. """
  860. # http://www.w3.org/TR/PNG/#5Chunk-layout
  861. outfile.write(struct.pack("!I", len(data)))
  862. tag = strtobytes(tag)
  863. outfile.write(tag)
  864. outfile.write(data)
  865. checksum = zlib.crc32(tag)
  866. checksum = zlib.crc32(data, checksum)
  867. checksum &= 2**32-1
  868. outfile.write(struct.pack("!I", checksum))
  869. def write_chunks(out, chunks):
  870. """Create a PNG file by writing out the chunks."""
  871. out.write(_signature)
  872. for chunk in chunks:
  873. write_chunk(out, *chunk)
  874. def filter_scanline(type, line, fo, prev=None):
  875. """Apply a scanline filter to a scanline. `type` specifies the
  876. filter type (0 to 4); `line` specifies the current (unfiltered)
  877. scanline as a sequence of bytes; `prev` specifies the previous
  878. (unfiltered) scanline as a sequence of bytes. `fo` specifies the
  879. filter offset; normally this is size of a pixel in bytes (the number
  880. of bytes per sample times the number of channels), but when this is
  881. < 1 (for bit depths < 8) then the filter offset is 1.
  882. """
  883. assert 0 <= type < 5
  884. # The output array. Which, pathetically, we extend one-byte at a
  885. # time (fortunately this is linear).
  886. out = array('B', [type])
  887. def sub():
  888. ai = -fo
  889. for x in line:
  890. if ai >= 0:
  891. x = (x - line[ai]) & 0xff
  892. out.append(x)
  893. ai += 1
  894. def up():
  895. for i,x in enumerate(line):
  896. x = (x - prev[i]) & 0xff
  897. out.append(x)
  898. def average():
  899. ai = -fo
  900. for i,x in enumerate(line):
  901. if ai >= 0:
  902. x = (x - ((line[ai] + prev[i]) >> 1)) & 0xff
  903. else:
  904. x = (x - (prev[i] >> 1)) & 0xff
  905. out.append(x)
  906. ai += 1
  907. def paeth():
  908. # http://www.w3.org/TR/PNG/#9Filter-type-4-Paeth
  909. ai = -fo # also used for ci
  910. for i,x in enumerate(line):
  911. a = 0
  912. b = prev[i]
  913. c = 0
  914. if ai >= 0:
  915. a = line[ai]
  916. c = prev[ai]
  917. p = a + b - c
  918. pa = abs(p - a)
  919. pb = abs(p - b)
  920. pc = abs(p - c)
  921. if pa <= pb and pa <= pc:
  922. Pr = a
  923. elif pb <= pc:
  924. Pr = b
  925. else:
  926. Pr = c
  927. x = (x - Pr) & 0xff
  928. out.append(x)
  929. ai += 1
  930. if not prev:
  931. # We're on the first line. Some of the filters can be reduced
  932. # to simpler cases which makes handling the line "off the top"
  933. # of the image simpler. "up" becomes "none"; "paeth" becomes
  934. # "left" (non-trivial, but true). "average" needs to be handled
  935. # specially.
  936. if type == 2: # "up"
  937. type = 0
  938. elif type == 3:
  939. prev = [0]*len(line)
  940. elif type == 4: # "paeth"
  941. type = 1
  942. if type == 0:
  943. out.extend(line)
  944. elif type == 1:
  945. sub()
  946. elif type == 2:
  947. up()
  948. elif type == 3:
  949. average()
  950. else: # type == 4
  951. paeth()
  952. return out
  953. def from_array(a, mode=None, info={}):
  954. """Create a PNG :class:`Image` object from a 2- or 3-dimensional
  955. array. One application of this function is easy PIL-style saving:
  956. ``png.from_array(pixels, 'L').save('foo.png')``.
  957. .. note :
  958. The use of the term *3-dimensional* is for marketing purposes
  959. only. It doesn't actually work. Please bear with us. Meanwhile
  960. enjoy the complimentary snacks (on request) and please use a
  961. 2-dimensional array.
  962. Unless they are specified using the *info* parameter, the PNG's
  963. height and width are taken from the array size. For a 3 dimensional
  964. array the first axis is the height; the second axis is the width;
  965. and the third axis is the channel number. Thus an RGB image that is
  966. 16 pixels high and 8 wide will use an array that is 16x8x3. For 2
  967. dimensional arrays the first axis is the height, but the second axis
  968. is ``width*channels``, so an RGB image that is 16 pixels high and 8
  969. wide will use a 2-dimensional array that is 16x24 (each row will be
  970. 8*3==24 sample values).
  971. *mode* is a string that specifies the image colour format in a
  972. PIL-style mode. It can be:
  973. ``'L'``
  974. greyscale (1 channel)
  975. ``'LA'``
  976. greyscale with alpha (2 channel)
  977. ``'RGB'``
  978. colour image (3 channel)
  979. ``'RGBA'``
  980. colour image with alpha (4 channel)
  981. The mode string can also specify the bit depth (overriding how this
  982. function normally derives the bit depth, see below). Appending
  983. ``';16'`` to the mode will cause the PNG to be 16 bits per channel;
  984. any decimal from 1 to 16 can be used to specify the bit depth.
  985. When a 2-dimensional array is used *mode* determines how many
  986. channels the image has, and so allows the width to be derived from
  987. the second array dimension.
  988. The array is expected to be a ``numpy`` array, but it can be any
  989. suitable Python sequence. For example, a list of lists can be used:
  990. ``png.from_array([[0, 255, 0], [255, 0, 255]], 'L')``. The exact
  991. rules are: ``len(a)`` gives the first dimension, height;
  992. ``len(a[0])`` gives the second dimension; ``len(a[0][0])`` gives the
  993. third dimension, unless an exception is raised in which case a
  994. 2-dimensional array is assumed. It's slightly more complicated than
  995. that because an iterator of rows can be used, and it all still
  996. works. Using an iterator allows data to be streamed efficiently.
  997. The bit depth of the PNG is normally taken from the array element's
  998. datatype (but if *mode* specifies a bitdepth then that is used
  999. instead). The array element's datatype is determined in a way which
  1000. is supposed to work both for ``numpy`` arrays and for Python
  1001. ``array.array`` objects. A 1 byte datatype will give a bit depth of
  1002. 8, a 2 byte datatype will give a bit depth of 16. If the datatype
  1003. does not have an implicit size, for example it is a plain Python
  1004. list of lists, as above, then a default of 8 is used.
  1005. The *info* parameter is a dictionary that can be used to specify
  1006. metadata (in the same style as the arguments to the
  1007. :class:``png.Writer`` class). For this function the keys that are
  1008. useful are:
  1009. height
  1010. overrides the height derived from the array dimensions and allows
  1011. *a* to be an iterable.
  1012. width
  1013. overrides the width derived from the array dimensions.
  1014. bitdepth
  1015. overrides the bit depth derived from the element datatype (but
  1016. must match *mode* if that also specifies a bit depth).
  1017. Generally anything specified in the
  1018. *info* dictionary will override any implicit choices that this
  1019. function would otherwise make, but must match any explicit ones.
  1020. For example, if the *info* dictionary has a ``greyscale`` key then
  1021. this must be true when mode is ``'L'`` or ``'LA'`` and false when
  1022. mode is ``'RGB'`` or ``'RGBA'``.
  1023. """
  1024. # We abuse the *info* parameter by modifying it. Take a copy here.
  1025. # (Also typechecks *info* to some extent).
  1026. info = dict(info)
  1027. # Syntax check mode string.
  1028. bitdepth = None
  1029. try:
  1030. # Assign the 'L' or 'RGBA' part to `gotmode`.
  1031. if mode.startswith('L'):
  1032. gotmode = 'L'
  1033. mode = mode[1:]
  1034. elif mode.startswith('RGB'):
  1035. gotmode = 'RGB'
  1036. mode = mode[3:]
  1037. else:
  1038. raise Error()
  1039. if mode.startswith('A'):
  1040. gotmode += 'A'
  1041. mode = mode[1:]
  1042. # Skip any optional ';'
  1043. while mode.startswith(';'):
  1044. mode = mode[1:]
  1045. # Parse optional bitdepth
  1046. if mode:
  1047. try:
  1048. bitdepth = int(mode)
  1049. except (TypeError, ValueError):
  1050. raise Error()
  1051. except Error:
  1052. raise Error("mode string should be 'RGB' or 'L;16' or similar.")
  1053. mode = gotmode
  1054. # Get bitdepth from *mode* if possible.
  1055. if bitdepth:
  1056. if info.get('bitdepth') and bitdepth != info['bitdepth']:
  1057. raise Error("mode bitdepth (%d) should match info bitdepth (%d)." %
  1058. (bitdepth, info['bitdepth']))
  1059. info['bitdepth'] = bitdepth
  1060. # Fill in and/or check entries in *info*.
  1061. # Dimensions.
  1062. if 'size' in info:
  1063. # Check width, height, size all match where used.
  1064. for dimension,axis in [('width', 0), ('height', 1)]:
  1065. if dimension in info:
  1066. if info[dimension] != info['size'][axis]:
  1067. raise Error(
  1068. "info[%r] should match info['size'][%r]." %
  1069. (dimension, axis))
  1070. info['width'],info['height'] = info['size']
  1071. if 'height' not in info:
  1072. try:
  1073. l = len(a)
  1074. except TypeError:
  1075. raise Error(
  1076. "len(a) does not work, supply info['height'] instead.")
  1077. info['height'] = l
  1078. # Colour format.
  1079. if 'greyscale' in info:
  1080. if bool(info['greyscale']) != ('L' in mode):
  1081. raise Error("info['greyscale'] should match mode.")
  1082. info['greyscale'] = 'L' in mode
  1083. if 'alpha' in info:
  1084. if bool(info['alpha']) != ('A' in mode):
  1085. raise Error("info['alpha'] should match mode.")
  1086. info['alpha'] = 'A' in mode
  1087. planes = len(mode)
  1088. if 'planes' in info:
  1089. if info['planes'] != planes:
  1090. raise Error("info['planes'] should match mode.")
  1091. # In order to work out whether we the array is 2D or 3D we need its
  1092. # first row, which requires that we take a copy of its iterator.
  1093. # We may also need the first row to derive width and bitdepth.
  1094. a,t = itertools.tee(a)
  1095. row = t.next()
  1096. del t
  1097. try:
  1098. row[0][0]
  1099. threed = True
  1100. testelement = row[0]
  1101. except (IndexError, TypeError):
  1102. threed = False
  1103. testelement = row
  1104. if 'width' not in info:
  1105. if threed:
  1106. width = len(row)
  1107. else:
  1108. width = len(row) // planes
  1109. info['width'] = width
  1110. if threed:
  1111. # Flatten the threed rows
  1112. a = (itertools.chain.from_iterable(x) for x in a)
  1113. if 'bitdepth' not in info:
  1114. try:
  1115. dtype = testelement.dtype
  1116. # goto the "else:" clause. Sorry.
  1117. except AttributeError:
  1118. try:
  1119. # Try a Python array.array.
  1120. bitdepth = 8 * testelement.itemsize
  1121. except AttributeError:
  1122. # We can't determine it from the array element's
  1123. # datatype, use a default of 8.
  1124. bitdepth = 8
  1125. else:
  1126. # If we got here without exception, we now assume that
  1127. # the array is a numpy array.
  1128. if dtype.kind == 'b':
  1129. bitdepth = 1
  1130. else:
  1131. bitdepth = 8 * dtype.itemsize
  1132. info['bitdepth'] = bitdepth
  1133. for thing in 'width height bitdepth greyscale alpha'.split():
  1134. assert thing in info
  1135. return Image(a, info)
  1136. # So that refugee's from PIL feel more at home. Not documented.
  1137. fromarray = from_array
  1138. class Image:
  1139. """A PNG image. You can create an :class:`Image` object from
  1140. an array of pixels by calling :meth:`png.from_array`. It can be
  1141. saved to disk with the :meth:`save` method.
  1142. """
  1143. def __init__(self, rows, info):
  1144. """
  1145. .. note ::
  1146. The constructor is not public. Please do not call it.
  1147. """
  1148. self.rows = rows
  1149. self.info = info
  1150. def save(self, file):
  1151. """Save the image to *file*. If *file* looks like an open file
  1152. descriptor then it is used, otherwise it is treated as a
  1153. filename and a fresh file is opened.
  1154. In general, you can only call this method once; after it has
  1155. been called the first time and the PNG image has been saved, the
  1156. source data will have been streamed, and cannot be streamed
  1157. again.
  1158. """
  1159. w = Writer(**self.info)
  1160. try:
  1161. file.write
  1162. def close(): pass
  1163. except AttributeError:
  1164. file = open(file, 'wb')
  1165. def close(): file.close()
  1166. try:
  1167. w.write(file, self.rows)
  1168. finally:
  1169. close()
  1170. class _readable:
  1171. """
  1172. A simple file-like interface for strings and arrays.
  1173. """
  1174. def __init__(self, buf):
  1175. self.buf = buf
  1176. self.offset = 0
  1177. def read(self, n):
  1178. r = self.buf[self.offset:self.offset+n]
  1179. if isarray(r):
  1180. r = r.tostring()
  1181. self.offset += n
  1182. return r
  1183. class Reader:
  1184. """
  1185. PNG decoder in pure Python.
  1186. """
  1187. def __init__(self, _guess=None, **kw):
  1188. """
  1189. Create a PNG decoder object.
  1190. The constructor expects exactly one keyword argument. If you
  1191. supply a positional argument instead, it will guess the input
  1192. type. You can choose among the following keyword arguments:
  1193. filename
  1194. Name of input file (a PNG file).
  1195. file
  1196. A file-like object (object with a read() method).
  1197. bytes
  1198. ``array`` or ``string`` with PNG data.
  1199. """
  1200. if ((_guess is not None and len(kw) != 0) or
  1201. (_guess is None and len(kw) != 1)):
  1202. raise TypeError("Reader() takes exactly 1 argument")
  1203. # Will be the first 8 bytes, later on. See validate_signature.
  1204. self.signature = None
  1205. self.transparent = None
  1206. # A pair of (len,type) if a chunk has been read but its data and
  1207. # checksum have not (in other words the file position is just
  1208. # past the 4 bytes that specify the chunk type). See preamble
  1209. # method for how this is used.
  1210. self.atchunk = None
  1211. if _guess is not None:
  1212. if isarray(_guess):
  1213. kw["bytes"] = _guess
  1214. elif isinstance(_guess, str):
  1215. kw["filename"] = _guess
  1216. elif hasattr(_guess, 'read'):
  1217. kw["file"] = _guess
  1218. if "filename" in kw:
  1219. self.file = open(kw["filename"], "rb")
  1220. elif "file" in kw:
  1221. self.file = kw["file"]
  1222. elif "bytes" in kw:
  1223. self.file = _readable(kw["bytes"])
  1224. else:
  1225. raise TypeError("expecting filename, file or bytes array")
  1226. def chunk(self, seek=None, lenient=False):
  1227. """
  1228. Read the next PNG chunk from the input file; returns a
  1229. (*type*,*data*) tuple. *type* is the chunk's type as a string
  1230. (all PNG chunk types are 4 characters long). *data* is the
  1231. chunk's data content, as a string.
  1232. If the optional `seek` argument is
  1233. specified then it will keep reading chunks until it either runs
  1234. out of file or finds the type specified by the argument. Note
  1235. that in general the order of chunks in PNGs is unspecified, so
  1236. using `seek` can cause you to miss chunks.
  1237. If the optional `lenient` argument evaluates to True,
  1238. checksum failures will raise warnings rather than exceptions.
  1239. """
  1240. self.validate_signature()
  1241. while True:
  1242. # http://www.w3.org/TR/PNG/#5Chunk-layout
  1243. if not self.atchunk:
  1244. self.atchunk = self.chunklentype()
  1245. length,type = self.atchunk
  1246. self.atchunk = None
  1247. data = self.file.read(length)
  1248. if len(data) != length:
  1249. raise ChunkError('Chunk %s too short for required %i octets.'
  1250. % (type, length))
  1251. checksum = self.file.read(4)
  1252. if len(checksum) != 4:
  1253. raise ChunkError('Chunk %s too short for checksum.' % type)
  1254. if seek and type != seek:
  1255. continue
  1256. verify = zlib.crc32(strtobytes(type))
  1257. verify = zlib.crc32(data, verify)
  1258. # Whether the output from zlib.crc32 is signed or not varies
  1259. # according to hideous implementation details, see
  1260. # http://bugs.python.org/issue1202 .
  1261. # We coerce it to be positive here (in a way which works on
  1262. # Python 2.3 and older).
  1263. verify &= 2**32 - 1
  1264. verify = struct.pack('!I', verify)
  1265. if checksum != verify:
  1266. (a, ) = struct.unpack('!I', checksum)
  1267. (b, ) = struct.unpack('!I', verify)
  1268. message = "Checksum error in %s chunk: 0x%08X != 0x%08X." % (type, a, b)
  1269. if lenient:
  1270. warnings.warn(message, RuntimeWarning)
  1271. else:
  1272. raise ChunkError(message)
  1273. return type, data
  1274. def chunks(self):
  1275. """Return an iterator that will yield each chunk as a
  1276. (*chunktype*, *content*) pair.
  1277. """
  1278. while True:
  1279. t,v = self.chunk()
  1280. yield t,v
  1281. if t == 'IEND':
  1282. break
  1283. def undo_filter(self, filter_type, scanline, previous):
  1284. """Undo the filter for a scanline. `scanline` is a sequence of
  1285. bytes that does not include the initial filter type byte.
  1286. `previous` is decoded previous scanline (for straightlaced
  1287. images this is the previous pixel row, but for interlaced
  1288. images, it is the previous scanline in the reduced image, which
  1289. in general is not the previous pixel row in the final image).
  1290. When there is no previous scanline (the first row of a
  1291. straightlaced image, or the first row in one of the passes in an
  1292. interlaced image), then this argument should be ``None``.
  1293. The scanline will have the effects of filtering removed, and the
  1294. result will be returned as a fresh sequence of bytes.
  1295. """
  1296. # :todo: Would it be better to update scanline in place?
  1297. # Yes, with the Cython extension making the undo_filter fast,
  1298. # updating scanline inplace makes the code 3 times faster
  1299. # (reading 50 images of 800x800 went from 40s to 16s)
  1300. result = scanline
  1301. if filter_type == 0:
  1302. return result
  1303. if filter_type not in (1,2,3,4):
  1304. raise FormatError('Invalid PNG Filter Type.'
  1305. ' See http://www.w3.org/TR/2003/REC-PNG-20031110/#9Filters .')
  1306. # Filter unit. The stride from one pixel to the corresponding
  1307. # byte from the previous pixel. Normally this is the pixel
  1308. # size in bytes, but when this is smaller than 1, the previous
  1309. # byte is used instead.
  1310. fu = max(1, self.psize)
  1311. # For the first line of a pass, synthesize a dummy previous
  1312. # line. An alternative approach would be to observe that on the
  1313. # first line 'up' is the same as 'null', 'paeth' is the same
  1314. # as 'sub', with only 'average' requiring any special case.
  1315. if not previous:
  1316. previous = array('B', [0]*len(scanline))
  1317. def sub():
  1318. """Undo sub filter."""
  1319. ai = 0
  1320. # Loop starts at index fu. Observe that the initial part
  1321. # of the result is already filled in correctly with
  1322. # scanline.
  1323. for i in range(fu, len(result)):
  1324. x = scanline[i]
  1325. a = result[ai]
  1326. result[i] = (x + a) & 0xff
  1327. ai += 1
  1328. def up():
  1329. """Undo up filter."""
  1330. for i in range(len(result)):
  1331. x = scanline[i]
  1332. b = previous[i]
  1333. result[i] = (x + b) & 0xff
  1334. def average():
  1335. """Undo average filter."""
  1336. ai = -fu
  1337. for i in range(len(result)):
  1338. x = scanline[i]
  1339. if ai < 0:
  1340. a = 0
  1341. else:
  1342. a = result[ai]
  1343. b = previous[i]
  1344. result[i] = (x + ((a + b) >> 1)) & 0xff
  1345. ai += 1
  1346. def paeth():
  1347. """Undo Paeth filter."""
  1348. # Also used for ci.
  1349. ai = -fu
  1350. for i in range(len(result)):
  1351. x = scanline[i]
  1352. if ai < 0:
  1353. a = c = 0
  1354. else:
  1355. a = result[ai]
  1356. c = previous[ai]
  1357. b = previous[i]
  1358. p = a + b - c
  1359. pa = abs(p - a)
  1360. pb = abs(p - b)
  1361. pc = abs(p - c)
  1362. if pa <= pb and pa <= pc:
  1363. pr = a
  1364. elif pb <= pc:
  1365. pr = b
  1366. else:
  1367. pr = c
  1368. result[i] = (x + pr) & 0xff
  1369. ai += 1
  1370. # Call appropriate filter algorithm. Note that 0 has already
  1371. # been dealt with.
  1372. (None,
  1373. pngfilters.undo_filter_sub,
  1374. pngfilters.undo_filter_up,
  1375. pngfilters.undo_filter_average,
  1376. pngfilters.undo_filter_paeth)[filter_type](fu, scanline, previous, result)
  1377. return result
  1378. def deinterlace(self, raw):
  1379. """
  1380. Read raw pixel data, undo filters, deinterlace, and flatten.
  1381. Return in flat row flat pixel format.
  1382. """
  1383. # Values per row (of the target image)
  1384. vpr = self.width * self.planes
  1385. # Make a result array, and make it big enough. Interleaving
  1386. # writes to the output array randomly (well, not quite), so the
  1387. # entire output array must be in memory.
  1388. fmt = 'BH'[self.bitdepth > 8]
  1389. a = array(fmt, [0]*vpr*self.height)
  1390. source_offset = 0
  1391. for xstart, ystart, xstep, ystep in _adam7:
  1392. if xstart >= self.width:
  1393. continue
  1394. # The previous (reconstructed) scanline. None at the
  1395. # beginning of a pass to indicate that there is no previous
  1396. # line.
  1397. recon = None
  1398. # Pixels per row (reduced pass image)
  1399. ppr = int(math.ceil((self.width-xstart)/float(xstep)))
  1400. # Row size in bytes for this pass.
  1401. row_size = int(math.ceil(self.psize * ppr))
  1402. for y in range(ystart, self.height, ystep):
  1403. filter_type = raw[source_offset]
  1404. source_offset += 1
  1405. scanline = raw[source_offset:source_offset+row_size]
  1406. source_offset += row_size
  1407. recon = self.undo_filter(filter_type, scanline, recon)
  1408. # Convert so that there is one element per pixel value
  1409. flat = self.serialtoflat(recon, ppr)
  1410. if xstep == 1:
  1411. assert xstart == 0
  1412. offset = y * vpr
  1413. a[offset:offset+vpr] = flat
  1414. else:
  1415. offset = y * vpr + xstart * self.planes
  1416. end_offset = (y+1) * vpr
  1417. skip = self.planes * xstep
  1418. for i in range(self.planes):
  1419. a[offset+i:end_offset:skip] = \
  1420. flat[i::self.planes]
  1421. return a
  1422. def iterboxed(self, rows):
  1423. """Iterator that yields each scanline in boxed row flat pixel
  1424. format. `rows` should be an iterator that yields the bytes of
  1425. each row in turn.
  1426. """
  1427. def asvalues(raw):
  1428. """Convert a row of raw bytes into a flat row. Result will
  1429. be a freshly allocated object, not shared with
  1430. argument.
  1431. """
  1432. if self.bitdepth == 8:
  1433. return array('B', raw)
  1434. if self.bitdepth == 16:
  1435. raw = tostring(raw)
  1436. return array('H', struct.unpack('!%dH' % (len(raw)//2), raw))
  1437. assert self.bitdepth < 8
  1438. width = self.width
  1439. # Samples per byte
  1440. spb = 8//self.bitdepth
  1441. out = array('B')
  1442. mask = 2**self.bitdepth - 1
  1443. shifts = map(self.bitdepth.__mul__, reversed(range(spb)))
  1444. for o in raw:
  1445. out.extend(map(lambda i: mask&(o>>i), shifts))
  1446. return out[:width]
  1447. return itertools.imap(asvalues, rows)
  1448. def serialtoflat(self, bytes, width=None):
  1449. """Convert serial format (byte stream) pixel data to flat row
  1450. flat pixel.
  1451. """
  1452. if self.bitdepth == 8:
  1453. return bytes
  1454. if self.bitdepth == 16:
  1455. bytes = tostring(bytes)
  1456. return array('H',
  1457. struct.unpack('!%dH' % (len(bytes)//2), bytes))
  1458. assert self.bitdepth < 8
  1459. if width is None:
  1460. width = self.width
  1461. # Samples per byte
  1462. spb = 8//self.bitdepth
  1463. out = array('B')
  1464. mask = 2**self.bitdepth - 1
  1465. shifts = map(self.bitdepth.__mul__, reversed(range(spb)))
  1466. l = width
  1467. for o in bytes:
  1468. out.extend([(mask&(o>>s)) for s in shifts][:l])
  1469. l -= spb
  1470. if l <= 0:
  1471. l = width
  1472. return out
  1473. def iterstraight(self, raw):
  1474. """Iterator that undoes the effect of filtering, and yields
  1475. each row in serialised format (as a sequence of bytes).
  1476. Assumes input is straightlaced. `raw` should be an iterable
  1477. that yields the raw bytes in chunks of arbitrary size.
  1478. """
  1479. # length of row, in bytes
  1480. rb = self.row_bytes
  1481. a = array('B')
  1482. # The previous (reconstructed) scanline. None indicates first
  1483. # line of image.
  1484. recon = None
  1485. for some in raw:
  1486. a.extend(some)
  1487. while len(a) >= rb + 1:
  1488. filter_type = a[0]
  1489. scanline = a[1:rb+1]
  1490. del a[:rb+1]
  1491. recon = self.undo_filter(filter_type, scanline, recon)
  1492. yield recon
  1493. if len(a) != 0:
  1494. # :file:format We get here with a file format error:
  1495. # when the available bytes (after decompressing) do not
  1496. # pack into exact rows.
  1497. raise FormatError(
  1498. 'Wrong size for decompressed IDAT chunk.')
  1499. assert len(a) == 0
  1500. def validate_signature(self):
  1501. """If signature (header) has not been read then read and
  1502. validate it; otherwise do nothing.
  1503. """
  1504. if self.signature:
  1505. return
  1506. self.signature = self.file.read(8)
  1507. if self.signature != _signature:
  1508. raise FormatError("PNG file has invalid signature.")
  1509. def preamble(self, lenient=False):
  1510. """
  1511. Extract the image metadata by reading the initial part of
  1512. the PNG file up to the start of the ``IDAT`` chunk. All the
  1513. chunks that precede the ``IDAT`` chunk are read and either
  1514. processed for metadata or discarded.
  1515. If the optional `lenient` argument evaluates to True, checksum
  1516. failures will raise warnings rather than exceptions.
  1517. """
  1518. self.validate_signature()
  1519. while True:
  1520. if not self.atchunk:
  1521. self.atchunk = self.chunklentype()
  1522. if self.atchunk is None:
  1523. raise FormatError(
  1524. 'This PNG file has no IDAT chunks.')
  1525. if self.atchunk[1] == 'IDAT':
  1526. return
  1527. self.process_chunk(lenient=lenient)
  1528. def chunklentype(self):
  1529. """Reads just enough of the input to determine the next
  1530. chunk's length and type, returned as a (*length*, *type*) pair
  1531. where *type* is a string. If there are no more chunks, ``None``
  1532. is returned.
  1533. """
  1534. x = self.file.read(8)
  1535. if not x:
  1536. return None
  1537. if len(x) != 8:
  1538. raise FormatError(
  1539. 'End of file whilst reading chunk length and type.')
  1540. length,type = struct.unpack('!I4s', x)
  1541. type = bytestostr(type)
  1542. if length > 2**31-1:
  1543. raise FormatError('Chunk %s is too large: %d.' % (type,length))
  1544. return length,type
  1545. def process_chunk(self, lenient=False):
  1546. """Process the next chunk and its data. This only processes the
  1547. following chunk types, all others are ignored: ``IHDR``,
  1548. ``PLTE``, ``bKGD``, ``tRNS``, ``gAMA``, ``sBIT``, ``pHYs``.
  1549. If the optional `lenient` argument evaluates to True,
  1550. checksum failures will raise warnings rather than exceptions.
  1551. """
  1552. type, data = self.chunk(lenient=lenient)
  1553. method = '_process_' + type
  1554. m = getattr(self, method, None)
  1555. if m:
  1556. m(data)
  1557. def _process_IHDR(self, data):
  1558. # http://www.w3.org/TR/PNG/#11IHDR
  1559. if len(data) != 13:
  1560. raise FormatError('IHDR chunk has incorrect length.')
  1561. (self.width, self.height, self.bitdepth, self.color_type,
  1562. self.compression, self.filter,
  1563. self.interlace) = struct.unpack("!2I5B", data)
  1564. check_bitdepth_colortype(self.bitdepth, self.color_type)
  1565. if self.compression != 0:
  1566. raise Error("unknown compression method %d" % self.compression)
  1567. if self.filter != 0:
  1568. raise FormatError("Unknown filter method %d,"
  1569. " see http://www.w3.org/TR/2003/REC-PNG-20031110/#9Filters ."
  1570. % self.filter)
  1571. if self.interlace not in (0,1):
  1572. raise FormatError("Unknown interlace method %d,"
  1573. " see http://www.w3.org/TR/2003/REC-PNG-20031110/#8InterlaceMethods ."
  1574. % self.interlace)
  1575. # Derived values
  1576. # http://www.w3.org/TR/PNG/#6Colour-values
  1577. colormap = bool(self.color_type & 1)
  1578. greyscale = not (self.color_type & 2)
  1579. alpha = bool(self.color_type & 4)
  1580. color_planes = (3,1)[greyscale or colormap]
  1581. planes = color_planes + alpha
  1582. self.colormap = colormap
  1583. self.greyscale = greyscale
  1584. self.alpha = alpha
  1585. self.color_planes = color_planes
  1586. self.planes = planes
  1587. self.psize = float(self.bitdepth)/float(8) * planes
  1588. if int(self.psize) == self.psize:
  1589. self.psize = int(self.psize)
  1590. self.row_bytes = int(math.ceil(self.width * self.psize))
  1591. # Stores PLTE chunk if present, and is used to check
  1592. # chunk ordering constraints.
  1593. self.plte = None
  1594. # Stores tRNS chunk if present, and is used to check chunk
  1595. # ordering constraints.
  1596. self.trns = None
  1597. # Stores sbit chunk if present.
  1598. self.sbit = None
  1599. def _process_PLTE(self, data):
  1600. # http://www.w3.org/TR/PNG/#11PLTE
  1601. if self.plte:
  1602. warnings.warn("Multiple PLTE chunks present.")
  1603. self.plte = data
  1604. if len(data) % 3 != 0:
  1605. raise FormatError(
  1606. "PLTE chunk's length should be a multiple of 3.")
  1607. if len(data) > (2**self.bitdepth)*3:
  1608. raise FormatError("PLTE chunk is too long.")
  1609. if len(data) == 0:
  1610. raise FormatError("Empty PLTE is not allowed.")
  1611. def _process_bKGD(self, data):
  1612. try:
  1613. if self.colormap:
  1614. if not self.plte:
  1615. warnings.warn(
  1616. "PLTE chunk is required before bKGD chunk.")
  1617. self.background = struct.unpack('B', data)
  1618. else:
  1619. self.background = struct.unpack("!%dH" % self.color_planes,
  1620. data)
  1621. except struct.error:
  1622. raise FormatError("bKGD chunk has incorrect length.")
  1623. def _process_tRNS(self, data):
  1624. # http://www.w3.org/TR/PNG/#11tRNS
  1625. self.trns = data
  1626. if self.colormap:
  1627. if not self.plte:
  1628. warnings.warn("PLTE chunk is required before tRNS chunk.")
  1629. else:
  1630. if len(data) > len(self.plte)/3:
  1631. # Was warning, but promoted to Error as it
  1632. # would otherwise cause pain later on.
  1633. raise FormatError("tRNS chunk is too long.")
  1634. else:
  1635. if self.alpha:
  1636. raise FormatError(
  1637. "tRNS chunk is not valid with colour type %d." %
  1638. self.color_type)
  1639. try:
  1640. self.transparent = \
  1641. struct.unpack("!%dH" % self.color_planes, data)
  1642. except struct.error:
  1643. raise FormatError("tRNS chunk has incorrect length.")
  1644. def _process_gAMA(self, data):
  1645. try:
  1646. self.gamma = struct.unpack("!L", data)[0] / 100000.0
  1647. except struct.error:
  1648. raise FormatError("gAMA chunk has incorrect length.")
  1649. def _process_sBIT(self, data):
  1650. self.sbit = data
  1651. if (self.colormap and len(data) != 3 or
  1652. not self.colormap and len(data) != self.planes):
  1653. raise FormatError("sBIT chunk has incorrect length.")
  1654. def _process_pHYs(self, data):
  1655. # http://www.w3.org/TR/PNG/#11pHYs
  1656. self.phys = data
  1657. fmt = "!LLB"
  1658. if len(data) != struct.calcsize(fmt):
  1659. raise FormatError("pHYs chunk has incorrect length.")
  1660. self.x_pixels_per_unit, self.y_pixels_per_unit, unit = struct.unpack(fmt,data)
  1661. self.unit_is_meter = bool(unit)
  1662. def read(self, lenient=False):
  1663. """
  1664. Read the PNG file and decode it. Returns (`width`, `height`,
  1665. `pixels`, `metadata`).
  1666. May use excessive memory.
  1667. `pixels` are returned in boxed row flat pixel format.
  1668. If the optional `lenient` argument evaluates to True,
  1669. checksum failures will raise warnings rather than exceptions.
  1670. """
  1671. def iteridat():
  1672. """Iterator that yields all the ``IDAT`` chunks as strings."""
  1673. while True:
  1674. try:
  1675. type, data = self.chunk(lenient=lenient)
  1676. except ValueError, e:
  1677. raise ChunkError(e.args[0])
  1678. if type == 'IEND':
  1679. # http://www.w3.org/TR/PNG/#11IEND
  1680. break
  1681. if type != 'IDAT':
  1682. continue
  1683. # type == 'IDAT'
  1684. # http://www.w3.org/TR/PNG/#11IDAT
  1685. if self.colormap and not self.plte:
  1686. warnings.warn("PLTE chunk is required before IDAT chunk")
  1687. yield data
  1688. def iterdecomp(idat):
  1689. """Iterator that yields decompressed strings. `idat` should
  1690. be an iterator that yields the ``IDAT`` chunk data.
  1691. """
  1692. # Currently, with no max_length parameter to decompress,
  1693. # this routine will do one yield per IDAT chunk: Not very
  1694. # incremental.
  1695. d = zlib.decompressobj()
  1696. # Each IDAT chunk is passed to the decompressor, then any
  1697. # remaining state is decompressed out.
  1698. for data in idat:
  1699. # :todo: add a max_length argument here to limit output
  1700. # size.
  1701. yield array('B', d.decompress(data))
  1702. yield array('B', d.flush())
  1703. self.preamble(lenient=lenient)
  1704. raw = iterdecomp(iteridat())
  1705. if self.interlace:
  1706. raw = array('B', itertools.chain(*raw))
  1707. arraycode = 'BH'[self.bitdepth>8]
  1708. # Like :meth:`group` but producing an array.array object for
  1709. # each row.
  1710. pixels = itertools.imap(lambda *row: array(arraycode, row),
  1711. *[iter(self.deinterlace(raw))]*self.width*self.planes)
  1712. else:
  1713. pixels = self.iterboxed(self.iterstraight(raw))
  1714. meta = dict()
  1715. for attr in 'greyscale alpha planes bitdepth interlace'.split():
  1716. meta[attr] = getattr(self, attr)
  1717. meta['size'] = (self.width, self.height)
  1718. for attr in 'gamma transparent background'.split():
  1719. a = getattr(self, attr, None)
  1720. if a is not None:
  1721. meta[attr] = a
  1722. if self.plte:
  1723. meta['palette'] = self.palette()
  1724. return self.width, self.height, pixels, meta
  1725. def read_flat(self):
  1726. """
  1727. Read a PNG file and decode it into flat row flat pixel format.
  1728. Returns (*width*, *height*, *pixels*, *metadata*).
  1729. May use excessive memory.
  1730. `pixels` are returned in flat row flat pixel format.
  1731. See also the :meth:`read` method which returns pixels in the
  1732. more stream-friendly boxed row flat pixel format.
  1733. """
  1734. x, y, pixel, meta = self.read()
  1735. arraycode = 'BH'[meta['bitdepth']>8]
  1736. pixel = array(arraycode, itertools.chain(*pixel))
  1737. return x, y, pixel, meta
  1738. def palette(self, alpha='natural'):
  1739. """Returns a palette that is a sequence of 3-tuples or 4-tuples,
  1740. synthesizing it from the ``PLTE`` and ``tRNS`` chunks. These
  1741. chunks should have already been processed (for example, by
  1742. calling the :meth:`preamble` method). All the tuples are the
  1743. same size: 3-tuples if there is no ``tRNS`` chunk, 4-tuples when
  1744. there is a ``tRNS`` chunk. Assumes that the image is colour type
  1745. 3 and therefore a ``PLTE`` chunk is required.
  1746. If the `alpha` argument is ``'force'`` then an alpha channel is
  1747. always added, forcing the result to be a sequence of 4-tuples.
  1748. """
  1749. if not self.plte:
  1750. raise FormatError(
  1751. "Required PLTE chunk is missing in colour type 3 image.")
  1752. plte = group(array('B', self.plte), 3)
  1753. if self.trns or alpha == 'force':
  1754. trns = array('B', self.trns or '')
  1755. trns.extend([255]*(len(plte)-len(trns)))
  1756. plte = map(operator.add, plte, group(trns, 1))
  1757. return plte
  1758. def asDirect(self):
  1759. """Returns the image data as a direct representation of an
  1760. ``x * y * planes`` array. This method is intended to remove the
  1761. need for callers to deal with palettes and transparency
  1762. themselves. Images with a palette (colour type 3)
  1763. are converted to RGB or RGBA; images with transparency (a
  1764. ``tRNS`` chunk) are converted to LA or RGBA as appropriate.
  1765. When returned in this format the pixel values represent the
  1766. colour value directly without needing to refer to palettes or
  1767. transparency information.
  1768. Like the :meth:`read` method this method returns a 4-tuple:
  1769. (*width*, *height*, *pixels*, *meta*)
  1770. This method normally returns pixel values with the bit depth
  1771. they have in the source image, but when the source PNG has an
  1772. ``sBIT`` chunk it is inspected and can reduce the bit depth of
  1773. the result pixels; pixel values will be reduced according to
  1774. the bit depth specified in the ``sBIT`` chunk (PNG nerds should
  1775. note a single result bit depth is used for all channels; the
  1776. maximum of the ones specified in the ``sBIT`` chunk. An RGB565
  1777. image will be rescaled to 6-bit RGB666).
  1778. The *meta* dictionary that is returned reflects the `direct`
  1779. format and not the original source image. For example, an RGB
  1780. source image with a ``tRNS`` chunk to represent a transparent
  1781. colour, will have ``planes=3`` and ``alpha=False`` for the
  1782. source image, but the *meta* dictionary returned by this method
  1783. will have ``planes=4`` and ``alpha=True`` because an alpha
  1784. channel is synthesized and added.
  1785. *pixels* is the pixel data in boxed row flat pixel format (just
  1786. like the :meth:`read` method).
  1787. All the other aspects of the image data are not changed.
  1788. """
  1789. self.preamble()
  1790. # Simple case, no conversion necessary.
  1791. if not self.colormap and not self.trns and not self.sbit:
  1792. return self.read()
  1793. x,y,pixels,meta = self.read()
  1794. if self.colormap:
  1795. meta['colormap'] = False
  1796. meta['alpha'] = bool(self.trns)
  1797. meta['bitdepth'] = 8
  1798. meta['planes'] = 3 + bool(self.trns)
  1799. plte = self.palette()
  1800. def iterpal(pixels):
  1801. for row in pixels:
  1802. row = map(plte.__getitem__, row)
  1803. yield array('B', itertools.chain(*row))
  1804. pixels = iterpal(pixels)
  1805. elif self.trns:
  1806. # It would be nice if there was some reasonable way
  1807. # of doing this without generating a whole load of
  1808. # intermediate tuples. But tuples does seem like the
  1809. # easiest way, with no other way clearly much simpler or
  1810. # much faster. (Actually, the L to LA conversion could
  1811. # perhaps go faster (all those 1-tuples!), but I still
  1812. # wonder whether the code proliferation is worth it)
  1813. it = self.transparent
  1814. maxval = 2**meta['bitdepth']-1
  1815. planes = meta['planes']
  1816. meta['alpha'] = True
  1817. meta['planes'] += 1
  1818. typecode = 'BH'[meta['bitdepth']>8]
  1819. def itertrns(pixels):
  1820. for row in pixels:
  1821. # For each row we group it into pixels, then form a
  1822. # characterisation vector that says whether each
  1823. # pixel is opaque or not. Then we convert
  1824. # True/False to 0/maxval (by multiplication),
  1825. # and add it as the extra channel.
  1826. row = group(row, planes)
  1827. opa = map(it.__ne__, row)
  1828. opa = map(maxval.__mul__, opa)
  1829. opa = zip(opa) # convert to 1-tuples
  1830. yield array(typecode,
  1831. itertools.chain(*map(operator.add, row, opa)))
  1832. pixels = itertrns(pixels)
  1833. targetbitdepth = None
  1834. if self.sbit:
  1835. sbit = struct.unpack('%dB' % len(self.sbit), self.sbit)
  1836. targetbitdepth = max(sbit)
  1837. if targetbitdepth > meta['bitdepth']:
  1838. raise Error('sBIT chunk %r exceeds bitdepth %d' %
  1839. (sbit,self.bitdepth))
  1840. if min(sbit) <= 0:
  1841. raise Error('sBIT chunk %r has a 0-entry' % sbit)
  1842. if targetbitdepth == meta['bitdepth']:
  1843. targetbitdepth = None
  1844. if targetbitdepth:
  1845. shift = meta['bitdepth'] - targetbitdepth
  1846. meta['bitdepth'] = targetbitdepth
  1847. def itershift(pixels):
  1848. for row in pixels:
  1849. yield map(shift.__rrshift__, row)
  1850. pixels = itershift(pixels)
  1851. return x,y,pixels,meta
  1852. def asFloat(self, maxval=1.0):
  1853. """Return image pixels as per :meth:`asDirect` method, but scale
  1854. all pixel values to be floating point values between 0.0 and
  1855. *maxval*.
  1856. """
  1857. x,y,pixels,info = self.asDirect()
  1858. sourcemaxval = 2**info['bitdepth']-1
  1859. del info['bitdepth']
  1860. info['maxval'] = float(maxval)
  1861. factor = float(maxval)/float(sourcemaxval)
  1862. def iterfloat():
  1863. for row in pixels:
  1864. yield map(factor.__mul__, row)
  1865. return x,y,iterfloat(),info
  1866. def _as_rescale(self, get, targetbitdepth):
  1867. """Helper used by :meth:`asRGB8` and :meth:`asRGBA8`."""
  1868. width,height,pixels,meta = get()
  1869. maxval = 2**meta['bitdepth'] - 1
  1870. targetmaxval = 2**targetbitdepth - 1
  1871. factor = float(targetmaxval) / float(maxval)
  1872. meta['bitdepth'] = targetbitdepth
  1873. def iterscale():
  1874. for row in pixels:
  1875. yield map(lambda x: int(round(x*factor)), row)
  1876. if maxval == targetmaxval:
  1877. return width, height, pixels, meta
  1878. else:
  1879. return width, height, iterscale(), meta
  1880. def asRGB8(self):
  1881. """Return the image data as an RGB pixels with 8-bits per
  1882. sample. This is like the :meth:`asRGB` method except that
  1883. this method additionally rescales the values so that they
  1884. are all between 0 and 255 (8-bit). In the case where the
  1885. source image has a bit depth < 8 the transformation preserves
  1886. all the information; where the source image has bit depth
  1887. > 8, then rescaling to 8-bit values loses precision. No
  1888. dithering is performed. Like :meth:`asRGB`, an alpha channel
  1889. in the source image will raise an exception.
  1890. This function returns a 4-tuple:
  1891. (*width*, *height*, *pixels*, *metadata*).
  1892. *width*, *height*, *metadata* are as per the
  1893. :meth:`read` method.
  1894. *pixels* is the pixel data in boxed row flat pixel format.
  1895. """
  1896. return self._as_rescale(self.asRGB, 8)
  1897. def asRGBA8(self):
  1898. """Return the image data as RGBA pixels with 8-bits per
  1899. sample. This method is similar to :meth:`asRGB8` and
  1900. :meth:`asRGBA`: The result pixels have an alpha channel, *and*
  1901. values are rescaled to the range 0 to 255. The alpha channel is
  1902. synthesized if necessary (with a small speed penalty).
  1903. """
  1904. return self._as_rescale(self.asRGBA, 8)
  1905. def asRGB(self):
  1906. """Return image as RGB pixels. RGB colour images are passed
  1907. through unchanged; greyscales are expanded into RGB
  1908. triplets (there is a small speed overhead for doing this).
  1909. An alpha channel in the source image will raise an
  1910. exception.
  1911. The return values are as for the :meth:`read` method
  1912. except that the *metadata* reflect the returned pixels, not the
  1913. source image. In particular, for this method
  1914. ``metadata['greyscale']`` will be ``False``.
  1915. """
  1916. width,height,pixels,meta = self.asDirect()
  1917. if meta['alpha']:
  1918. raise Error("will not convert image with alpha channel to RGB")
  1919. if not meta['greyscale']:
  1920. return width,height,pixels,meta
  1921. meta['greyscale'] = False
  1922. typecode = 'BH'[meta['bitdepth'] > 8]
  1923. def iterrgb():
  1924. for row in pixels:
  1925. a = array(typecode, [0]) * 3 * width
  1926. for i in range(3):
  1927. a[i::3] = row
  1928. yield a
  1929. return width,height,iterrgb(),meta
  1930. def asRGBA(self):
  1931. """Return image as RGBA pixels. Greyscales are expanded into
  1932. RGB triplets; an alpha channel is synthesized if necessary.
  1933. The return values are as for the :meth:`read` method
  1934. except that the *metadata* reflect the returned pixels, not the
  1935. source image. In particular, for this method
  1936. ``metadata['greyscale']`` will be ``False``, and
  1937. ``metadata['alpha']`` will be ``True``.
  1938. """
  1939. width,height,pixels,meta = self.asDirect()
  1940. if meta['alpha'] and not meta['greyscale']:
  1941. return width,height,pixels,meta
  1942. typecode = 'BH'[meta['bitdepth'] > 8]
  1943. maxval = 2**meta['bitdepth'] - 1
  1944. maxbuffer = struct.pack('=' + typecode, maxval) * 4 * width
  1945. def newarray():
  1946. return array(typecode, maxbuffer)
  1947. if meta['alpha'] and meta['greyscale']:
  1948. # LA to RGBA
  1949. def convert():
  1950. for row in pixels:
  1951. # Create a fresh target row, then copy L channel
  1952. # into first three target channels, and A channel
  1953. # into fourth channel.
  1954. a = newarray()
  1955. pngfilters.convert_la_to_rgba(row, a)
  1956. yield a
  1957. elif meta['greyscale']:
  1958. # L to RGBA
  1959. def convert():
  1960. for row in pixels:
  1961. a = newarray()
  1962. pngfilters.convert_l_to_rgba(row, a)
  1963. yield a
  1964. else:
  1965. assert not meta['alpha'] and not meta['greyscale']
  1966. # RGB to RGBA
  1967. def convert():
  1968. for row in pixels:
  1969. a = newarray()
  1970. pngfilters.convert_rgb_to_rgba(row, a)
  1971. yield a
  1972. meta['alpha'] = True
  1973. meta['greyscale'] = False
  1974. return width,height,convert(),meta
  1975. def check_bitdepth_colortype(bitdepth, colortype):
  1976. """Check that `bitdepth` and `colortype` are both valid,
  1977. and specified in a valid combination. Returns if valid,
  1978. raise an Exception if not valid.
  1979. """
  1980. if bitdepth not in (1,2,4,8,16):
  1981. raise FormatError("invalid bit depth %d" % bitdepth)
  1982. if colortype not in (0,2,3,4,6):
  1983. raise FormatError("invalid colour type %d" % colortype)
  1984. # Check indexed (palettized) images have 8 or fewer bits
  1985. # per pixel; check only indexed or greyscale images have
  1986. # fewer than 8 bits per pixel.
  1987. if colortype & 1 and bitdepth > 8:
  1988. raise FormatError(
  1989. "Indexed images (colour type %d) cannot"
  1990. " have bitdepth > 8 (bit depth %d)."
  1991. " See http://www.w3.org/TR/2003/REC-PNG-20031110/#table111 ."
  1992. % (bitdepth, colortype))
  1993. if bitdepth < 8 and colortype not in (0,3):
  1994. raise FormatError("Illegal combination of bit depth (%d)"
  1995. " and colour type (%d)."
  1996. " See http://www.w3.org/TR/2003/REC-PNG-20031110/#table111 ."
  1997. % (bitdepth, colortype))
  1998. def isinteger(x):
  1999. try:
  2000. return int(x) == x
  2001. except (TypeError, ValueError):
  2002. return False
  2003. # === Legacy Version Support ===
  2004. # :pyver:old: PyPNG works on Python versions 2.3 and 2.2, but not
  2005. # without some awkward problems. Really PyPNG works on Python 2.4 (and
  2006. # above); it works on Pythons 2.3 and 2.2 by virtue of fixing up
  2007. # problems here. It's a bit ugly (which is why it's hidden down here).
  2008. #
  2009. # Generally the strategy is one of pretending that we're running on
  2010. # Python 2.4 (or above), and patching up the library support on earlier
  2011. # versions so that it looks enough like Python 2.4. When it comes to
  2012. # Python 2.2 there is one thing we cannot patch: extended slices
  2013. # http://www.python.org/doc/2.3/whatsnew/section-slices.html.
  2014. # Instead we simply declare that features that are implemented using
  2015. # extended slices will not work on Python 2.2.
  2016. #
  2017. # In order to work on Python 2.3 we fix up a recurring annoyance involving
  2018. # the array type. In Python 2.3 an array cannot be initialised with an
  2019. # array, and it cannot be extended with a list (or other sequence).
  2020. # Both of those are repeated issues in the code. Whilst I would not
  2021. # normally tolerate this sort of behaviour, here we "shim" a replacement
  2022. # for array into place (and hope no-one notices). You never read this.
  2023. #
  2024. # In an amusing case of warty hacks on top of warty hacks... the array
  2025. # shimming we try and do only works on Python 2.3 and above (you can't
  2026. # subclass array.array in Python 2.2). So to get it working on Python
  2027. # 2.2 we go for something much simpler and (probably) way slower.
  2028. try:
  2029. array('B').extend([])
  2030. array('B', array('B'))
  2031. # :todo:(drj) Check that TypeError is correct for Python 2.3
  2032. except TypeError:
  2033. # Expect to get here on Python 2.3
  2034. try:
  2035. class _array_shim(array):
  2036. true_array = array
  2037. def __new__(cls, typecode, init=None):
  2038. super_new = super(_array_shim, cls).__new__
  2039. it = super_new(cls, typecode)
  2040. if init is None:
  2041. return it
  2042. it.extend(init)
  2043. return it
  2044. def extend(self, extension):
  2045. super_extend = super(_array_shim, self).extend
  2046. if isinstance(extension, self.true_array):
  2047. return super_extend(extension)
  2048. if not isinstance(extension, (list, str)):
  2049. # Convert to list. Allows iterators to work.
  2050. extension = list(extension)
  2051. return super_extend(self.true_array(self.typecode, extension))
  2052. array = _array_shim
  2053. except TypeError:
  2054. # Expect to get here on Python 2.2
  2055. def array(typecode, init=()):
  2056. if type(init) == str:
  2057. return map(ord, init)
  2058. return list(init)
  2059. # Further hacks to get it limping along on Python 2.2
  2060. try:
  2061. enumerate
  2062. except NameError:
  2063. def enumerate(seq):
  2064. i=0
  2065. for x in seq:
  2066. yield i,x
  2067. i += 1
  2068. try:
  2069. reversed
  2070. except NameError:
  2071. def reversed(l):
  2072. l = list(l)
  2073. l.reverse()
  2074. for x in l:
  2075. yield x
  2076. try:
  2077. itertools
  2078. except NameError:
  2079. class _dummy_itertools:
  2080. pass
  2081. itertools = _dummy_itertools()
  2082. def _itertools_imap(f, seq):
  2083. for x in seq:
  2084. yield f(x)
  2085. itertools.imap = _itertools_imap
  2086. def _itertools_chain(*iterables):
  2087. for it in iterables:
  2088. for element in it:
  2089. yield element
  2090. itertools.chain = _itertools_chain
  2091. # === Support for users without Cython ===
  2092. try:
  2093. pngfilters
  2094. except NameError:
  2095. class pngfilters(object):
  2096. def undo_filter_sub(filter_unit, scanline, previous, result):
  2097. """Undo sub filter."""
  2098. ai = 0
  2099. # Loops starts at index fu. Observe that the initial part
  2100. # of the result is already filled in correctly with
  2101. # scanline.
  2102. for i in range(filter_unit, len(result)):
  2103. x = scanline[i]
  2104. a = result[ai]
  2105. result[i] = (x + a) & 0xff
  2106. ai += 1
  2107. undo_filter_sub = staticmethod(undo_filter_sub)
  2108. def undo_filter_up(filter_unit, scanline, previous, result):
  2109. """Undo up filter."""
  2110. for i in range(len(result)):
  2111. x = scanline[i]
  2112. b = previous[i]
  2113. result[i] = (x + b) & 0xff
  2114. undo_filter_up = staticmethod(undo_filter_up)
  2115. def undo_filter_average(filter_unit, scanline, previous, result):
  2116. """Undo up filter."""
  2117. ai = -filter_unit
  2118. for i in range(len(result)):
  2119. x = scanline[i]
  2120. if ai < 0:
  2121. a = 0
  2122. else:
  2123. a = result[ai]
  2124. b = previous[i]
  2125. result[i] = (x + ((a + b) >> 1)) & 0xff
  2126. ai += 1
  2127. undo_filter_average = staticmethod(undo_filter_average)
  2128. def undo_filter_paeth(filter_unit, scanline, previous, result):
  2129. """Undo Paeth filter."""
  2130. # Also used for ci.
  2131. ai = -filter_unit
  2132. for i in range(len(result)):
  2133. x = scanline[i]
  2134. if ai < 0:
  2135. a = c = 0
  2136. else:
  2137. a = result[ai]
  2138. c = previous[ai]
  2139. b = previous[i]
  2140. p = a + b - c
  2141. pa = abs(p - a)
  2142. pb = abs(p - b)
  2143. pc = abs(p - c)
  2144. if pa <= pb and pa <= pc:
  2145. pr = a
  2146. elif pb <= pc:
  2147. pr = b
  2148. else:
  2149. pr = c
  2150. result[i] = (x + pr) & 0xff
  2151. ai += 1
  2152. undo_filter_paeth = staticmethod(undo_filter_paeth)
  2153. def convert_la_to_rgba(row, result):
  2154. for i in range(3):
  2155. result[i::4] = row[0::2]
  2156. result[3::4] = row[1::2]
  2157. convert_la_to_rgba = staticmethod(convert_la_to_rgba)
  2158. def convert_l_to_rgba(row, result):
  2159. """Convert a grayscale image to RGBA. This method assumes
  2160. the alpha channel in result is already correctly
  2161. initialized.
  2162. """
  2163. for i in range(3):
  2164. result[i::4] = row
  2165. convert_l_to_rgba = staticmethod(convert_l_to_rgba)
  2166. def convert_rgb_to_rgba(row, result):
  2167. """Convert an RGB image to RGBA. This method assumes the
  2168. alpha channel in result is already correctly initialized.
  2169. """
  2170. for i in range(3):
  2171. result[i::4] = row[i::3]
  2172. convert_rgb_to_rgba = staticmethod(convert_rgb_to_rgba)
  2173. # === Command Line Support ===
  2174. def read_pam_header(infile):
  2175. """
  2176. Read (the rest of a) PAM header. `infile` should be positioned
  2177. immediately after the initial 'P7' line (at the beginning of the
  2178. second line). Returns are as for `read_pnm_header`.
  2179. """
  2180. # Unlike PBM, PGM, and PPM, we can read the header a line at a time.
  2181. header = dict()
  2182. while True:
  2183. l = infile.readline().strip()
  2184. if l == strtobytes('ENDHDR'):
  2185. break
  2186. if not l:
  2187. raise EOFError('PAM ended prematurely')
  2188. if l[0] == strtobytes('#'):
  2189. continue
  2190. l = l.split(None, 1)
  2191. if l[0] not in header:
  2192. header[l[0]] = l[1]
  2193. else:
  2194. header[l[0]] += strtobytes(' ') + l[1]
  2195. required = ['WIDTH', 'HEIGHT', 'DEPTH', 'MAXVAL']
  2196. required = [strtobytes(x) for x in required]
  2197. WIDTH,HEIGHT,DEPTH,MAXVAL = required
  2198. present = [x for x in required if x in header]
  2199. if len(present) != len(required):
  2200. raise Error('PAM file must specify WIDTH, HEIGHT, DEPTH, and MAXVAL')
  2201. width = int(header[WIDTH])
  2202. height = int(header[HEIGHT])
  2203. depth = int(header[DEPTH])
  2204. maxval = int(header[MAXVAL])
  2205. if (width <= 0 or
  2206. height <= 0 or
  2207. depth <= 0 or
  2208. maxval <= 0):
  2209. raise Error(
  2210. 'WIDTH, HEIGHT, DEPTH, MAXVAL must all be positive integers')
  2211. return 'P7', width, height, depth, maxval
  2212. def read_pnm_header(infile, supported=('P5','P6')):
  2213. """
  2214. Read a PNM header, returning (format,width,height,depth,maxval).
  2215. `width` and `height` are in pixels. `depth` is the number of
  2216. channels in the image; for PBM and PGM it is synthesized as 1, for
  2217. PPM as 3; for PAM images it is read from the header. `maxval` is
  2218. synthesized (as 1) for PBM images.
  2219. """
  2220. # Generally, see http://netpbm.sourceforge.net/doc/ppm.html
  2221. # and http://netpbm.sourceforge.net/doc/pam.html
  2222. supported = [strtobytes(x) for x in supported]
  2223. # Technically 'P7' must be followed by a newline, so by using
  2224. # rstrip() we are being liberal in what we accept. I think this
  2225. # is acceptable.
  2226. type = infile.read(3).rstrip()
  2227. if type not in supported:
  2228. raise NotImplementedError('file format %s not supported' % type)
  2229. if type == strtobytes('P7'):
  2230. # PAM header parsing is completely different.
  2231. return read_pam_header(infile)
  2232. # Expected number of tokens in header (3 for P4, 4 for P6)
  2233. expected = 4
  2234. pbm = ('P1', 'P4')
  2235. if type in pbm:
  2236. expected = 3
  2237. header = [type]
  2238. # We have to read the rest of the header byte by byte because the
  2239. # final whitespace character (immediately following the MAXVAL in
  2240. # the case of P6) may not be a newline. Of course all PNM files in
  2241. # the wild use a newline at this point, so it's tempting to use
  2242. # readline; but it would be wrong.
  2243. def getc():
  2244. c = infile.read(1)
  2245. if not c:
  2246. raise Error('premature EOF reading PNM header')
  2247. return c
  2248. c = getc()
  2249. while True:
  2250. # Skip whitespace that precedes a token.
  2251. while c.isspace():
  2252. c = getc()
  2253. # Skip comments.
  2254. while c == '#':
  2255. while c not in '\n\r':
  2256. c = getc()
  2257. if not c.isdigit():
  2258. raise Error('unexpected character %s found in header' % c)
  2259. # According to the specification it is legal to have comments
  2260. # that appear in the middle of a token.
  2261. # This is bonkers; I've never seen it; and it's a bit awkward to
  2262. # code good lexers in Python (no goto). So we break on such
  2263. # cases.
  2264. token = strtobytes('')
  2265. while c.isdigit():
  2266. token += c
  2267. c = getc()
  2268. # Slight hack. All "tokens" are decimal integers, so convert
  2269. # them here.
  2270. header.append(int(token))
  2271. if len(header) == expected:
  2272. break
  2273. # Skip comments (again)
  2274. while c == '#':
  2275. while c not in '\n\r':
  2276. c = getc()
  2277. if not c.isspace():
  2278. raise Error('expected header to end with whitespace, not %s' % c)
  2279. if type in pbm:
  2280. # synthesize a MAXVAL
  2281. header.append(1)
  2282. depth = (1,3)[type == strtobytes('P6')]
  2283. return header[0], header[1], header[2], depth, header[3]
  2284. def write_pnm(file, width, height, pixels, meta):
  2285. """Write a Netpbm PNM/PAM file.
  2286. """
  2287. bitdepth = meta['bitdepth']
  2288. maxval = 2**bitdepth - 1
  2289. # Rudely, the number of image planes can be used to determine
  2290. # whether we are L (PGM), LA (PAM), RGB (PPM), or RGBA (PAM).
  2291. planes = meta['planes']
  2292. # Can be an assert as long as we assume that pixels and meta came
  2293. # from a PNG file.
  2294. assert planes in (1,2,3,4)
  2295. if planes in (1,3):
  2296. if 1 == planes:
  2297. # PGM
  2298. # Could generate PBM if maxval is 1, but we don't (for one
  2299. # thing, we'd have to convert the data, not just blat it
  2300. # out).
  2301. fmt = 'P5'
  2302. else:
  2303. # PPM
  2304. fmt = 'P6'
  2305. header = '%s %d %d %d\n' % (fmt, width, height, maxval)
  2306. if planes in (2,4):
  2307. # PAM
  2308. # See http://netpbm.sourceforge.net/doc/pam.html
  2309. if 2 == planes:
  2310. tupltype = 'GRAYSCALE_ALPHA'
  2311. else:
  2312. tupltype = 'RGB_ALPHA'
  2313. header = ('P7\nWIDTH %d\nHEIGHT %d\nDEPTH %d\nMAXVAL %d\n'
  2314. 'TUPLTYPE %s\nENDHDR\n' %
  2315. (width, height, planes, maxval, tupltype))
  2316. file.write(header.encode('ascii'))
  2317. # Values per row
  2318. vpr = planes * width
  2319. # struct format
  2320. fmt = '>%d' % vpr
  2321. if maxval > 0xff:
  2322. fmt = fmt + 'H'
  2323. else:
  2324. fmt = fmt + 'B'
  2325. for row in pixels:
  2326. file.write(struct.pack(fmt, *row))
  2327. file.flush()
  2328. def color_triple(color):
  2329. """
  2330. Convert a command line colour value to a RGB triple of integers.
  2331. FIXME: Somewhere we need support for greyscale backgrounds etc.
  2332. """
  2333. if color.startswith('#') and len(color) == 4:
  2334. return (int(color[1], 16),
  2335. int(color[2], 16),
  2336. int(color[3], 16))
  2337. if color.startswith('#') and len(color) == 7:
  2338. return (int(color[1:3], 16),
  2339. int(color[3:5], 16),
  2340. int(color[5:7], 16))
  2341. elif color.startswith('#') and len(color) == 13:
  2342. return (int(color[1:5], 16),
  2343. int(color[5:9], 16),
  2344. int(color[9:13], 16))
  2345. def _add_common_options(parser):
  2346. """Call *parser.add_option* for each of the options that are
  2347. common between this PNG--PNM conversion tool and the gen
  2348. tool.
  2349. """
  2350. parser.add_option("-i", "--interlace",
  2351. default=False, action="store_true",
  2352. help="create an interlaced PNG file (Adam7)")
  2353. parser.add_option("-t", "--transparent",
  2354. action="store", type="string", metavar="#RRGGBB",
  2355. help="mark the specified colour as transparent")
  2356. parser.add_option("-b", "--background",
  2357. action="store", type="string", metavar="#RRGGBB",
  2358. help="save the specified background colour")
  2359. parser.add_option("-g", "--gamma",
  2360. action="store", type="float", metavar="value",
  2361. help="save the specified gamma value")
  2362. parser.add_option("-c", "--compression",
  2363. action="store", type="int", metavar="level",
  2364. help="zlib compression level (0-9)")
  2365. return parser
  2366. def _main(argv):
  2367. """
  2368. Run the PNG encoder with options from the command line.
  2369. """
  2370. # Parse command line arguments
  2371. from optparse import OptionParser
  2372. version = '%prog ' + __version__
  2373. parser = OptionParser(version=version)
  2374. parser.set_usage("%prog [options] [imagefile]")
  2375. parser.add_option('-r', '--read-png', default=False,
  2376. action='store_true',
  2377. help='Read PNG, write PNM')
  2378. parser.add_option("-a", "--alpha",
  2379. action="store", type="string", metavar="pgmfile",
  2380. help="alpha channel transparency (RGBA)")
  2381. _add_common_options(parser)
  2382. (options, args) = parser.parse_args(args=argv[1:])
  2383. # Convert options
  2384. if options.transparent is not None:
  2385. options.transparent = color_triple(options.transparent)
  2386. if options.background is not None:
  2387. options.background = color_triple(options.background)
  2388. # Prepare input and output files
  2389. if len(args) == 0:
  2390. infilename = '-'
  2391. infile = sys.stdin
  2392. elif len(args) == 1:
  2393. infilename = args[0]
  2394. infile = open(infilename, 'rb')
  2395. else:
  2396. parser.error("more than one input file")
  2397. outfile = sys.stdout
  2398. if sys.platform == "win32":
  2399. import msvcrt, os
  2400. msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
  2401. if options.read_png:
  2402. # Encode PNG to PPM
  2403. png = Reader(file=infile)
  2404. width,height,pixels,meta = png.asDirect()
  2405. write_pnm(outfile, width, height, pixels, meta)
  2406. else:
  2407. # Encode PNM to PNG
  2408. format, width, height, depth, maxval = \
  2409. read_pnm_header(infile, ('P5','P6','P7'))
  2410. # When it comes to the variety of input formats, we do something
  2411. # rather rude. Observe that L, LA, RGB, RGBA are the 4 colour
  2412. # types supported by PNG and that they correspond to 1, 2, 3, 4
  2413. # channels respectively. So we use the number of channels in
  2414. # the source image to determine which one we have. We do not
  2415. # care about TUPLTYPE.
  2416. greyscale = depth <= 2
  2417. pamalpha = depth in (2,4)
  2418. supported = map(lambda x: 2**x-1, range(1,17))
  2419. try:
  2420. mi = supported.index(maxval)
  2421. except ValueError:
  2422. raise NotImplementedError(
  2423. 'your maxval (%s) not in supported list %s' %
  2424. (maxval, str(supported)))
  2425. bitdepth = mi+1
  2426. writer = Writer(width, height,
  2427. greyscale=greyscale,
  2428. bitdepth=bitdepth,
  2429. interlace=options.interlace,
  2430. transparent=options.transparent,
  2431. background=options.background,
  2432. alpha=bool(pamalpha or options.alpha),
  2433. gamma=options.gamma,
  2434. compression=options.compression)
  2435. if options.alpha:
  2436. pgmfile = open(options.alpha, 'rb')
  2437. format, awidth, aheight, adepth, amaxval = \
  2438. read_pnm_header(pgmfile, 'P5')
  2439. if amaxval != '255':
  2440. raise NotImplementedError(
  2441. 'maxval %s not supported for alpha channel' % amaxval)
  2442. if (awidth, aheight) != (width, height):
  2443. raise ValueError("alpha channel image size mismatch"
  2444. " (%s has %sx%s but %s has %sx%s)"
  2445. % (infilename, width, height,
  2446. options.alpha, awidth, aheight))
  2447. writer.convert_ppm_and_pgm(infile, pgmfile, outfile)
  2448. else:
  2449. writer.convert_pnm(infile, outfile)
  2450. if __name__ == '__main__':
  2451. try:
  2452. _main(sys.argv)
  2453. except Error, e:
  2454. print >>sys.stderr, e