Advertisement
TerusTheBird

Standalone sprite converter

Apr 26th, 2020
511
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 112.86 KB | None | 0 0
  1. #!/usr/bin/python3
  2. # -*- coding: utf-8 -*-
  3. from __future__ import print_function
  4.  
  5. '''
  6. STANDALONE SPRITE CONVERTER
  7. HOW TO RUN:
  8. python makeimg_standalone.py -H -C -d 2 -l grayhir -tq <input_sprite> <output_png>
  9.                              ^  ^
  10.                              |  \-- The input file is compressed (can be used alongside -H)
  11.                              \----- The input file is a text file with loads of .db/.dw commands
  12. extra flags:
  13. -cbb  <- the input file is a .CBB file
  14.  
  15. '''
  16.  
  17. import os, sys, argparse, re, math, subprocess, itertools, struct, warnings, zlib, collections
  18. sys.dont_write_bytecode = True
  19. from array import array
  20. from functools import reduce
  21. sqrt = math.sqrt
  22.  
  23. if sys.version_info > (3,0):
  24.     global xrange
  25.     xrange = range
  26.  
  27. # hex_char_encoding = 'utf-8'
  28. hex_char_encoding = 'shift_jis'
  29.  
  30. # -------------------------------------------------------------------------------------------
  31. # -------------------------------------------------------------------------------------------
  32. # -------------------------------------------------------------------------------------------
  33. # -------------------------------------------------------------------------------------------
  34. # -------------------------------------------------------------------------------------------
  35. # -------------------------------------------------------------------------------------------
  36. # -------------------------------------------------------------------------------------------
  37. # -------------------------------------------------------------------------------------------
  38. # -------------------------------------------------------------------------------------------
  39.  
  40. # png.py - PNG encoder/decoder in pure Python
  41. #
  42. # Copyright (C) 2006 Johann C. Rocholl <johann@browsershots.org>
  43. # Portions Copyright (C) 2009 David Jones <drj@pobox.com>
  44. # And probably portions Copyright (C) 2006 Nicko van Someren <nicko@nicko.org>
  45. #
  46. # Original concept by Johann C. Rocholl.
  47. #
  48. # LICENCE (MIT)
  49. #
  50. # Permission is hereby granted, free of charge, to any person
  51. # obtaining a copy of this software and associated documentation files
  52. # (the "Software"), to deal in the Software without restriction,
  53. # including without limitation the rights to use, copy, modify, merge,
  54. # publish, distribute, sublicense, and/or sell copies of the Software,
  55. # and to permit persons to whom the Software is furnished to do so,
  56. # subject to the following conditions:
  57. #
  58. # The above copyright notice and this permission notice shall be
  59. # included in all copies or substantial portions of the Software.
  60. #
  61. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  62. # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  63. # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  64. # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  65. # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  66. # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  67. # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  68. # SOFTWARE.
  69.  
  70. """
  71. The ``png`` module can read and write PNG files.
  72.  
  73. Installation and Overview
  74. -------------------------
  75.  
  76. ``pip install pypng``
  77.  
  78. For help, type ``import png; help(png)`` in your python interpreter.
  79.  
  80. A good place to start is the :class:`Reader` and :class:`Writer` classes.
  81.  
  82. Coverage of PNG formats is fairly complete;
  83. all allowable bit depths (1/2/4/8/16/24/32/48/64 bits per pixel) and
  84. colour combinations are supported:
  85.  
  86. - greyscale (1/2/4/8/16 bit);
  87. - RGB, RGBA, LA (greyscale with alpha) with 8/16 bits per channel;
  88. - colour mapped images (1/2/4/8 bit).
  89.  
  90. Interlaced images,
  91. which support a progressive display when downloading,
  92. are supported for both reading and writing.
  93.  
  94. A number of optional chunks can be specified (when writing)
  95. and understood (when reading): ``tRNS``, ``bKGD``, ``gAMA``.
  96.  
  97. The ``sBIT`` chunk can be used to specify precision for
  98. non-native bit depths.
  99.  
  100. Requires Python 3.4 or higher (or Python 2.7).
  101. Installation is trivial,
  102. but see the ``README.txt`` file (with the source distribution) for details.
  103.  
  104. Full use of all features will need some reading of the PNG specification
  105. http://www.w3.org/TR/2003/REC-PNG-20031110/.
  106.  
  107. The package also comes with command line utilities.
  108.  
  109. - ``pripamtopng`` converts
  110.  `Netpbm <http://netpbm.sourceforge.net/>`_ PAM/PNM files to PNG;
  111. - ``pripngtopam`` converts PNG to file PAM/PNM.
  112.  
  113. There are a few more for simple PNG manipulations.
  114.  
  115. Spelling and Terminology
  116. ------------------------
  117.  
  118. Generally British English spelling is used in the documentation.
  119. So that's "greyscale" and "colour".
  120. This not only matches the author's native language,
  121. it's also used by the PNG specification.
  122.  
  123. Colour Models
  124. -------------
  125.  
  126. The major colour models supported by PNG (and hence by PyPNG) are:
  127.  
  128. - greyscale;
  129. - greyscale--alpha;
  130. - RGB;
  131. - RGB--alpha.
  132.  
  133. Also referred to using the abbreviations: L, LA, RGB, RGBA.
  134. Each letter codes a single channel:
  135. *L* is for Luminance or Luma or Lightness (greyscale images);
  136. *A* stands for Alpha, the opacity channel
  137. (used for transparency effects, but higher values are more opaque,
  138. so it makes sense to call it opacity);
  139. *R*, *G*, *B* stand for Red, Green, Blue (colour image).
  140.  
  141. Lists, arrays, sequences, and so on
  142. -----------------------------------
  143.  
  144. When getting pixel data out of this module (reading) and
  145. presenting data to this module (writing) there are
  146. a number of ways the data could be represented as a Python value.
  147.  
  148. The preferred format is a sequence of *rows*,
  149. which each row being a sequence of *values*.
  150. In this format, the values are in pixel order,
  151. with all the values from all the pixels in a row
  152. being concatenated into a single sequence for that row.
  153.  
  154. Consider an image that is 3 pixels wide by 2 pixels high, and each pixel
  155. has RGB components:
  156.  
  157. Sequence of rows::
  158.  
  159.  list([R,G,B, R,G,B, R,G,B],
  160.       [R,G,B, R,G,B, R,G,B])
  161.  
  162. Each row appears as its own list,
  163. but the pixels are flattened so that three values for one pixel
  164. simply follow the three values for the previous pixel.
  165.  
  166. This is the preferred because
  167. it provides a good compromise between space and convenience.
  168. PyPNG regards itself as at liberty to replace any sequence type with
  169. any sufficiently compatible other sequence type;
  170. in practice each row is an array (``bytearray`` or ``array.array``).
  171.  
  172. To allow streaming the outer list is sometimes
  173. an iterator rather than an explicit list.
  174.  
  175. An alternative format is a single array holding all the values.
  176.  
  177. Array of values::
  178.  
  179.  [R,G,B, R,G,B, R,G,B,
  180.   R,G,B, R,G,B, R,G,B]
  181.  
  182. The entire image is one single giant sequence of colour values.
  183. Generally an array will be used (to save space), not a list.
  184.  
  185. The top row comes first,
  186. and within each row the pixels are ordered from left-to-right.
  187. Within a pixel the values appear in the order R-G-B-A
  188. (or L-A for greyscale--alpha).
  189.  
  190. There is another format, which should only be used with caution.
  191. It is mentioned because it is used internally,
  192. is close to what lies inside a PNG file itself,
  193. and has some support from the public API.
  194. This format is called *packed*.
  195. When packed, each row is a sequence of bytes (integers from 0 to 255),
  196. just as it is before PNG scanline filtering is applied.
  197. When the bit depth is 8 this is the same as a sequence of rows;
  198. when the bit depth is less than 8 (1, 2 and 4),
  199. several pixels are packed into each byte;
  200. when the bit depth is 16 each pixel value is decomposed into 2 bytes
  201. (and `packed` is a misnomer).
  202. This format is used by the :meth:`Writer.write_packed` method.
  203. It isn't usually a convenient format,
  204. but may be just right if the source data for
  205. the PNG image comes from something that uses a similar format
  206. (for example, 1-bit BMPs, or another PNG file).
  207. """
  208.  
  209. __version__ = "0.0.20"
  210.  
  211. __all__ = ['Image', 'Reader', 'Writer', 'write_chunks', 'from_array']
  212.  
  213.  
  214. # The PNG signature.
  215. # http://www.w3.org/TR/PNG/#5PNG-file-signature
  216. signature = struct.pack('8B', 137, 80, 78, 71, 13, 10, 26, 10)
  217.  
  218. # The xstart, ystart, xstep, ystep for the Adam7 interlace passes.
  219. adam7 = ((0, 0, 8, 8),
  220.          (4, 0, 8, 8),
  221.          (0, 4, 4, 8),
  222.          (2, 0, 4, 4),
  223.          (0, 2, 2, 4),
  224.          (1, 0, 2, 2),
  225.          (0, 1, 1, 2))
  226.  
  227.  
  228. def adam7_generate(width, height):
  229.     """
  230.    Generate the coordinates for the reduced scanlines
  231.    of an Adam7 interlaced image
  232.    of size `width` by `height` pixels.
  233.  
  234.    Yields a generator for each pass,
  235.    and each pass generator yields a series of (x, y, xstep) triples,
  236.    each one identifying a reduced scanline consisting of
  237.    pixels starting at (x, y) and taking every xstep pixel to the right.
  238.    """
  239.  
  240.     for xstart, ystart, xstep, ystep in adam7:
  241.         if xstart >= width:
  242.             continue
  243.         yield ((xstart, y, xstep) for y in range(ystart, height, ystep))
  244.  
  245.  
  246. # Models the 'pHYs' chunk (used by the Reader)
  247. Resolution = collections.namedtuple('_Resolution', 'x y unit_is_meter')
  248.  
  249.  
  250. def group(s, n):
  251.     return list(zip(* [iter(s)] * n))
  252.  
  253.  
  254. def isarray(x):
  255.     return isinstance(x, array)
  256.  
  257.  
  258. def check_palette(palette):
  259.     """
  260.    Check a palette argument (to the :class:`Writer` class) for validity.
  261.    Returns the palette as a list if okay;
  262.    raises an exception otherwise.
  263.    """
  264.  
  265.     # None is the default and is allowed.
  266.     if palette is None:
  267.         return None
  268.  
  269.     p = list(palette)
  270.     if not (0 < len(p) <= 256):
  271.         raise ProtocolError(
  272.             "a palette must have between 1 and 256 entries,"
  273.             " see https://www.w3.org/TR/PNG/#11PLTE")
  274.     seen_triple = False
  275.     for i, t in enumerate(p):
  276.         if len(t) not in (3, 4):
  277.             raise ProtocolError(
  278.                 "palette entry %d: entries must be 3- or 4-tuples." % i)
  279.         if len(t) == 3:
  280.             seen_triple = True
  281.         if seen_triple and len(t) == 4:
  282.             raise ProtocolError(
  283.                 "palette entry %d: all 4-tuples must precede all 3-tuples" % i)
  284.         for x in t:
  285.             if int(x) != x or not(0 <= x <= 255):
  286.                 raise ProtocolError(
  287.                     "palette entry %d: "
  288.                     "values must be integer: 0 <= x <= 255" % i)
  289.     return p
  290.  
  291.  
  292. def check_sizes(size, width, height):
  293.     """
  294.    Check that these arguments, if supplied, are consistent.
  295.    Return a (width, height) pair.
  296.    """
  297.  
  298.     if not size:
  299.         return width, height
  300.  
  301.     if len(size) != 2:
  302.         raise ProtocolError(
  303.             "size argument should be a pair (width, height)")
  304.     if width is not None and width != size[0]:
  305.         raise ProtocolError(
  306.             "size[0] (%r) and width (%r) should match when both are used."
  307.             % (size[0], width))
  308.     if height is not None and height != size[1]:
  309.         raise ProtocolError(
  310.             "size[1] (%r) and height (%r) should match when both are used."
  311.             % (size[1], height))
  312.     return size
  313.  
  314.  
  315. def check_color(c, greyscale, which):
  316.     """
  317.    Checks that a colour argument for transparent or background options
  318.    is the right form.
  319.    Returns the colour
  320.    (which, if it's a bare integer, is "corrected" to a 1-tuple).
  321.    """
  322.  
  323.     if c is None:
  324.         return c
  325.     if greyscale:
  326.         try:
  327.             len(c)
  328.         except TypeError:
  329.             c = (c,)
  330.         if len(c) != 1:
  331.             raise ProtocolError("%s for greyscale must be 1-tuple" % which)
  332.         if not is_natural(c[0]):
  333.             raise ProtocolError(
  334.                 "%s colour for greyscale must be integer" % which)
  335.     else:
  336.         if not (len(c) == 3 and
  337.                 is_natural(c[0]) and
  338.                 is_natural(c[1]) and
  339.                 is_natural(c[2])):
  340.             raise ProtocolError(
  341.                 "%s colour must be a triple of integers" % which)
  342.     return c
  343.  
  344.  
  345. class Error(Exception):
  346.     def __str__(self):
  347.         return self.__class__.__name__ + ': ' + ' '.join(self.args)
  348.  
  349.  
  350. class FormatError(Error):
  351.     """
  352.    Problem with input file format.
  353.    In other words, PNG file does not conform to
  354.    the specification in some way and is invalid.
  355.    """
  356.  
  357.  
  358. class ProtocolError(Error):
  359.     """
  360.    Problem with the way the programming interface has been used,
  361.    or the data presented to it.
  362.    """
  363.  
  364.  
  365. class ChunkError(FormatError):
  366.     pass
  367.  
  368.  
  369. class Default:
  370.     """The default for the greyscale paramter."""
  371.  
  372.  
  373. class Writer:
  374.     """
  375.    PNG encoder in pure Python.
  376.    """
  377.  
  378.     def __init__(self, width=None, height=None,
  379.                  size=None,
  380.                  greyscale=Default,
  381.                  alpha=False,
  382.                  bitdepth=8,
  383.                  palette=None,
  384.                  transparent=None,
  385.                  background=None,
  386.                  gamma=None,
  387.                  compression=None,
  388.                  interlace=False,
  389.                  planes=None,
  390.                  colormap=None,
  391.                  maxval=None,
  392.                  chunk_limit=2**20,
  393.                  x_pixels_per_unit=None,
  394.                  y_pixels_per_unit=None,
  395.                  unit_is_meter=False):
  396.         """
  397.        Create a PNG encoder object.
  398.  
  399.        Arguments:
  400.  
  401.        width, height
  402.          Image size in pixels, as two separate arguments.
  403.        size
  404.          Image size (w,h) in pixels, as single argument.
  405.        greyscale
  406.          Pixels are greyscale, not RGB.
  407.        alpha
  408.          Input data has alpha channel (RGBA or LA).
  409.        bitdepth
  410.          Bit depth: from 1 to 16 (for each channel).
  411.        palette
  412.          Create a palette for a colour mapped image (colour type 3).
  413.        transparent
  414.          Specify a transparent colour (create a ``tRNS`` chunk).
  415.        background
  416.          Specify a default background colour (create a ``bKGD`` chunk).
  417.        gamma
  418.          Specify a gamma value (create a ``gAMA`` chunk).
  419.        compression
  420.          zlib compression level: 0 (none) to 9 (more compressed);
  421.          default: -1 or None.
  422.        interlace
  423.          Create an interlaced image.
  424.        chunk_limit
  425.          Write multiple ``IDAT`` chunks to save memory.
  426.        x_pixels_per_unit
  427.          Number of pixels a unit along the x axis (write a
  428.          `pHYs` chunk).
  429.        y_pixels_per_unit
  430.          Number of pixels a unit along the y axis (write a
  431.          `pHYs` chunk). Along with `x_pixel_unit`, this gives
  432.          the pixel size ratio.
  433.        unit_is_meter
  434.          `True` to indicate that the unit (for the `pHYs`
  435.          chunk) is metre.
  436.  
  437.        The image size (in pixels) can be specified either by using the
  438.        `width` and `height` arguments, or with the single `size`
  439.        argument.
  440.        If `size` is used it should be a pair (*width*, *height*).
  441.  
  442.        The `greyscale` argument indicates whether input pixels
  443.        are greyscale (when true), or colour (when false).
  444.        The default is true unless `palette=` is used.
  445.  
  446.        The `alpha` argument (a boolean) specifies
  447.        whether input pixels have an alpha channel (or not).
  448.  
  449.        `bitdepth` specifies the bit depth of the source pixel values.
  450.        Each channel may have a different bit depth.
  451.        Each source pixel must have values that are
  452.        an integer between 0 and ``2**bitdepth-1``, where
  453.        `bitdepth` is the bit depth for the corresponding channel.
  454.        For example, 8-bit images have values between 0 and 255.
  455.        PNG only stores images with bit depths of
  456.        1,2,4,8, or 16 (the same for all channels).
  457.        When `bitdepth` is not one of these values or where
  458.        channels have different bit depths,
  459.        the next highest valid bit depth is selected,
  460.        and an ``sBIT`` (significant bits) chunk is generated
  461.        that specifies the original precision of the source image.
  462.        In this case the supplied pixel values will be rescaled to
  463.        fit the range of the selected bit depth.
  464.  
  465.        The PNG file format supports many bit depth / colour model
  466.        combinations, but not all.
  467.        The details are somewhat arcane
  468.        (refer to the PNG specification for full details).
  469.        Briefly:
  470.        Bit depths < 8 (1,2,4) are only allowed with greyscale and
  471.        colour mapped images;
  472.        colour mapped images cannot have bit depth 16.
  473.  
  474.        For colour mapped images
  475.        (in other words, when the `palette` argument is specified)
  476.        the `bitdepth` argument must match one of
  477.        the valid PNG bit depths: 1, 2, 4, or 8.
  478.        (It is valid to have a PNG image with a palette and
  479.        an ``sBIT`` chunk, but the meaning is slightly different;
  480.        it would be awkward to use the `bitdepth` argument for this.)
  481.  
  482.        The `palette` option, when specified,
  483.        causes a colour mapped image to be created:
  484.        the PNG colour type is set to 3;
  485.        `greyscale` must not be true; `alpha` must not be true;
  486.        `transparent` must not be set.
  487.        The bit depth must be 1,2,4, or 8.
  488.        When a colour mapped image is created,
  489.        the pixel values are palette indexes and
  490.        the `bitdepth` argument specifies the size of these indexes
  491.        (not the size of the colour values in the palette).
  492.  
  493.        The palette argument value should be a sequence of 3- or
  494.        4-tuples.
  495.        3-tuples specify RGB palette entries;
  496.        4-tuples specify RGBA palette entries.
  497.        All the 4-tuples (if present) must come before all the 3-tuples.
  498.        A ``PLTE`` chunk is created;
  499.        if there are 4-tuples then a ``tRNS`` chunk is created as well.
  500.        The ``PLTE`` chunk will contain all the RGB triples in the same
  501.        sequence;
  502.        the ``tRNS`` chunk will contain the alpha channel for
  503.        all the 4-tuples, in the same sequence.
  504.        Palette entries are always 8-bit.
  505.  
  506.        If specified, the `transparent` and `background` parameters must be
  507.        a tuple with one element for each channel in the image.
  508.        Either a 3-tuple of integer (RGB) values for a colour image, or
  509.        a 1-tuple of a single integer for a greyscale image.
  510.  
  511.        If specified, the `gamma` parameter must be a positive number
  512.        (generally, a `float`).
  513.        A ``gAMA`` chunk will be created.
  514.        Note that this will not change the values of the pixels as
  515.        they appear in the PNG file,
  516.        they are assumed to have already
  517.        been converted appropriately for the gamma specified.
  518.  
  519.        The `compression` argument specifies the compression level to
  520.        be used by the ``zlib`` module.
  521.        Values from 1 to 9 (highest) specify compression.
  522.        0 means no compression.
  523.        -1 and ``None`` both mean that the ``zlib`` module uses
  524.        the default level of compession (which is generally acceptable).
  525.  
  526.        If `interlace` is true then an interlaced image is created
  527.        (using PNG's so far only interace method, *Adam7*).
  528.        This does not affect how the pixels should be passed in,
  529.        rather it changes how they are arranged into the PNG file.
  530.        On slow connexions interlaced images can be
  531.        partially decoded by the browser to give
  532.        a rough view of the image that is
  533.        successively refined as more image data appears.
  534.  
  535.        .. note ::
  536.  
  537.          Enabling the `interlace` option requires the entire image
  538.          to be processed in working memory.
  539.  
  540.        `chunk_limit` is used to limit the amount of memory used whilst
  541.        compressing the image.
  542.        In order to avoid using large amounts of memory,
  543.        multiple ``IDAT`` chunks may be created.
  544.        """
  545.  
  546.         # At the moment the `planes` argument is ignored;
  547.         # its purpose is to act as a dummy so that
  548.         # ``Writer(x, y, **info)`` works, where `info` is a dictionary
  549.         # returned by Reader.read and friends.
  550.         # Ditto for `colormap`.
  551.  
  552.         width, height = check_sizes(size, width, height)
  553.         del size
  554.  
  555.         if not is_natural(width) or not is_natural(height):
  556.             raise ProtocolError("width and height must be integers")
  557.         if width <= 0 or height <= 0:
  558.             raise ProtocolError("width and height must be greater than zero")
  559.         # http://www.w3.org/TR/PNG/#7Integers-and-byte-order
  560.         if width > 2 ** 31 - 1 or height > 2 ** 31 - 1:
  561.             raise ProtocolError("width and height cannot exceed 2**31-1")
  562.  
  563.         if alpha and transparent is not None:
  564.             raise ProtocolError(
  565.                 "transparent colour not allowed with alpha channel")
  566.  
  567.         # bitdepth is either single integer, or tuple of integers.
  568.         # Convert to tuple.
  569.         try:
  570.             len(bitdepth)
  571.         except TypeError:
  572.             bitdepth = (bitdepth, )
  573.         for b in bitdepth:
  574.             valid = is_natural(b) and 1 <= b <= 16
  575.             if not valid:
  576.                 raise ProtocolError(
  577.                     "each bitdepth %r must be a positive integer <= 16" %
  578.                     (bitdepth,))
  579.  
  580.         # Calculate channels, and
  581.         # expand bitdepth to be one element per channel.
  582.         palette = check_palette(palette)
  583.         alpha = bool(alpha)
  584.         colormap = bool(palette)
  585.         if greyscale is Default and palette:
  586.             greyscale = False
  587.         greyscale = bool(greyscale)
  588.         if colormap:
  589.             color_planes = 1
  590.             planes = 1
  591.         else:
  592.             color_planes = (3, 1)[greyscale]
  593.             planes = color_planes + alpha
  594.         if len(bitdepth) == 1:
  595.             bitdepth *= planes
  596.  
  597.         bitdepth, self.rescale = check_bitdepth_rescale(
  598.                 palette,
  599.                 bitdepth,
  600.                 transparent, alpha, greyscale)
  601.  
  602.         # These are assertions, because above logic should have
  603.         # corrected or raised all problematic cases.
  604.         if bitdepth < 8:
  605.             assert greyscale or palette
  606.             assert not alpha
  607.         if bitdepth > 8:
  608.             assert not palette
  609.  
  610.         transparent = check_color(transparent, greyscale, 'transparent')
  611.         background = check_color(background, greyscale, 'background')
  612.  
  613.         # It's important that the true boolean values
  614.         # (greyscale, alpha, colormap, interlace) are converted
  615.         # to bool because Iverson's convention is relied upon later on.
  616.         self.width = width
  617.         self.height = height
  618.         self.transparent = transparent
  619.         self.background = background
  620.         self.gamma = gamma
  621.         self.greyscale = greyscale
  622.         self.alpha = alpha
  623.         self.colormap = colormap
  624.         self.bitdepth = int(bitdepth)
  625.         self.compression = compression
  626.         self.chunk_limit = chunk_limit
  627.         self.interlace = bool(interlace)
  628.         self.palette = palette
  629.         self.x_pixels_per_unit = x_pixels_per_unit
  630.         self.y_pixels_per_unit = y_pixels_per_unit
  631.         self.unit_is_meter = bool(unit_is_meter)
  632.  
  633.         self.color_type = (4 * self.alpha +
  634.                            2 * (not greyscale) +
  635.                            1 * self.colormap)
  636.         assert self.color_type in (0, 2, 3, 4, 6)
  637.  
  638.         self.color_planes = color_planes
  639.         self.planes = planes
  640.         # :todo: fix for bitdepth < 8
  641.         self.psize = (self.bitdepth / 8) * self.planes
  642.  
  643.     def write(self, outfile, rows):
  644.         """
  645.        Write a PNG image to the output file.
  646.        `rows` should be an iterable that yields each row
  647.        (each row is a sequence of values).
  648.        The rows should be the rows of the original image,
  649.        so there should be ``self.height`` rows of
  650.        ``self.width * self.planes`` values.
  651.        If `interlace` is specified (when creating the instance),
  652.        then an interlaced PNG file will be written.
  653.        Supply the rows in the normal image order;
  654.        the interlacing is carried out internally.
  655.  
  656.        .. note ::
  657.  
  658.          Interlacing requires the entire image to be in working memory.
  659.        """
  660.  
  661.         # Values per row
  662.         vpr = self.width * self.planes
  663.  
  664.         def check_rows(rows):
  665.             """
  666.            Yield each row in rows,
  667.            but check each row first (for correct width).
  668.            """
  669.             for i, row in enumerate(rows):
  670.                 try:
  671.                     wrong_length = len(row) != vpr
  672.                 except TypeError:
  673.                     # When using an itertools.ichain object or
  674.                     # other generator not supporting __len__,
  675.                     # we set this to False to skip the check.
  676.                     wrong_length = False
  677.                 if wrong_length:
  678.                     # Note: row numbers start at 0.
  679.                     raise ProtocolError(
  680.                         "Expected %d values but got %d value, in row %d" %
  681.                         (vpr, len(row), i))
  682.                 yield row
  683.  
  684.         if self.interlace:
  685.             fmt = 'BH'[self.bitdepth > 8]
  686.             a = array(fmt, itertools.chain(*check_rows(rows)))
  687.             return self.write_array(outfile, a)
  688.  
  689.         nrows = self.write_passes(outfile, check_rows(rows))
  690.         if nrows != self.height:
  691.             raise ProtocolError(
  692.                 "rows supplied (%d) does not match height (%d)" %
  693.                 (nrows, self.height))
  694.  
  695.     def write_passes(self, outfile, rows):
  696.         """
  697.        Write a PNG image to the output file.
  698.  
  699.        Most users are expected to find the :meth:`write` or
  700.        :meth:`write_array` method more convenient.
  701.  
  702.        The rows should be given to this method in the order that
  703.        they appear in the output file.
  704.        For straightlaced images, this is the usual top to bottom ordering.
  705.        For interlaced images the rows should have been interlaced before
  706.        passing them to this function.
  707.  
  708.        `rows` should be an iterable that yields each row
  709.        (each row being a sequence of values).
  710.        """
  711.  
  712.         # Ensure rows are scaled (to 4-/8-/16-bit),
  713.         # and packed into bytes.
  714.  
  715.         if self.rescale:
  716.             rows = rescale_rows(rows, self.rescale)
  717.  
  718.         if self.bitdepth < 8:
  719.             rows = pack_rows(rows, self.bitdepth)
  720.         elif self.bitdepth == 16:
  721.             rows = unpack_rows(rows)
  722.  
  723.         return self.write_packed(outfile, rows)
  724.  
  725.     def write_packed(self, outfile, rows):
  726.         """
  727.        Write PNG file to `outfile`.
  728.        `rows` should be an iterator that yields each packed row;
  729.        a packed row being a sequence of packed bytes.
  730.  
  731.        The rows have a filter byte prefixed and
  732.        are then compressed into one or more IDAT chunks.
  733.        They are not processed any further,
  734.        so if bitdepth is other than 1, 2, 4, 8, 16,
  735.        the pixel values should have been scaled
  736.        before passing them to this method.
  737.  
  738.        This method does work for interlaced images but it is best avoided.
  739.        For interlaced images, the rows should be
  740.        presented in the order that they appear in the file.
  741.        """
  742.  
  743.         self.write_preamble(outfile)
  744.  
  745.         # http://www.w3.org/TR/PNG/#11IDAT
  746.         if self.compression is not None:
  747.             compressor = zlib.compressobj(self.compression)
  748.         else:
  749.             compressor = zlib.compressobj()
  750.  
  751.         # data accumulates bytes to be compressed for the IDAT chunk;
  752.         # it's compressed when sufficiently large.
  753.         data = bytearray()
  754.  
  755.         for i, row in enumerate(rows):
  756.             # Add "None" filter type.
  757.             # Currently, it's essential that this filter type be used
  758.             # for every scanline as
  759.             # we do not mark the first row of a reduced pass image;
  760.             # that means we could accidentally compute
  761.             # the wrong filtered scanline if we used
  762.             # "up", "average", or "paeth" on such a line.
  763.             data.append(0)
  764.             data.extend(row)
  765.             if len(data) > self.chunk_limit:
  766.                 # :todo: bytes() only necessary in Python 2
  767.                 compressed = compressor.compress(bytes(data))
  768.                 if len(compressed):
  769.                     write_chunk(outfile, b'IDAT', compressed)
  770.                 data = bytearray()
  771.  
  772.         compressed = compressor.compress(bytes(data))
  773.         flushed = compressor.flush()
  774.         if len(compressed) or len(flushed):
  775.             write_chunk(outfile, b'IDAT', compressed + flushed)
  776.         # http://www.w3.org/TR/PNG/#11IEND
  777.         write_chunk(outfile, b'IEND')
  778.         return i + 1
  779.  
  780.     def write_preamble(self, outfile):
  781.         # http://www.w3.org/TR/PNG/#5PNG-file-signature
  782.         outfile.write(signature)
  783.  
  784.         # http://www.w3.org/TR/PNG/#11IHDR
  785.         write_chunk(outfile, b'IHDR',
  786.                     struct.pack("!2I5B", self.width, self.height,
  787.                                 self.bitdepth, self.color_type,
  788.                                 0, 0, self.interlace))
  789.  
  790.         # See :chunk:order
  791.         # http://www.w3.org/TR/PNG/#11gAMA
  792.         if self.gamma is not None:
  793.             write_chunk(outfile, b'gAMA',
  794.                         struct.pack("!L", int(round(self.gamma * 1e5))))
  795.  
  796.         # See :chunk:order
  797.         # http://www.w3.org/TR/PNG/#11sBIT
  798.         if self.rescale:
  799.             write_chunk(
  800.                 outfile, b'sBIT',
  801.                 struct.pack('%dB' % self.planes,
  802.                             * [s[0] for s in self.rescale]))
  803.  
  804.         # :chunk:order: Without a palette (PLTE chunk),
  805.         # ordering is relatively relaxed.
  806.         # With one, gAMA chunk must precede PLTE chunk
  807.         # which must precede tRNS and bKGD.
  808.         # See http://www.w3.org/TR/PNG/#5ChunkOrdering
  809.         if self.palette:
  810.             p, t = make_palette_chunks(self.palette)
  811.             write_chunk(outfile, b'PLTE', p)
  812.             if t:
  813.                 # tRNS chunk is optional;
  814.                 # Only needed if palette entries have alpha.
  815.                 write_chunk(outfile, b'tRNS', t)
  816.  
  817.         # http://www.w3.org/TR/PNG/#11tRNS
  818.         if self.transparent is not None:
  819.             if self.greyscale:
  820.                 fmt = "!1H"
  821.             else:
  822.                 fmt = "!3H"
  823.             write_chunk(outfile, b'tRNS',
  824.                         struct.pack(fmt, *self.transparent))
  825.  
  826.         # http://www.w3.org/TR/PNG/#11bKGD
  827.         if self.background is not None:
  828.             if self.greyscale:
  829.                 fmt = "!1H"
  830.             else:
  831.                 fmt = "!3H"
  832.             write_chunk(outfile, b'bKGD',
  833.                         struct.pack(fmt, *self.background))
  834.  
  835.         # http://www.w3.org/TR/PNG/#11pHYs
  836.         if (self.x_pixels_per_unit is not None and
  837.                 self.y_pixels_per_unit is not None):
  838.             tup = (self.x_pixels_per_unit,
  839.                    self.y_pixels_per_unit,
  840.                    int(self.unit_is_meter))
  841.             write_chunk(outfile, b'pHYs', struct.pack("!LLB", *tup))
  842.  
  843.     def write_array(self, outfile, pixels):
  844.         """
  845.        Write an array that holds all the image values
  846.        as a PNG file on the output file.
  847.        See also :meth:`write` method.
  848.        """
  849.  
  850.         if self.interlace:
  851.             if type(pixels) != array:
  852.                 # Coerce to array type
  853.                 fmt = 'BH'[self.bitdepth > 8]
  854.                 pixels = array(fmt, pixels)
  855.             self.write_passes(outfile, self.array_scanlines_interlace(pixels))
  856.         else:
  857.             self.write_passes(outfile, self.array_scanlines(pixels))
  858.  
  859.     def array_scanlines(self, pixels):
  860.         """
  861.        Generates rows (each a sequence of values) from
  862.        a single array of values.
  863.        """
  864.  
  865.         # Values per row
  866.         vpr = self.width * self.planes
  867.         stop = 0
  868.         for y in range(self.height):
  869.             start = stop
  870.             stop = start + vpr
  871.             yield pixels[start:stop]
  872.  
  873.     def array_scanlines_interlace(self, pixels):
  874.         """
  875.        Generator for interlaced scanlines from an array.
  876.        `pixels` is the full source image as a single array of values.
  877.        The generator yields each scanline of the reduced passes in turn,
  878.        each scanline being a sequence of values.
  879.        """
  880.  
  881.         # http://www.w3.org/TR/PNG/#8InterlaceMethods
  882.         # Array type.
  883.         fmt = 'BH'[self.bitdepth > 8]
  884.         # Value per row
  885.         vpr = self.width * self.planes
  886.  
  887.         # Each iteration generates a scanline starting at (x, y)
  888.         # and consisting of every xstep pixels.
  889.         for lines in adam7_generate(self.width, self.height):
  890.             for x, y, xstep in lines:
  891.                 # Pixels per row (of reduced image)
  892.                 ppr = int(math.ceil((self.width - x) / float(xstep)))
  893.                 # Values per row (of reduced image)
  894.                 reduced_row_len = ppr * self.planes
  895.                 if xstep == 1:
  896.                     # Easy case: line is a simple slice.
  897.                     offset = y * vpr
  898.                     yield pixels[offset: offset + vpr]
  899.                     continue
  900.                 # We have to step by xstep,
  901.                 # which we can do one plane at a time
  902.                 # using the step in Python slices.
  903.                 row = array(fmt)
  904.                 # There's no easier way to set the length of an array
  905.                 row.extend(pixels[0:reduced_row_len])
  906.                 offset = y * vpr + x * self.planes
  907.                 end_offset = (y + 1) * vpr
  908.                 skip = self.planes * xstep
  909.                 for i in range(self.planes):
  910.                     row[i::self.planes] = \
  911.                         pixels[offset + i: end_offset: skip]
  912.                 yield row
  913.  
  914.  
  915. def write_chunk(outfile, tag, data=b''):
  916.     """
  917.    Write a PNG chunk to the output file, including length and
  918.    checksum.
  919.    """
  920.  
  921.     data = bytes(data)
  922.     # http://www.w3.org/TR/PNG/#5Chunk-layout
  923.     outfile.write(struct.pack("!I", len(data)))
  924.     outfile.write(tag)
  925.     outfile.write(data)
  926.     checksum = zlib.crc32(tag)
  927.     checksum = zlib.crc32(data, checksum)
  928.     checksum &= 2 ** 32 - 1
  929.     outfile.write(struct.pack("!I", checksum))
  930.  
  931.  
  932. def write_chunks(out, chunks):
  933.     """Create a PNG file by writing out the chunks."""
  934.  
  935.     out.write(signature)
  936.     for chunk in chunks:
  937.         write_chunk(out, *chunk)
  938.  
  939.  
  940. def rescale_rows(rows, rescale):
  941.     """
  942.    Take each row in rows (an iterator) and yield
  943.    a fresh row with the pixels scaled according to
  944.    the rescale parameters in the list `rescale`.
  945.    Each element of `rescale` is a tuple of
  946.    (source_bitdepth, target_bitdepth),
  947.    with one element per channel.
  948.    """
  949.  
  950.     # One factor for each channel
  951.     fs = [float(2 ** s[1] - 1)/float(2 ** s[0] - 1)
  952.           for s in rescale]
  953.  
  954.     # Assume all target_bitdepths are the same
  955.     target_bitdepths = set(s[1] for s in rescale)
  956.     assert len(target_bitdepths) == 1
  957.     (target_bitdepth, ) = target_bitdepths
  958.     typecode = 'BH'[target_bitdepth > 8]
  959.  
  960.     # Number of channels
  961.     n_chans = len(rescale)
  962.  
  963.     for row in rows:
  964.         rescaled_row = array(typecode, iter(row))
  965.         for i in range(n_chans):
  966.             channel = array(
  967.                 typecode,
  968.                 (int(round(fs[i] * x)) for x in row[i::n_chans]))
  969.             rescaled_row[i::n_chans] = channel
  970.         yield rescaled_row
  971.  
  972.  
  973. def pack_rows(rows, bitdepth):
  974.     """Yield packed rows that are a byte array.
  975.    Each byte is packed with the values from several pixels.
  976.    """
  977.  
  978.     assert bitdepth < 8
  979.     assert 8 % bitdepth == 0
  980.  
  981.     # samples per byte
  982.     spb = int(8 / bitdepth)
  983.  
  984.     def make_byte(block):
  985.         """Take a block of (2, 4, or 8) values,
  986.        and pack them into a single byte.
  987.        """
  988.  
  989.         res = 0
  990.         for v in block:
  991.             res = (res << bitdepth) + v
  992.         return res
  993.  
  994.     for row in rows:
  995.         a = bytearray(row)
  996.         # Adding padding bytes so we can group into a whole
  997.         # number of spb-tuples.
  998.         n = float(len(a))
  999.         extra = math.ceil(n / spb) * spb - n
  1000.         a.extend([0] * int(extra))
  1001.         # Pack into bytes.
  1002.         # Each block is the samples for one byte.
  1003.         blocks = group(a, spb)
  1004.         yield bytearray(make_byte(block) for block in blocks)
  1005.  
  1006.  
  1007. def unpack_rows(rows):
  1008.     """Unpack each row from being 16-bits per value,
  1009.    to being a sequence of bytes.
  1010.    """
  1011.     for row in rows:
  1012.         fmt = '!%dH' % len(row)
  1013.         yield bytearray(struct.pack(fmt, *row))
  1014.  
  1015.  
  1016. def make_palette_chunks(palette):
  1017.     """
  1018.    Create the byte sequences for a ``PLTE`` and
  1019.    if necessary a ``tRNS`` chunk.
  1020.    Returned as a pair (*p*, *t*).
  1021.    *t* will be ``None`` if no ``tRNS`` chunk is necessary.
  1022.    """
  1023.  
  1024.     p = bytearray()
  1025.     t = bytearray()
  1026.  
  1027.     for x in palette:
  1028.         p.extend(x[0:3])
  1029.         if len(x) > 3:
  1030.             t.append(x[3])
  1031.     if t:
  1032.         return p, t
  1033.     return p, None
  1034.  
  1035.  
  1036. def check_bitdepth_rescale(
  1037.         palette, bitdepth, transparent, alpha, greyscale):
  1038.     """
  1039.    Returns (bitdepth, rescale) pair.
  1040.    """
  1041.  
  1042.     if palette:
  1043.         if len(bitdepth) != 1:
  1044.             raise ProtocolError(
  1045.                 "with palette, only a single bitdepth may be used")
  1046.         (bitdepth, ) = bitdepth
  1047.         if bitdepth not in (1, 2, 4, 8):
  1048.             raise ProtocolError(
  1049.                 "with palette, bitdepth must be 1, 2, 4, or 8")
  1050.         if transparent is not None:
  1051.             raise ProtocolError("transparent and palette not compatible")
  1052.         if alpha:
  1053.             raise ProtocolError("alpha and palette not compatible")
  1054.         if greyscale:
  1055.             raise ProtocolError("greyscale and palette not compatible")
  1056.         return bitdepth, None
  1057.  
  1058.     # No palette, check for sBIT chunk generation.
  1059.  
  1060.     if greyscale and not alpha:
  1061.         # Single channel, L.
  1062.         (bitdepth,) = bitdepth
  1063.         if bitdepth in (1, 2, 4, 8, 16):
  1064.             return bitdepth, None
  1065.         if bitdepth > 8:
  1066.             targetbitdepth = 16
  1067.         elif bitdepth == 3:
  1068.             targetbitdepth = 4
  1069.         else:
  1070.             assert bitdepth in (5, 6, 7)
  1071.             targetbitdepth = 8
  1072.         return targetbitdepth, [(bitdepth, targetbitdepth)]
  1073.  
  1074.     assert alpha or not greyscale
  1075.  
  1076.     depth_set = tuple(set(bitdepth))
  1077.     if depth_set in [(8,), (16,)]:
  1078.         # No sBIT required.
  1079.         (bitdepth, ) = depth_set
  1080.         return bitdepth, None
  1081.  
  1082.     targetbitdepth = (8, 16)[max(bitdepth) > 8]
  1083.     return targetbitdepth, [(b, targetbitdepth) for b in bitdepth]
  1084.  
  1085.  
  1086. # Regex for decoding mode string
  1087. RegexModeDecode = re.compile("(LA?|RGBA?);?([0-9]*)", flags=re.IGNORECASE)
  1088.  
  1089.  
  1090. def from_array(a, mode=None, info={}):
  1091.     """
  1092.    Create a PNG :class:`Image` object from a 2-dimensional array.
  1093.    One application of this function is easy PIL-style saving:
  1094.    ``png.from_array(pixels, 'L').save('foo.png')``.
  1095.  
  1096.    Unless they are specified using the *info* parameter,
  1097.    the PNG's height and width are taken from the array size.
  1098.    The first axis is the height; the second axis is the
  1099.    ravelled width and channel index.
  1100.    The array is treated is a sequence of rows,
  1101.    each row being a sequence of values (``width*channels`` in number).
  1102.    So an RGB image that is 16 pixels high and 8 wide will
  1103.    occupy a 2-dimensional array that is 16x24
  1104.    (each row will be 8*3 = 24 sample values).
  1105.  
  1106.    *mode* is a string that specifies the image colour format in a
  1107.    PIL-style mode.  It can be:
  1108.  
  1109.    ``'L'``
  1110.      greyscale (1 channel)
  1111.    ``'LA'``
  1112.      greyscale with alpha (2 channel)
  1113.    ``'RGB'``
  1114.      colour image (3 channel)
  1115.    ``'RGBA'``
  1116.      colour image with alpha (4 channel)
  1117.  
  1118.    The mode string can also specify the bit depth
  1119.    (overriding how this function normally derives the bit depth,
  1120.    see below).
  1121.    Appending ``';16'`` to the mode will cause the PNG to be
  1122.    16 bits per channel;
  1123.    any decimal from 1 to 16 can be used to specify the bit depth.
  1124.  
  1125.    When a 2-dimensional array is used *mode* determines how many
  1126.    channels the image has, and so allows the width to be derived from
  1127.    the second array dimension.
  1128.  
  1129.    The array is expected to be a ``numpy`` array,
  1130.    but it can be any suitable Python sequence.
  1131.    For example, a list of lists can be used:
  1132.    ``png.from_array([[0, 255, 0], [255, 0, 255]], 'L')``.
  1133.    The exact rules are: ``len(a)`` gives the first dimension, height;
  1134.    ``len(a[0])`` gives the second dimension.
  1135.    It's slightly more complicated than that because
  1136.    an iterator of rows can be used, and it all still works.
  1137.    Using an iterator allows data to be streamed efficiently.
  1138.  
  1139.    The bit depth of the PNG is normally taken from
  1140.    the array element's datatype
  1141.    (but if *mode* specifies a bitdepth then that is used instead).
  1142.    The array element's datatype is determined in a way which
  1143.    is supposed to work both for ``numpy`` arrays and for Python
  1144.    ``array.array`` objects.
  1145.    A 1 byte datatype will give a bit depth of 8,
  1146.    a 2 byte datatype will give a bit depth of 16.
  1147.    If the datatype does not have an implicit size,
  1148.    like the above example where it is a plain Python list of lists,
  1149.    then a default of 8 is used.
  1150.  
  1151.    The *info* parameter is a dictionary that can
  1152.    be used to specify metadata (in the same style as
  1153.    the arguments to the :class:`png.Writer` class).
  1154.    For this function the keys that are useful are:
  1155.  
  1156.    height
  1157.      overrides the height derived from the array dimensions and
  1158.      allows *a* to be an iterable.
  1159.    width
  1160.      overrides the width derived from the array dimensions.
  1161.    bitdepth
  1162.      overrides the bit depth derived from the element datatype
  1163.      (but must match *mode* if that also specifies a bit depth).
  1164.  
  1165.    Generally anything specified in the *info* dictionary will
  1166.    override any implicit choices that this function would otherwise make,
  1167.    but must match any explicit ones.
  1168.    For example, if the *info* dictionary has a ``greyscale`` key then
  1169.    this must be true when mode is ``'L'`` or ``'LA'`` and
  1170.    false when mode is ``'RGB'`` or ``'RGBA'``.
  1171.    """
  1172.  
  1173.     # We abuse the *info* parameter by modifying it.  Take a copy here.
  1174.     # (Also typechecks *info* to some extent).
  1175.     info = dict(info)
  1176.  
  1177.     # Syntax check mode string.
  1178.     match = RegexModeDecode.match(mode)
  1179.     if not match:
  1180.         raise Error("mode string should be 'RGB' or 'L;16' or similar.")
  1181.  
  1182.     mode, bitdepth = match.groups()
  1183.     if bitdepth:
  1184.         bitdepth = int(bitdepth)
  1185.  
  1186.     # Colour format.
  1187.     if 'greyscale' in info:
  1188.         if bool(info['greyscale']) != ('L' in mode):
  1189.             raise ProtocolError("info['greyscale'] should match mode.")
  1190.     info['greyscale'] = 'L' in mode
  1191.  
  1192.     alpha = 'A' in mode
  1193.     if 'alpha' in info:
  1194.         if bool(info['alpha']) != alpha:
  1195.             raise ProtocolError("info['alpha'] should match mode.")
  1196.     info['alpha'] = alpha
  1197.  
  1198.     # Get bitdepth from *mode* if possible.
  1199.     if bitdepth:
  1200.         if info.get("bitdepth") and bitdepth != info['bitdepth']:
  1201.             raise ProtocolError(
  1202.                 "bitdepth (%d) should match bitdepth of info (%d)." %
  1203.                 (bitdepth, info['bitdepth']))
  1204.         info['bitdepth'] = bitdepth
  1205.  
  1206.     # Fill in and/or check entries in *info*.
  1207.     # Dimensions.
  1208.     width, height = check_sizes(
  1209.         info.get("size"),
  1210.         info.get("width"),
  1211.         info.get("height"))
  1212.     if width:
  1213.         info["width"] = width
  1214.     if height:
  1215.         info["height"] = height
  1216.  
  1217.     if "height" not in info:
  1218.         try:
  1219.             info['height'] = len(a)
  1220.         except TypeError:
  1221.             raise ProtocolError(
  1222.                 "len(a) does not work, supply info['height'] instead.")
  1223.  
  1224.     planes = len(mode)
  1225.     if 'planes' in info:
  1226.         if info['planes'] != planes:
  1227.             raise Error("info['planes'] should match mode.")
  1228.  
  1229.     # In order to work out whether we the array is 2D or 3D we need its
  1230.     # first row, which requires that we take a copy of its iterator.
  1231.     # We may also need the first row to derive width and bitdepth.
  1232.     a, t = itertools.tee(a)
  1233.     row = next(t)
  1234.     del t
  1235.  
  1236.     testelement = row
  1237.     if 'width' not in info:
  1238.         width = len(row) // planes
  1239.         info['width'] = width
  1240.  
  1241.     if 'bitdepth' not in info:
  1242.         try:
  1243.             dtype = testelement.dtype
  1244.             # goto the "else:" clause.  Sorry.
  1245.         except AttributeError:
  1246.             try:
  1247.                 # Try a Python array.array.
  1248.                 bitdepth = 8 * testelement.itemsize
  1249.             except AttributeError:
  1250.                 # We can't determine it from the array element's datatype,
  1251.                 # use a default of 8.
  1252.                 bitdepth = 8
  1253.         else:
  1254.             # If we got here without exception,
  1255.             # we now assume that the array is a numpy array.
  1256.             if dtype.kind == 'b':
  1257.                 bitdepth = 1
  1258.             else:
  1259.                 bitdepth = 8 * dtype.itemsize
  1260.         info['bitdepth'] = bitdepth
  1261.  
  1262.     for thing in ["width", "height", "bitdepth", "greyscale", "alpha"]:
  1263.         assert thing in info
  1264.  
  1265.     return Image(a, info)
  1266.  
  1267.  
  1268. # So that refugee's from PIL feel more at home.  Not documented.
  1269. fromarray = from_array
  1270.  
  1271.  
  1272. class Image:
  1273.     """A PNG image.  You can create an :class:`Image` object from
  1274.    an array of pixels by calling :meth:`png.from_array`.  It can be
  1275.    saved to disk with the :meth:`save` method.
  1276.    """
  1277.  
  1278.     def __init__(self, rows, info):
  1279.         """
  1280.        .. note ::
  1281.  
  1282.          The constructor is not public.  Please do not call it.
  1283.        """
  1284.  
  1285.         self.rows = rows
  1286.         self.info = info
  1287.  
  1288.     def save(self, file):
  1289.         """Save the image to the named *file*.
  1290.  
  1291.        See `.write()` if you already have an open file object.
  1292.  
  1293.        In general, you can only call this method once;
  1294.        after it has been called the first time the PNG image is written,
  1295.        the source data will have been streamed, and
  1296.        cannot be streamed again.
  1297.        """
  1298.  
  1299.         w = Writer(**self.info)
  1300.  
  1301.         with open(file, 'wb') as fd:
  1302.             w.write(fd, self.rows)
  1303.  
  1304.     def write(self, file):
  1305.         """Write the image to the open file object.
  1306.  
  1307.        See `.save()` if you have a filename.
  1308.  
  1309.        In general, you can only call this method once;
  1310.        after it has been called the first time the PNG image is written,
  1311.        the source data will have been streamed, and
  1312.        cannot be streamed again.
  1313.        """
  1314.  
  1315.         w = Writer(**self.info)
  1316.         w.write(file, self.rows)
  1317.  
  1318.  
  1319. class Reader:
  1320.     """
  1321.    Pure Python PNG decoder in pure Python.
  1322.    """
  1323.  
  1324.     def __init__(self, _guess=None, filename=None, file=None, bytes=None):
  1325.         """
  1326.        The constructor expects exactly one keyword argument.
  1327.        If you supply a positional argument instead,
  1328.        it will guess the input type.
  1329.        Choose from the following keyword arguments:
  1330.  
  1331.        filename
  1332.          Name of input file (a PNG file).
  1333.        file
  1334.          A file-like object (object with a read() method).
  1335.        bytes
  1336.          ``bytes`` or ``bytearray`` with PNG data.
  1337.  
  1338.        """
  1339.         keywords_supplied = (
  1340.             (_guess is not None) +
  1341.             (filename is not None) +
  1342.             (file is not None) +
  1343.             (bytes is not None))
  1344.         if keywords_supplied != 1:
  1345.             raise TypeError("Reader() takes exactly 1 argument")
  1346.  
  1347.         # Will be the first 8 bytes, later on.  See validate_signature.
  1348.         self.signature = None
  1349.         self.transparent = None
  1350.         # A pair of (len,type) if a chunk has been read but its data and
  1351.         # checksum have not (in other words the file position is just
  1352.         # past the 4 bytes that specify the chunk type).
  1353.         # See preamble method for how this is used.
  1354.         self.atchunk = None
  1355.  
  1356.         if _guess is not None:
  1357.             if isarray(_guess):
  1358.                 bytes = _guess
  1359.             elif isinstance(_guess, str):
  1360.                 filename = _guess
  1361.             elif hasattr(_guess, 'read'):
  1362.                 file = _guess
  1363.  
  1364.         if bytes is not None:
  1365.             self.file = io.BytesIO(bytes)
  1366.         elif filename is not None:
  1367.             self.file = open(filename, "rb")
  1368.         elif file is not None:
  1369.             self.file = file
  1370.         else:
  1371.             raise ProtocolError("expecting filename, file or bytes array")
  1372.  
  1373.     def chunk(self, lenient=False):
  1374.         """
  1375.        Read the next PNG chunk from the input file;
  1376.        returns a (*type*, *data*) tuple.
  1377.        *type* is the chunk's type as a byte string
  1378.        (all PNG chunk types are 4 bytes long).
  1379.        *data* is the chunk's data content, as a byte string.
  1380.  
  1381.        If the optional `lenient` argument evaluates to `True`,
  1382.        checksum failures will raise warnings rather than exceptions.
  1383.        """
  1384.  
  1385.         self.validate_signature()
  1386.  
  1387.         # http://www.w3.org/TR/PNG/#5Chunk-layout
  1388.         if not self.atchunk:
  1389.             self.atchunk = self._chunk_len_type()
  1390.         if not self.atchunk:
  1391.             raise ChunkError("No more chunks.")
  1392.         length, type = self.atchunk
  1393.         self.atchunk = None
  1394.  
  1395.         data = self.file.read(length)
  1396.         if len(data) != length:
  1397.             raise ChunkError(
  1398.                 'Chunk %s too short for required %i octets.'
  1399.                 % (type, length))
  1400.         checksum = self.file.read(4)
  1401.         if len(checksum) != 4:
  1402.             raise ChunkError('Chunk %s too short for checksum.' % type)
  1403.         verify = zlib.crc32(type)
  1404.         verify = zlib.crc32(data, verify)
  1405.         # Whether the output from zlib.crc32 is signed or not varies
  1406.         # according to hideous implementation details, see
  1407.         # http://bugs.python.org/issue1202 .
  1408.         # We coerce it to be positive here (in a way which works on
  1409.         # Python 2.3 and older).
  1410.         verify &= 2**32 - 1
  1411.         verify = struct.pack('!I', verify)
  1412.         if checksum != verify:
  1413.             (a, ) = struct.unpack('!I', checksum)
  1414.             (b, ) = struct.unpack('!I', verify)
  1415.             message = ("Checksum error in %s chunk: 0x%08X != 0x%08X."
  1416.                        % (type.decode('ascii'), a, b))
  1417.             if lenient:
  1418.                 warnings.warn(message, RuntimeWarning)
  1419.             else:
  1420.                 raise ChunkError(message)
  1421.         return type, data
  1422.  
  1423.     def chunks(self):
  1424.         """Return an iterator that will yield each chunk as a
  1425.        (*chunktype*, *content*) pair.
  1426.        """
  1427.  
  1428.         while True:
  1429.             t, v = self.chunk()
  1430.             yield t, v
  1431.             if t == b'IEND':
  1432.                 break
  1433.  
  1434.     def undo_filter(self, filter_type, scanline, previous):
  1435.         """
  1436.        Undo the filter for a scanline.
  1437.        `scanline` is a sequence of bytes that
  1438.        does not include the initial filter type byte.
  1439.        `previous` is decoded previous scanline
  1440.        (for straightlaced images this is the previous pixel row,
  1441.        but for interlaced images, it is
  1442.        the previous scanline in the reduced image,
  1443.        which in general is not the previous pixel row in the final image).
  1444.        When there is no previous scanline
  1445.        (the first row of a straightlaced image,
  1446.        or the first row in one of the passes in an interlaced image),
  1447.        then this argument should be ``None``.
  1448.  
  1449.        The scanline will have the effects of filtering removed;
  1450.        the result will be returned as a fresh sequence of bytes.
  1451.        """
  1452.  
  1453.         # :todo: Would it be better to update scanline in place?
  1454.         result = scanline
  1455.  
  1456.         if filter_type == 0:
  1457.             return result
  1458.  
  1459.         if filter_type not in (1, 2, 3, 4):
  1460.             raise FormatError(
  1461.                 'Invalid PNG Filter Type.  '
  1462.                 'See http://www.w3.org/TR/2003/REC-PNG-20031110/#9Filters .')
  1463.  
  1464.         # Filter unit.  The stride from one pixel to the corresponding
  1465.         # byte from the previous pixel.  Normally this is the pixel
  1466.         # size in bytes, but when this is smaller than 1, the previous
  1467.         # byte is used instead.
  1468.         fu = max(1, self.psize)
  1469.  
  1470.         # For the first line of a pass, synthesize a dummy previous
  1471.         # line.  An alternative approach would be to observe that on the
  1472.         # first line 'up' is the same as 'null', 'paeth' is the same
  1473.         # as 'sub', with only 'average' requiring any special case.
  1474.         if not previous:
  1475.             previous = bytearray([0] * len(scanline))
  1476.  
  1477.         # Call appropriate filter algorithm.  Note that 0 has already
  1478.         # been dealt with.
  1479.         fn = (None,
  1480.               undo_filter_sub,
  1481.               undo_filter_up,
  1482.               undo_filter_average,
  1483.               undo_filter_paeth)[filter_type]
  1484.         fn(fu, scanline, previous, result)
  1485.         return result
  1486.  
  1487.     def _deinterlace(self, raw):
  1488.         """
  1489.        Read raw pixel data, undo filters, deinterlace, and flatten.
  1490.        Return a single array of values.
  1491.        """
  1492.  
  1493.         # Values per row (of the target image)
  1494.         vpr = self.width * self.planes
  1495.  
  1496.         # Values per image
  1497.         vpi = vpr * self.height
  1498.         # Interleaving writes to the output array randomly
  1499.         # (well, not quite), so the entire output array must be in memory.
  1500.         # Make a result array, and make it big enough.
  1501.         if self.bitdepth > 8:
  1502.             a = array('H', [0] * vpi)
  1503.         else:
  1504.             a = bytearray([0] * vpi)
  1505.         source_offset = 0
  1506.  
  1507.         for lines in adam7_generate(self.width, self.height):
  1508.             # The previous (reconstructed) scanline.
  1509.             # `None` at the beginning of a pass
  1510.             # to indicate that there is no previous line.
  1511.             recon = None
  1512.             for x, y, xstep in lines:
  1513.                 # Pixels per row (reduced pass image)
  1514.                 ppr = int(math.ceil((self.width - x) / float(xstep)))
  1515.                 # Row size in bytes for this pass.
  1516.                 row_size = int(math.ceil(self.psize * ppr))
  1517.  
  1518.                 filter_type = raw[source_offset]
  1519.                 source_offset += 1
  1520.                 scanline = raw[source_offset: source_offset + row_size]
  1521.                 source_offset += row_size
  1522.                 recon = self.undo_filter(filter_type, scanline, recon)
  1523.                 # Convert so that there is one element per pixel value
  1524.                 flat = self._bytes_to_values(recon, width=ppr)
  1525.                 if xstep == 1:
  1526.                     assert x == 0
  1527.                     offset = y * vpr
  1528.                     a[offset: offset + vpr] = flat
  1529.                 else:
  1530.                     offset = y * vpr + x * self.planes
  1531.                     end_offset = (y + 1) * vpr
  1532.                     skip = self.planes * xstep
  1533.                     for i in range(self.planes):
  1534.                         a[offset + i: end_offset: skip] = \
  1535.                             flat[i:: self.planes]
  1536.  
  1537.         return a
  1538.  
  1539.     def _iter_bytes_to_values(self, byte_rows):
  1540.         """
  1541.        Iterator that yields each scanline;
  1542.        each scanline being a sequence of values.
  1543.        `byte_rows` should be an iterator that yields
  1544.        the bytes of each row in turn.
  1545.        """
  1546.  
  1547.         for row in byte_rows:
  1548.             yield self._bytes_to_values(row)
  1549.  
  1550.     def _bytes_to_values(self, bs, width=None):
  1551.         """Convert a packed row of bytes into a row of values.
  1552.        Result will be a freshly allocated object,
  1553.        not shared with the argument.
  1554.        """
  1555.  
  1556.         if self.bitdepth == 8:
  1557.             return bytearray(bs)
  1558.         if self.bitdepth == 16:
  1559.             return array('H',
  1560.                          struct.unpack('!%dH' % (len(bs) // 2), bs))
  1561.  
  1562.         assert self.bitdepth < 8
  1563.         if width is None:
  1564.             width = self.width
  1565.         # Samples per byte
  1566.         spb = 8 // self.bitdepth
  1567.         out = bytearray()
  1568.         mask = 2**self.bitdepth - 1
  1569.         shifts = [self.bitdepth * i
  1570.                   for i in reversed(list(range(spb)))]
  1571.         for o in bs:
  1572.             out.extend([mask & (o >> i) for i in shifts])
  1573.         return out[:width]
  1574.  
  1575.     def _iter_straight_packed(self, byte_blocks):
  1576.         """Iterator that undoes the effect of filtering;
  1577.        yields each row as a sequence of packed bytes.
  1578.        Assumes input is straightlaced.
  1579.        `byte_blocks` should be an iterable that yields the raw bytes
  1580.        in blocks of arbitrary size.
  1581.        """
  1582.  
  1583.         # length of row, in bytes
  1584.         rb = self.row_bytes
  1585.         a = bytearray()
  1586.         # The previous (reconstructed) scanline.
  1587.         # None indicates first line of image.
  1588.         recon = None
  1589.         for some_bytes in byte_blocks:
  1590.             a.extend(some_bytes)
  1591.             while len(a) >= rb + 1:
  1592.                 filter_type = a[0]
  1593.                 scanline = a[1: rb + 1]
  1594.                 del a[: rb + 1]
  1595.                 recon = self.undo_filter(filter_type, scanline, recon)
  1596.                 yield recon
  1597.         if len(a) != 0:
  1598.             # :file:format We get here with a file format error:
  1599.             # when the available bytes (after decompressing) do not
  1600.             # pack into exact rows.
  1601.             raise FormatError('Wrong size for decompressed IDAT chunk.')
  1602.         assert len(a) == 0
  1603.  
  1604.     def validate_signature(self):
  1605.         """
  1606.        If signature (header) has not been read then read and
  1607.        validate it; otherwise do nothing.
  1608.        """
  1609.  
  1610.         if self.signature:
  1611.             return
  1612.         self.signature = self.file.read(8)
  1613.         if self.signature != signature:
  1614.             raise FormatError("PNG file has invalid signature.")
  1615.  
  1616.     def preamble(self, lenient=False):
  1617.         """
  1618.        Extract the image metadata by reading
  1619.        the initial part of the PNG file up to
  1620.        the start of the ``IDAT`` chunk.
  1621.        All the chunks that precede the ``IDAT`` chunk are
  1622.        read and either processed for metadata or discarded.
  1623.  
  1624.        If the optional `lenient` argument evaluates to `True`,
  1625.        checksum failures will raise warnings rather than exceptions.
  1626.        """
  1627.  
  1628.         self.validate_signature()
  1629.  
  1630.         while True:
  1631.             if not self.atchunk:
  1632.                 self.atchunk = self._chunk_len_type()
  1633.                 if self.atchunk is None:
  1634.                     raise FormatError('This PNG file has no IDAT chunks.')
  1635.             if self.atchunk[1] == b'IDAT':
  1636.                 return
  1637.             self.process_chunk(lenient=lenient)
  1638.  
  1639.     def _chunk_len_type(self):
  1640.         """
  1641.        Reads just enough of the input to
  1642.        determine the next chunk's length and type;
  1643.        return a (*length*, *type*) pair where *type* is a byte sequence.
  1644.        If there are no more chunks, ``None`` is returned.
  1645.        """
  1646.  
  1647.         x = self.file.read(8)
  1648.         if not x:
  1649.             return None
  1650.         if len(x) != 8:
  1651.             raise FormatError(
  1652.                 'End of file whilst reading chunk length and type.')
  1653.         length, type = struct.unpack('!I4s', x)
  1654.         if length > 2 ** 31 - 1:
  1655.             raise FormatError('Chunk %s is too large: %d.' % (type, length))
  1656.         # Check that all bytes are in valid ASCII range.
  1657.         # https://www.w3.org/TR/2003/REC-PNG-20031110/#5Chunk-layout
  1658.         type_bytes = set(bytearray(type))
  1659.         if not(type_bytes <= set(range(65, 91)) | set(range(97, 123))):
  1660.             raise FormatError(
  1661.                 'Chunk %r has invalid Chunk Type.'
  1662.                 % list(type))
  1663.         return length, type
  1664.  
  1665.     def process_chunk(self, lenient=False):
  1666.         """
  1667.        Process the next chunk and its data.
  1668.        This only processes the following chunk types:
  1669.        ``IHDR``, ``PLTE``, ``bKGD``, ``tRNS``, ``gAMA``, ``sBIT``, ``pHYs``.
  1670.        All other chunk types are ignored.
  1671.  
  1672.        If the optional `lenient` argument evaluates to `True`,
  1673.        checksum failures will raise warnings rather than exceptions.
  1674.        """
  1675.  
  1676.         type, data = self.chunk(lenient=lenient)
  1677.         method = '_process_' + type.decode('ascii')
  1678.         m = getattr(self, method, None)
  1679.         if m:
  1680.             m(data)
  1681.  
  1682.     def _process_IHDR(self, data):
  1683.         # http://www.w3.org/TR/PNG/#11IHDR
  1684.         if len(data) != 13:
  1685.             raise FormatError('IHDR chunk has incorrect length.')
  1686.         (self.width, self.height, self.bitdepth, self.color_type,
  1687.          self.compression, self.filter,
  1688.          self.interlace) = struct.unpack("!2I5B", data)
  1689.  
  1690.         check_bitdepth_colortype(self.bitdepth, self.color_type)
  1691.  
  1692.         if self.compression != 0:
  1693.             raise FormatError(
  1694.                 "Unknown compression method %d" % self.compression)
  1695.         if self.filter != 0:
  1696.             raise FormatError(
  1697.                 "Unknown filter method %d,"
  1698.                 " see http://www.w3.org/TR/2003/REC-PNG-20031110/#9Filters ."
  1699.                 % self.filter)
  1700.         if self.interlace not in (0, 1):
  1701.             raise FormatError(
  1702.                 "Unknown interlace method %d, see "
  1703.                 "http://www.w3.org/TR/2003/REC-PNG-20031110/#8InterlaceMethods"
  1704.                 " ."
  1705.                 % self.interlace)
  1706.  
  1707.         # Derived values
  1708.         # http://www.w3.org/TR/PNG/#6Colour-values
  1709.         colormap = bool(self.color_type & 1)
  1710.         greyscale = not(self.color_type & 2)
  1711.         alpha = bool(self.color_type & 4)
  1712.         color_planes = (3, 1)[greyscale or colormap]
  1713.         planes = color_planes + alpha
  1714.  
  1715.         self.colormap = colormap
  1716.         self.greyscale = greyscale
  1717.         self.alpha = alpha
  1718.         self.color_planes = color_planes
  1719.         self.planes = planes
  1720.         self.psize = float(self.bitdepth) / float(8) * planes
  1721.         if int(self.psize) == self.psize:
  1722.             self.psize = int(self.psize)
  1723.         self.row_bytes = int(math.ceil(self.width * self.psize))
  1724.         # Stores PLTE chunk if present, and is used to check
  1725.         # chunk ordering constraints.
  1726.         self.plte = None
  1727.         # Stores tRNS chunk if present, and is used to check chunk
  1728.         # ordering constraints.
  1729.         self.trns = None
  1730.         # Stores sBIT chunk if present.
  1731.         self.sbit = None
  1732.  
  1733.     def _process_PLTE(self, data):
  1734.         # http://www.w3.org/TR/PNG/#11PLTE
  1735.         if self.plte:
  1736.             warnings.warn("Multiple PLTE chunks present.")
  1737.         self.plte = data
  1738.         if len(data) % 3 != 0:
  1739.             raise FormatError(
  1740.                 "PLTE chunk's length should be a multiple of 3.")
  1741.         if len(data) > (2 ** self.bitdepth) * 3:
  1742.             raise FormatError("PLTE chunk is too long.")
  1743.         if len(data) == 0:
  1744.             raise FormatError("Empty PLTE is not allowed.")
  1745.  
  1746.     def _process_bKGD(self, data):
  1747.         try:
  1748.             if self.colormap:
  1749.                 if not self.plte:
  1750.                     warnings.warn(
  1751.                         "PLTE chunk is required before bKGD chunk.")
  1752.                 self.background = struct.unpack('B', data)
  1753.             else:
  1754.                 self.background = struct.unpack("!%dH" % self.color_planes,
  1755.                                                 data)
  1756.         except struct.error:
  1757.             raise FormatError("bKGD chunk has incorrect length.")
  1758.  
  1759.     def _process_tRNS(self, data):
  1760.         # http://www.w3.org/TR/PNG/#11tRNS
  1761.         self.trns = data
  1762.         if self.colormap:
  1763.             if not self.plte:
  1764.                 warnings.warn("PLTE chunk is required before tRNS chunk.")
  1765.             else:
  1766.                 if len(data) > len(self.plte) / 3:
  1767.                     # Was warning, but promoted to Error as it
  1768.                     # would otherwise cause pain later on.
  1769.                     raise FormatError("tRNS chunk is too long.")
  1770.         else:
  1771.             if self.alpha:
  1772.                 raise FormatError(
  1773.                     "tRNS chunk is not valid with colour type %d." %
  1774.                     self.color_type)
  1775.             try:
  1776.                 self.transparent = \
  1777.                     struct.unpack("!%dH" % self.color_planes, data)
  1778.             except struct.error:
  1779.                 raise FormatError("tRNS chunk has incorrect length.")
  1780.  
  1781.     def _process_gAMA(self, data):
  1782.         try:
  1783.             self.gamma = struct.unpack("!L", data)[0] / 100000.0
  1784.         except struct.error:
  1785.             raise FormatError("gAMA chunk has incorrect length.")
  1786.  
  1787.     def _process_sBIT(self, data):
  1788.         self.sbit = data
  1789.         if (self.colormap and len(data) != 3 or
  1790.                 not self.colormap and len(data) != self.planes):
  1791.             raise FormatError("sBIT chunk has incorrect length.")
  1792.  
  1793.     def _process_pHYs(self, data):
  1794.         # http://www.w3.org/TR/PNG/#11pHYs
  1795.         self.phys = data
  1796.         fmt = "!LLB"
  1797.         if len(data) != struct.calcsize(fmt):
  1798.             raise FormatError("pHYs chunk has incorrect length.")
  1799.         self.x_pixels_per_unit, self.y_pixels_per_unit, unit = \
  1800.             struct.unpack(fmt, data)
  1801.         self.unit_is_meter = bool(unit)
  1802.  
  1803.     def read(self, lenient=False):
  1804.         """
  1805.        Read the PNG file and decode it.
  1806.        Returns (`width`, `height`, `rows`, `info`).
  1807.  
  1808.        May use excessive memory.
  1809.  
  1810.        `rows` is a sequence of rows;
  1811.        each row is a sequence of values.
  1812.  
  1813.        If the optional `lenient` argument evaluates to True,
  1814.        checksum failures will raise warnings rather than exceptions.
  1815.        """
  1816.  
  1817.         def iteridat():
  1818.             """Iterator that yields all the ``IDAT`` chunks as strings."""
  1819.             while True:
  1820.                 type, data = self.chunk(lenient=lenient)
  1821.                 if type == b'IEND':
  1822.                     # http://www.w3.org/TR/PNG/#11IEND
  1823.                     break
  1824.                 if type != b'IDAT':
  1825.                     continue
  1826.                 # type == b'IDAT'
  1827.                 # http://www.w3.org/TR/PNG/#11IDAT
  1828.                 if self.colormap and not self.plte:
  1829.                     warnings.warn("PLTE chunk is required before IDAT chunk")
  1830.                 yield data
  1831.  
  1832.         self.preamble(lenient=lenient)
  1833.         raw = decompress(iteridat())
  1834.  
  1835.         if self.interlace:
  1836.             def rows_from_interlace():
  1837.                 """Yield each row from an interlaced PNG."""
  1838.                 # It's important that this iterator doesn't read
  1839.                 # IDAT chunks until it yields the first row.
  1840.                 bs = bytearray(itertools.chain(*raw))
  1841.                 arraycode = 'BH'[self.bitdepth > 8]
  1842.                 # Like :meth:`group` but
  1843.                 # producing an array.array object for each row.
  1844.                 values = self._deinterlace(bs)
  1845.                 vpr = self.width * self.planes
  1846.                 for i in range(0, len(values), vpr):
  1847.                     row = array(arraycode, values[i:i+vpr])
  1848.                     yield row
  1849.             rows = rows_from_interlace()
  1850.         else:
  1851.             rows = self._iter_bytes_to_values(self._iter_straight_packed(raw))
  1852.         info = dict()
  1853.         for attr in 'greyscale alpha planes bitdepth interlace'.split():
  1854.             info[attr] = getattr(self, attr)
  1855.         info['size'] = (self.width, self.height)
  1856.         for attr in 'gamma transparent background'.split():
  1857.             a = getattr(self, attr, None)
  1858.             if a is not None:
  1859.                 info[attr] = a
  1860.         if getattr(self, 'x_pixels_per_unit', None):
  1861.             info['physical'] = Resolution(self.x_pixels_per_unit,
  1862.                                           self.y_pixels_per_unit,
  1863.                                           self.unit_is_meter)
  1864.         if self.plte:
  1865.             info['palette'] = self.palette()
  1866.         return self.width, self.height, rows, info
  1867.  
  1868.     def read_flat(self):
  1869.         """
  1870.        Read a PNG file and decode it into a single array of values.
  1871.        Returns (*width*, *height*, *values*, *info*).
  1872.  
  1873.        May use excessive memory.
  1874.  
  1875.        `values` is a single array.
  1876.  
  1877.        The :meth:`read` method is more stream-friendly than this,
  1878.        because it returns a sequence of rows.
  1879.        """
  1880.  
  1881.         x, y, pixel, info = self.read()
  1882.         arraycode = 'BH'[info['bitdepth'] > 8]
  1883.         pixel = array(arraycode, itertools.chain(*pixel))
  1884.         return x, y, pixel, info
  1885.  
  1886.     def palette(self, alpha='natural'):
  1887.         """
  1888.        Returns a palette that is a sequence of 3-tuples or 4-tuples,
  1889.        synthesizing it from the ``PLTE`` and ``tRNS`` chunks.
  1890.        These chunks should have already been processed (for example,
  1891.        by calling the :meth:`preamble` method).
  1892.        All the tuples are the same size:
  1893.        3-tuples if there is no ``tRNS`` chunk,
  1894.        4-tuples when there is a ``tRNS`` chunk.
  1895.  
  1896.        Assumes that the image is colour type
  1897.        3 and therefore a ``PLTE`` chunk is required.
  1898.  
  1899.        If the `alpha` argument is ``'force'`` then an alpha channel is
  1900.        always added, forcing the result to be a sequence of 4-tuples.
  1901.        """
  1902.  
  1903.         if not self.plte:
  1904.             raise FormatError(
  1905.                 "Required PLTE chunk is missing in colour type 3 image.")
  1906.         plte = group(array('B', self.plte), 3)
  1907.         if self.trns or alpha == 'force':
  1908.             trns = array('B', self.trns or [])
  1909.             trns.extend([255] * (len(plte) - len(trns)))
  1910.             plte = list(map(operator.add, plte, group(trns, 1)))
  1911.         return plte
  1912.  
  1913.     def asDirect(self):
  1914.         """
  1915.        Returns the image data as a direct representation of
  1916.        an ``x * y * planes`` array.
  1917.        This removes the need for callers to deal with
  1918.        palettes and transparency themselves.
  1919.        Images with a palette (colour type 3) are converted to RGB or RGBA;
  1920.        images with transparency (a ``tRNS`` chunk) are converted to
  1921.        LA or RGBA as appropriate.
  1922.        When returned in this format the pixel values represent
  1923.        the colour value directly without needing to refer
  1924.        to palettes or transparency information.
  1925.  
  1926.        Like the :meth:`read` method this method returns a 4-tuple:
  1927.  
  1928.        (*width*, *height*, *rows*, *info*)
  1929.  
  1930.        This method normally returns pixel values with
  1931.        the bit depth they have in the source image, but
  1932.        when the source PNG has an ``sBIT`` chunk it is inspected and
  1933.        can reduce the bit depth of the result pixels;
  1934.        pixel values will be reduced according to the bit depth
  1935.        specified in the ``sBIT`` chunk.
  1936.        PNG nerds should note a single result bit depth is
  1937.        used for all channels:
  1938.        the maximum of the ones specified in the ``sBIT`` chunk.
  1939.        An RGB565 image will be rescaled to 6-bit RGB666.
  1940.  
  1941.        The *info* dictionary that is returned reflects
  1942.        the `direct` format and not the original source image.
  1943.        For example, an RGB source image with a ``tRNS`` chunk
  1944.        to represent a transparent colour,
  1945.        will start with ``planes=3`` and ``alpha=False`` for the
  1946.        source image,
  1947.        but the *info* dictionary returned by this method
  1948.        will have ``planes=4`` and ``alpha=True`` because
  1949.        an alpha channel is synthesized and added.
  1950.  
  1951.        *rows* is a sequence of rows;
  1952.        each row being a sequence of values
  1953.        (like the :meth:`read` method).
  1954.  
  1955.        All the other aspects of the image data are not changed.
  1956.        """
  1957.  
  1958.         self.preamble()
  1959.  
  1960.         # Simple case, no conversion necessary.
  1961.         if not self.colormap and not self.trns and not self.sbit:
  1962.             return self.read()
  1963.  
  1964.         x, y, pixels, info = self.read()
  1965.  
  1966.         if self.colormap:
  1967.             info['colormap'] = False
  1968.             info['alpha'] = bool(self.trns)
  1969.             info['bitdepth'] = 8
  1970.             info['planes'] = 3 + bool(self.trns)
  1971.             plte = self.palette()
  1972.  
  1973.             def iterpal(pixels):
  1974.                 for row in pixels:
  1975.                     row = [plte[x] for x in row]
  1976.                     yield array('B', itertools.chain(*row))
  1977.             pixels = iterpal(pixels)
  1978.         elif self.trns:
  1979.             # It would be nice if there was some reasonable way
  1980.             # of doing this without generating a whole load of
  1981.             # intermediate tuples.  But tuples does seem like the
  1982.             # easiest way, with no other way clearly much simpler or
  1983.             # much faster.  (Actually, the L to LA conversion could
  1984.             # perhaps go faster (all those 1-tuples!), but I still
  1985.             # wonder whether the code proliferation is worth it)
  1986.             it = self.transparent
  1987.             maxval = 2 ** info['bitdepth'] - 1
  1988.             planes = info['planes']
  1989.             info['alpha'] = True
  1990.             info['planes'] += 1
  1991.             typecode = 'BH'[info['bitdepth'] > 8]
  1992.  
  1993.             def itertrns(pixels):
  1994.                 for row in pixels:
  1995.                     # For each row we group it into pixels, then form a
  1996.                     # characterisation vector that says whether each
  1997.                     # pixel is opaque or not.  Then we convert
  1998.                     # True/False to 0/maxval (by multiplication),
  1999.                     # and add it as the extra channel.
  2000.                     row = group(row, planes)
  2001.                     opa = map(it.__ne__, row)
  2002.                     opa = map(maxval.__mul__, opa)
  2003.                     opa = list(zip(opa))    # convert to 1-tuples
  2004.                     yield array(
  2005.                         typecode,
  2006.                         itertools.chain(*map(operator.add, row, opa)))
  2007.             pixels = itertrns(pixels)
  2008.         targetbitdepth = None
  2009.         if self.sbit:
  2010.             sbit = struct.unpack('%dB' % len(self.sbit), self.sbit)
  2011.             targetbitdepth = max(sbit)
  2012.             if targetbitdepth > info['bitdepth']:
  2013.                 raise Error('sBIT chunk %r exceeds bitdepth %d' %
  2014.                             (sbit, self.bitdepth))
  2015.             if min(sbit) <= 0:
  2016.                 raise Error('sBIT chunk %r has a 0-entry' % sbit)
  2017.         if targetbitdepth:
  2018.             shift = info['bitdepth'] - targetbitdepth
  2019.             info['bitdepth'] = targetbitdepth
  2020.  
  2021.             def itershift(pixels):
  2022.                 for row in pixels:
  2023.                     yield [p >> shift for p in row]
  2024.             pixels = itershift(pixels)
  2025.         return x, y, pixels, info
  2026.  
  2027.     def _as_rescale(self, get, targetbitdepth):
  2028.         """Helper used by :meth:`asRGB8` and :meth:`asRGBA8`."""
  2029.  
  2030.         width, height, pixels, info = get()
  2031.         maxval = 2**info['bitdepth'] - 1
  2032.         targetmaxval = 2**targetbitdepth - 1
  2033.         factor = float(targetmaxval) / float(maxval)
  2034.         info['bitdepth'] = targetbitdepth
  2035.  
  2036.         def iterscale():
  2037.             for row in pixels:
  2038.                 yield [int(round(x * factor)) for x in row]
  2039.         if maxval == targetmaxval:
  2040.             return width, height, pixels, info
  2041.         else:
  2042.             return width, height, iterscale(), info
  2043.  
  2044.     def asRGB8(self):
  2045.         """
  2046.        Return the image data as an RGB pixels with 8-bits per sample.
  2047.        This is like the :meth:`asRGB` method except that
  2048.        this method additionally rescales the values so that
  2049.        they are all between 0 and 255 (8-bit).
  2050.        In the case where the source image has a bit depth < 8
  2051.        the transformation preserves all the information;
  2052.        where the source image has bit depth > 8, then
  2053.        rescaling to 8-bit values loses precision.
  2054.        No dithering is performed.
  2055.        Like :meth:`asRGB`,
  2056.        an alpha channel in the source image will raise an exception.
  2057.  
  2058.        This function returns a 4-tuple:
  2059.        (*width*, *height*, *rows*, *info*).
  2060.        *width*, *height*, *info* are as per the :meth:`read` method.
  2061.  
  2062.        *rows* is the pixel data as a sequence of rows.
  2063.        """
  2064.  
  2065.         return self._as_rescale(self.asRGB, 8)
  2066.  
  2067.     def asRGBA8(self):
  2068.         """
  2069.        Return the image data as RGBA pixels with 8-bits per sample.
  2070.        This method is similar to :meth:`asRGB8` and :meth:`asRGBA`:
  2071.        The result pixels have an alpha channel, *and*
  2072.        values are rescaled to the range 0 to 255.
  2073.        The alpha channel is synthesized if necessary
  2074.        (with a small speed penalty).
  2075.        """
  2076.  
  2077.         return self._as_rescale(self.asRGBA, 8)
  2078.  
  2079.     def asRGB(self):
  2080.         """
  2081.        Return image as RGB pixels.
  2082.        RGB colour images are passed through unchanged;
  2083.        greyscales are expanded into RGB triplets
  2084.        (there is a small speed overhead for doing this).
  2085.  
  2086.        An alpha channel in the source image will raise an exception.
  2087.  
  2088.        The return values are as for the :meth:`read` method except that
  2089.        the *info* reflect the returned pixels, not the source image.
  2090.        In particular,
  2091.        for this method ``info['greyscale']`` will be ``False``.
  2092.        """
  2093.  
  2094.         width, height, pixels, info = self.asDirect()
  2095.         if info['alpha']:
  2096.             raise Error("will not convert image with alpha channel to RGB")
  2097.         if not info['greyscale']:
  2098.             return width, height, pixels, info
  2099.         info['greyscale'] = False
  2100.         info['planes'] = 3
  2101.  
  2102.         if info['bitdepth'] > 8:
  2103.             def newarray():
  2104.                 return array('H', [0])
  2105.         else:
  2106.             def newarray():
  2107.                 return bytearray([0])
  2108.  
  2109.         def iterrgb():
  2110.             for row in pixels:
  2111.                 a = newarray() * 3 * width
  2112.                 for i in range(3):
  2113.                     a[i::3] = row
  2114.                 yield a
  2115.         return width, height, iterrgb(), info
  2116.  
  2117.     def asRGBA(self):
  2118.         """
  2119.        Return image as RGBA pixels.
  2120.        Greyscales are expanded into RGB triplets;
  2121.        an alpha channel is synthesized if necessary.
  2122.        The return values are as for the :meth:`read` method except that
  2123.        the *info* reflect the returned pixels, not the source image.
  2124.        In particular, for this method
  2125.        ``info['greyscale']`` will be ``False``, and
  2126.        ``info['alpha']`` will be ``True``.
  2127.        """
  2128.  
  2129.         width, height, pixels, info = self.asDirect()
  2130.         if info['alpha'] and not info['greyscale']:
  2131.             return width, height, pixels, info
  2132.         typecode = 'BH'[info['bitdepth'] > 8]
  2133.         maxval = 2**info['bitdepth'] - 1
  2134.         maxbuffer = struct.pack('=' + typecode, maxval) * 4 * width
  2135.  
  2136.         if info['bitdepth'] > 8:
  2137.             def newarray():
  2138.                 return array('H', maxbuffer)
  2139.         else:
  2140.             def newarray():
  2141.                 return bytearray(maxbuffer)
  2142.  
  2143.         if info['alpha'] and info['greyscale']:
  2144.             # LA to RGBA
  2145.             def convert():
  2146.                 for row in pixels:
  2147.                     # Create a fresh target row, then copy L channel
  2148.                     # into first three target channels, and A channel
  2149.                     # into fourth channel.
  2150.                     a = newarray()
  2151.                     convert_la_to_rgba(row, a)
  2152.                     yield a
  2153.         elif info['greyscale']:
  2154.             # L to RGBA
  2155.             def convert():
  2156.                 for row in pixels:
  2157.                     a = newarray()
  2158.                     convert_l_to_rgba(row, a)
  2159.                     yield a
  2160.         else:
  2161.             assert not info['alpha'] and not info['greyscale']
  2162.             # RGB to RGBA
  2163.  
  2164.             def convert():
  2165.                 for row in pixels:
  2166.                     a = newarray()
  2167.                     convert_rgb_to_rgba(row, a)
  2168.                     yield a
  2169.         info['alpha'] = True
  2170.         info['greyscale'] = False
  2171.         info['planes'] = 4
  2172.         return width, height, convert(), info
  2173.  
  2174.  
  2175. def decompress(data_blocks):
  2176.     """
  2177.    `data_blocks` should be an iterable that
  2178.    yields the compressed data (from the ``IDAT`` chunks).
  2179.    This yields decompressed byte strings.
  2180.    """
  2181.  
  2182.     # Currently, with no max_length parameter to decompress,
  2183.     # this routine will do one yield per IDAT chunk: Not very
  2184.     # incremental.
  2185.     d = zlib.decompressobj()
  2186.     # Each IDAT chunk is passed to the decompressor, then any
  2187.     # remaining state is decompressed out.
  2188.     for data in data_blocks:
  2189.         # :todo: add a max_length argument here to limit output size.
  2190.         yield bytearray(d.decompress(data))
  2191.     yield bytearray(d.flush())
  2192.  
  2193.  
  2194. def check_bitdepth_colortype(bitdepth, colortype):
  2195.     """
  2196.    Check that `bitdepth` and `colortype` are both valid,
  2197.    and specified in a valid combination.
  2198.    Returns (None) if valid, raise an Exception if not valid.
  2199.    """
  2200.  
  2201.     if bitdepth not in (1, 2, 4, 8, 16):
  2202.         raise FormatError("invalid bit depth %d" % bitdepth)
  2203.     if colortype not in (0, 2, 3, 4, 6):
  2204.         raise FormatError("invalid colour type %d" % colortype)
  2205.     # Check indexed (palettized) images have 8 or fewer bits
  2206.     # per pixel; check only indexed or greyscale images have
  2207.     # fewer than 8 bits per pixel.
  2208.     if colortype & 1 and bitdepth > 8:
  2209.         raise FormatError(
  2210.             "Indexed images (colour type %d) cannot"
  2211.             " have bitdepth > 8 (bit depth %d)."
  2212.             " See http://www.w3.org/TR/2003/REC-PNG-20031110/#table111 ."
  2213.             % (bitdepth, colortype))
  2214.     if bitdepth < 8 and colortype not in (0, 3):
  2215.         raise FormatError(
  2216.             "Illegal combination of bit depth (%d)"
  2217.             " and colour type (%d)."
  2218.             " See http://www.w3.org/TR/2003/REC-PNG-20031110/#table111 ."
  2219.             % (bitdepth, colortype))
  2220.  
  2221.  
  2222. def is_natural(x):
  2223.     """A non-negative integer."""
  2224.     try:
  2225.         is_integer = int(x) == x
  2226.     except (TypeError, ValueError):
  2227.         return False
  2228.     return is_integer and x >= 0
  2229.  
  2230.  
  2231. def undo_filter_sub(filter_unit, scanline, previous, result):
  2232.     """Undo sub filter."""
  2233.  
  2234.     ai = 0
  2235.     # Loops starts at index fu.  Observe that the initial part
  2236.     # of the result is already filled in correctly with
  2237.     # scanline.
  2238.     for i in range(filter_unit, len(result)):
  2239.         x = scanline[i]
  2240.         a = result[ai]
  2241.         result[i] = (x + a) & 0xff
  2242.         ai += 1
  2243.  
  2244.  
  2245. def undo_filter_up(filter_unit, scanline, previous, result):
  2246.     """Undo up filter."""
  2247.  
  2248.     for i in range(len(result)):
  2249.         x = scanline[i]
  2250.         b = previous[i]
  2251.         result[i] = (x + b) & 0xff
  2252.  
  2253.  
  2254. def undo_filter_average(filter_unit, scanline, previous, result):
  2255.     """Undo up filter."""
  2256.  
  2257.     ai = -filter_unit
  2258.     for i in range(len(result)):
  2259.         x = scanline[i]
  2260.         if ai < 0:
  2261.             a = 0
  2262.         else:
  2263.             a = result[ai]
  2264.         b = previous[i]
  2265.         result[i] = (x + ((a + b) >> 1)) & 0xff
  2266.         ai += 1
  2267.  
  2268.  
  2269. def undo_filter_paeth(filter_unit, scanline, previous, result):
  2270.     """Undo Paeth filter."""
  2271.  
  2272.     # Also used for ci.
  2273.     ai = -filter_unit
  2274.     for i in range(len(result)):
  2275.         x = scanline[i]
  2276.         if ai < 0:
  2277.             a = c = 0
  2278.         else:
  2279.             a = result[ai]
  2280.             c = previous[ai]
  2281.         b = previous[i]
  2282.         p = a + b - c
  2283.         pa = abs(p - a)
  2284.         pb = abs(p - b)
  2285.         pc = abs(p - c)
  2286.         if pa <= pb and pa <= pc:
  2287.             pr = a
  2288.         elif pb <= pc:
  2289.             pr = b
  2290.         else:
  2291.             pr = c
  2292.         result[i] = (x + pr) & 0xff
  2293.         ai += 1
  2294.  
  2295.  
  2296. def convert_la_to_rgba(row, result):
  2297.     for i in range(3):
  2298.         result[i::4] = row[0::2]
  2299.     result[3::4] = row[1::2]
  2300.  
  2301.  
  2302. def convert_l_to_rgba(row, result):
  2303.     """
  2304.    Convert a grayscale image to RGBA.
  2305.    This method assumes the alpha channel in result is
  2306.    already correctly initialized.
  2307.    """
  2308.     for i in range(3):
  2309.         result[i::4] = row
  2310.  
  2311.  
  2312. def convert_rgb_to_rgba(row, result):
  2313.     """
  2314.    Convert an RGB image to RGBA.
  2315.    This method assumes the alpha channel in result is
  2316.    already correctly initialized.
  2317.    """
  2318.     for i in range(3):
  2319.         result[i::4] = row[i::3]
  2320.  
  2321.  
  2322. # -------------------------------------------------------------------------------------------
  2323. # -------------------------------------------------------------------------------------------
  2324. # -------------------------------------------------------------------------------------------
  2325. # -------------------------------------------------------------------------------------------
  2326. # -------------------------------------------------------------------------------------------
  2327. # -------------------------------------------------------------------------------------------
  2328. # -------------------------------------------------------------------------------------------
  2329. # -------------------------------------------------------------------------------------------
  2330. # -------------------------------------------------------------------------------------------
  2331. """
  2332. Pokemon Crystal data de/compression.
  2333. """
  2334.  
  2335. """
  2336. A rundown of Pokemon Crystal's compression scheme:
  2337.  
  2338. Control commands occupy bits 5-7.
  2339. Bits 0-4 serve as the first parameter <n> for each command.
  2340. """
  2341. lz_commands = {
  2342.     'literal':   0, # n values for n bytes
  2343.     'iterate':   1, # one value for n bytes
  2344.     'alternate': 2, # alternate two values for n bytes
  2345.     'blank':     3, # zero for n bytes
  2346. }
  2347.  
  2348. """
  2349. Repeater commands repeat any data that was just decompressed.
  2350. They take an additional signed parameter <s> to mark a relative starting point.
  2351. These wrap around (positive from the start, negative from the current position).
  2352. """
  2353. lz_commands.update({
  2354.     'repeat':    4, # n bytes starting from s
  2355.     'flip':      5, # n bytes in reverse bit order starting from s
  2356.     'reverse':   6, # n bytes backwards starting from s
  2357. })
  2358.  
  2359. """
  2360. The long command is used when 5 bits aren't enough. Bits 2-4 contain a new control code.
  2361. Bits 0-1 are appended to a new byte as 8-9, allowing a 10-bit parameter.
  2362. """
  2363. lz_commands.update({
  2364.     'long':      7, # n is now 10 bits for a new control code
  2365. })
  2366. max_length = 1 << 10 # can't go higher than 10 bits
  2367. lowmax     = 1 <<  5 # standard 5-bit param
  2368.  
  2369. """
  2370. If 0xff is encountered instead of a command, decompression ends.
  2371. """
  2372. lz_end = 0xff
  2373.  
  2374.  
  2375. bit_flipped = [
  2376.     sum(((byte >> i) & 1) << (7 - i) for i in xrange(8))
  2377.     for byte in xrange(0x100)
  2378. ]
  2379.  
  2380.  
  2381. def fbitstream(f):
  2382.     while 1:
  2383.         char = f.read(1)
  2384.         if not char:
  2385.             break
  2386.         byte = ord(char)
  2387.         for i in range(7, -1, -1):
  2388.             yield (byte >> i) & 1
  2389.  
  2390. def bitstream(b):
  2391.     for byte in b:
  2392.         for i in range(7, -1, -1):
  2393.             yield (byte >> i) & 1
  2394.  
  2395. def readint(bs, count):
  2396.     n = 0
  2397.     while count:
  2398.         n <<= 1
  2399.         n |= next(bs)
  2400.         count -= 1
  2401.     return n
  2402.  
  2403. def bitgroups_to_bytes(bits):
  2404.     l = []
  2405.     for i in range(0, len(bits) - 3, 4):
  2406.         n = ((bits[i + 0] << 6)
  2407.            | (bits[i + 1] << 4)
  2408.            | (bits[i + 2] << 2)
  2409.            | (bits[i + 3] << 0))
  2410.         l.append(n)
  2411.     return bytearray(l)
  2412.  
  2413.  
  2414. def bytes_to_bits(bytelist):
  2415.     return list(bitstream(bytelist))
  2416.  
  2417. class Compressed:
  2418.  
  2419.     """
  2420.     Usage:
  2421.         lz = Compressed(data).output
  2422.     or
  2423.         lz = Compressed().compress(data)
  2424.     or
  2425.         c = Compressed()
  2426.         c.data = data
  2427.         lz = c.compress()
  2428.  
  2429.     There are some issues with reproducing the target compressor.
  2430.     Some notes are listed here:
  2431.         - the criteria for detecting a lookback is inconsistent
  2432.             - sometimes lookbacks that are mostly 0s are pruned, sometimes not
  2433.         - target appears to skip ahead if it can use a lookback soon, stopping the current command short or in some cases truncating it with literals.
  2434.             - this has been implemented, but the specifics are unknown
  2435.         - self.min_scores: It's unknown if blank's minimum score should be 1 or 2. Most likely it's 1, with some other hack to account for edge cases.
  2436.             - may be related to the above
  2437.         - target does not appear to compress backwards
  2438.     """
  2439.  
  2440.     def __init__(self, *args, **kwargs):
  2441.  
  2442.         self.min_scores = {
  2443.             'blank':     1,
  2444.             'iterate':   2,
  2445.             'alternate': 3,
  2446.             'repeat':    3,
  2447.             'reverse':   3,
  2448.             'flip':      3,
  2449.         }
  2450.  
  2451.         self.preference = [
  2452.             'repeat',
  2453.             'blank',
  2454.             'flip',
  2455.             'reverse',
  2456.             'iterate',
  2457.             'alternate',
  2458.             #'literal',
  2459.         ]
  2460.  
  2461.         self.lookback_methods = 'repeat', 'reverse', 'flip'
  2462.  
  2463.         self.__dict__.update({
  2464.             'data': None,
  2465.             'commands': lz_commands,
  2466.             'debug': False,
  2467.             'literal_only': False,
  2468.         })
  2469.  
  2470.         self.arg_names = 'data', 'commands', 'debug', 'literal_only'
  2471.  
  2472.         self.__dict__.update(kwargs)
  2473.         self.__dict__.update(dict(zip(self.arg_names, args)))
  2474.  
  2475.         if self.data is not None:
  2476.             self.compress()
  2477.  
  2478.     def compress(self, data=None):
  2479.         if data is not None:
  2480.             self.data = data
  2481.  
  2482.         self.data = list(bytearray(self.data))
  2483.  
  2484.         self.indexes = {}
  2485.         self.lookbacks = {}
  2486.         for method in self.lookback_methods:
  2487.             self.lookbacks[method] = {}
  2488.  
  2489.         self.address = 0
  2490.         self.end     = len(self.data)
  2491.         self.output  = []
  2492.         self.literal = None
  2493.  
  2494.         while self.address < self.end:
  2495.  
  2496.             if self.score():
  2497.                 self.do_literal()
  2498.                 self.do_winner()
  2499.  
  2500.             else:
  2501.                 if self.literal == None:
  2502.                     self.literal = self.address
  2503.                 self.address += 1
  2504.  
  2505.         self.do_literal()
  2506.  
  2507.         self.output += [lz_end]
  2508.         return self.output
  2509.    
  2510.     def reset_scores(self):
  2511.         self.scores = {}
  2512.         self.offsets = {}
  2513.         self.helpers = {}
  2514.         for method in self.min_scores.iterkeys():
  2515.             self.scores[method] = 0
  2516.    
  2517.     def bit_flip(self, byte):
  2518.         return bit_flipped[byte]
  2519.    
  2520.     def do_literal(self):
  2521.         if self.literal != None:
  2522.             length = abs(self.address - self.literal)
  2523.             start  = min(self.literal, self.address + 1)
  2524.             self.helpers['literal'] = self.data[start:start+length]
  2525.             self.do_cmd('literal', length)
  2526.             self.literal = None
  2527.    
  2528.     def score(self):
  2529.         self.reset_scores()
  2530.        
  2531.         map(self.score_literal, ['iterate', 'alternate', 'blank'])
  2532.        
  2533.         for method in self.lookback_methods:
  2534.             self.scores[method], self.offsets[method] = self.find_lookback(method, self.address)
  2535.        
  2536.         self.stop_short()
  2537.        
  2538.         return any(
  2539.             score
  2540.           > self.min_scores[method] + int(score > lowmax)
  2541.             for method, score in self.scores.iteritems()
  2542.         )
  2543.    
  2544.     def stop_short(self):
  2545.         """
  2546.         If a lookback is close, reduce the scores of other commands.
  2547.         """
  2548.         best_method, best_score = max(
  2549.             self.scores.items(),
  2550.             key = lambda x: (
  2551.                 x[1],
  2552.                 -self.preference.index(x[0])
  2553.             )
  2554.         )
  2555.         for method in self.lookback_methods:
  2556.             min_score = self.min_scores[method]
  2557.             for address in xrange(self.address+1, self.address+best_score):
  2558.                 length, index = self.find_lookback(method, address)
  2559.                 if length > max(min_score, best_score):
  2560.                     # BUG: lookbacks can reduce themselves. This appears to be a bug in the target also.
  2561.                     for m, score in self.scores.items():
  2562.                         self.scores[m] = min(score, address - self.address)
  2563.    
  2564.    
  2565.     def read(self, address=None):
  2566.         if address is None:
  2567.             address = self.address
  2568.         if 0 <= address < len(self.data):
  2569.             return self.data[address]
  2570.         return None
  2571.    
  2572.     def find_all_lookbacks(self):
  2573.         for method in self.lookback_methods:
  2574.             for address, byte in enumerate(self.data):
  2575.                 self.find_lookback(method, address)
  2576.    
  2577.     def find_lookback(self, method, address=None):
  2578.         #Temporarily stubbed, because the real function doesn't run in polynomial time.
  2579.         return (0, None)
  2580.  
  2581.     def broken_find_lookback(self, method, address=None):
  2582.         if address is None:
  2583.             address = self.address
  2584.  
  2585.         existing = self.lookbacks.get(method, {}).get(address)
  2586.         if existing != None:
  2587.             return existing
  2588.  
  2589.         lookback = 0, None
  2590.  
  2591.         # Better to not carelessly optimize at the moment.
  2592.         """
  2593.         if address < 2:
  2594.             return lookback
  2595.         """
  2596.  
  2597.         byte = self.read(address)
  2598.         if byte is None:
  2599.             return lookback
  2600.  
  2601.         direction, mutate = {
  2602.             'repeat':  ( 1, int),
  2603.             'reverse': (-1, int),
  2604.             'flip':    ( 1, self.bit_flip),
  2605.         }[method]
  2606.  
  2607.         # Doesn't seem to help
  2608.         """
  2609.         if mutate == self.bit_flip:
  2610.             if byte == 0:
  2611.                 self.lookbacks[method][address] = lookback
  2612.                 return lookback
  2613.         """
  2614.  
  2615.         data_len = len(self.data)
  2616.         is_two_byte_index = lambda index: int(index < address - 0x7f)
  2617.  
  2618.         for index in self.get_indexes(mutate(byte)):
  2619.  
  2620.             if index >= address:
  2621.                 break
  2622.  
  2623.             old_length, old_index = lookback
  2624.             if direction == 1:
  2625.                 if old_length > data_len - index: break
  2626.             else:
  2627.                 if old_length > index: continue
  2628.  
  2629.             if self.read(index) in [None]: continue
  2630.  
  2631.             length = 1 # we know there's at least one match, or we wouldn't be checking this index
  2632.             while 1:
  2633.                 this_byte = self.read(address + length)
  2634.                 that_byte = self.read(index + length * direction)
  2635.                 if that_byte == None or this_byte != mutate(that_byte):
  2636.                     break
  2637.                 length += 1
  2638.  
  2639.             score = length - is_two_byte_index(index)
  2640.             old_score = old_length - is_two_byte_index(old_index)
  2641.             if score >= old_score or (score == old_score and length > old_length):
  2642.                 # XXX maybe avoid two-byte indexes when possible
  2643.                 if score >= lookback[0] - is_two_byte_index(lookback[1]):
  2644.                     lookback = length, index
  2645.  
  2646.         self.lookbacks[method][address] = lookback
  2647.         return lookback
  2648.  
  2649.     def get_indexes(self, byte):
  2650.         if not self.indexes.has_key(byte):
  2651.             self.indexes[byte] = []
  2652.             index = -1
  2653.             while 1:
  2654.                 try:
  2655.                     index = self.data.index(byte, index + 1)
  2656.                 except ValueError:
  2657.                     break
  2658.                 self.indexes[byte].append(index)
  2659.         return self.indexes[byte]
  2660.  
  2661.     def score_literal(self, method):
  2662.         address = self.address
  2663.  
  2664.         compare = {
  2665.             'blank': [0],
  2666.             'iterate': [self.read(address)],
  2667.             'alternate': [self.read(address), self.read(address + 1)],
  2668.         }[method]
  2669.  
  2670.         # XXX may or may not be correct
  2671.         if method == 'alternate' and compare[0] == 0:
  2672.             return
  2673.  
  2674.         length = 0
  2675.         while self.read(address + length) == compare[length % len(compare)]:
  2676.             length += 1
  2677.  
  2678.         self.scores[method] = length
  2679.         self.helpers[method] = compare
  2680.  
  2681.     def do_winner(self):
  2682.         winners = filter(
  2683.             lambda method, score:
  2684.                 score
  2685.               > self.min_scores[method] + int(score > lowmax),
  2686.             self.scores.iteritems()
  2687.         )
  2688.         winners.sort(
  2689.             key = lambda method, score: (
  2690.                 -(score - self.min_scores[method] - int(score > lowmax)),
  2691.                 self.preference.index(method)
  2692.             )
  2693.         )
  2694.         winner, score = winners[0]
  2695.  
  2696.         length = min(score, max_length)
  2697.         self.do_cmd(winner, length)
  2698.         self.address += length
  2699.  
  2700.     def do_cmd(self, cmd, length):
  2701.         start_address = self.address
  2702.  
  2703.         cmd_length = length - 1
  2704.  
  2705.         output = []
  2706.  
  2707.         if length > lowmax:
  2708.             output.append(
  2709.                 (self.commands['long'] << 5)
  2710.               + (self.commands[cmd] << 2)
  2711.               + (cmd_length >> 8)
  2712.             )
  2713.             output.append(
  2714.                 cmd_length & 0xff
  2715.             )
  2716.         else:
  2717.             output.append(
  2718.                 (self.commands[cmd] << 5)
  2719.               + cmd_length
  2720.             )
  2721.  
  2722.         self.helpers['blank'] = [] # quick hack
  2723.         output += self.helpers.get(cmd, [])
  2724.  
  2725.         if cmd in self.lookback_methods:
  2726.             offset = self.offsets[cmd]
  2727.             # Negative offsets are one byte.
  2728.             # Positive offsets are two.
  2729.             if 0 < start_address - offset - 1 <= 0x7f:
  2730.                 offset = (start_address - offset - 1) | 0x80
  2731.                 output += [offset]
  2732.             else:
  2733.                 output += [offset / 0x100, offset % 0x100] # big endian
  2734.  
  2735.         if self.debug:
  2736.             print(' '.join(map(str, [
  2737.                   cmd, length, '\t',
  2738.                   ' '.join(map('{:02x}'.format, output)),
  2739.                   self.data[start_address:start_address+length] if cmd in self.lookback_methods else '',
  2740.             ])))
  2741.         self.output += output
  2742.  
  2743.  
  2744.  
  2745. class Decompressed:
  2746.     """
  2747.     Interpret and decompress lz-compressed data, usually 2bpp.
  2748.     """
  2749.  
  2750.     """
  2751.     Usage:
  2752.         data = Decompressed(lz).output
  2753.     or
  2754.         data = Decompressed().decompress(lz)
  2755.     or
  2756.         d = Decompressed()
  2757.         d.lz = lz
  2758.         data = d.decompress()
  2759.  
  2760.     To decompress from offset 0x80000 in a rom:
  2761.         data = Decompressed(rom, start=0x80000).output
  2762.     """
  2763.  
  2764.     lz = None
  2765.     start = 0
  2766.     commands = lz_commands
  2767.     debug = False
  2768.  
  2769.     arg_names = 'lz', 'start', 'commands', 'debug'
  2770.  
  2771.     def __init__(self, *args, **kwargs):
  2772.         self.__dict__.update(dict(zip(self.arg_names, args)))
  2773.         self.__dict__.update(kwargs)
  2774.  
  2775.         self.command_names = dict(map(reversed, self.commands.items()))
  2776.         self.address = self.start
  2777.  
  2778.         if self.lz is not None:
  2779.             self.decompress()
  2780.  
  2781.         if self.debug: print( self.command_list() )
  2782.  
  2783.  
  2784.     def command_list(self):
  2785.         """
  2786.         Print a list of commands that were used. Useful for debugging.
  2787.         """
  2788.  
  2789.         text = ''
  2790.  
  2791.         output_address = 0
  2792.         for name, attrs in self.used_commands:
  2793.             length     = attrs['length']
  2794.             address    = attrs['address']
  2795.             offset     = attrs['offset']
  2796.             direction  = attrs['direction']
  2797.  
  2798.             text += '{2:03x} {0}: {1}'.format(name, length, output_address)
  2799.             text += '\t' + ' '.join(
  2800.                 '{:02x}'.format(int(byte))
  2801.                 for byte in self.lz[ address : address + attrs['cmd_length'] ]
  2802.             )
  2803.  
  2804.             if offset is not None:
  2805.                 repeated_data = self.output[ offset : offset + length * direction : direction ]
  2806.                 if name == 'flip':
  2807.                     repeated_data = map(bit_flipped.__getitem__, repeated_data)
  2808.                 text += ' [' + ' '.join(map('{:02x}'.format, repeated_data)) + ']'
  2809.  
  2810.             text += '\n'
  2811.             output_address += length
  2812.  
  2813.         return text
  2814.  
  2815.  
  2816.     def decompress(self, lz=None):
  2817.  
  2818.         if lz is not None:
  2819.             self.lz = lz
  2820.  
  2821.         self.lz = bytearray(self.lz)
  2822.  
  2823.         self.used_commands = []
  2824.         self.output = []
  2825.  
  2826.         while 1:
  2827.  
  2828.             cmd_address = self.address
  2829.             self.offset = None
  2830.             self.direction = None
  2831.  
  2832.             if (self.byte == lz_end):
  2833.                 self.next()
  2834.                 break
  2835.  
  2836.             self.cmd = (self.byte & 0b11100000) >> 5
  2837.  
  2838.             if self.cmd_name == 'long':
  2839.                 # 10-bit length
  2840.                 self.cmd = (self.byte & 0b00011100) >> 2
  2841.                 self.length = (self.next() & 0b00000011) * 0x100
  2842.                 self.length += self.next() + 1
  2843.             else:
  2844.                 # 5-bit length
  2845.                 self.length = (self.next() & 0b00011111) + 1
  2846.  
  2847.             self.__class__.__dict__[self.cmd_name](self)
  2848.  
  2849.             self.used_commands += [(
  2850.                 self.cmd_name,
  2851.                 {
  2852.                     'length':     self.length,
  2853.                     'address':    cmd_address,
  2854.                     'offset':     self.offset,
  2855.                     'cmd_length': self.address - cmd_address,
  2856.                     'direction':  self.direction,
  2857.                 }
  2858.             )]
  2859.  
  2860.         # Keep track of the data we just decompressed.
  2861.         self.compressed_data = self.lz[self.start : self.address]
  2862.  
  2863.  
  2864.     @property
  2865.     def byte(self):
  2866.         return self.lz[ self.address ]
  2867.  
  2868.     def next(self):
  2869.         byte = self.byte
  2870.         self.address += 1
  2871.         return byte
  2872.  
  2873.     @property
  2874.     def cmd_name(self):
  2875.         return self.command_names.get(self.cmd)
  2876.  
  2877.  
  2878.     def get_offset(self):
  2879.  
  2880.         if self.byte >= 0x80: # negative
  2881.             # negative
  2882.             offset = self.next() & 0x7f
  2883.             offset = len(self.output) - offset - 1
  2884.         else:
  2885.             # positive
  2886.             offset =  self.next() * 0x100
  2887.             offset += self.next()
  2888.  
  2889.         self.offset = offset
  2890.  
  2891.  
  2892.     def literal(self):
  2893.         """
  2894.         Copy data directly.
  2895.         """
  2896.         self.output  += self.lz[ self.address : self.address + self.length ]
  2897.         self.address += self.length
  2898.  
  2899.     def iterate(self):
  2900.         """
  2901.         Write one byte repeatedly.
  2902.         """
  2903.         self.output += [self.next()] * self.length
  2904.  
  2905.     def alternate(self):
  2906.         """
  2907.         Write alternating bytes.
  2908.         """
  2909.         alts = [self.next(), self.next()]
  2910.         self.output += [ alts[x & 1] for x in xrange(self.length) ]
  2911.  
  2912.     def blank(self):
  2913.         """
  2914.         Write zeros.
  2915.         """
  2916.         self.output += [0] * self.length
  2917.  
  2918.     def flip(self):
  2919.         """
  2920.         Repeat flipped bytes from output.
  2921.  
  2922.         Example: 11100100 -> 00100111
  2923.         """
  2924.         self._repeat(table=bit_flipped)
  2925.  
  2926.     def reverse(self):
  2927.         """
  2928.         Repeat reversed bytes from output.
  2929.         """
  2930.         self._repeat(direction=-1)
  2931.  
  2932.     def repeat(self):
  2933.         """
  2934.         Repeat bytes from output.
  2935.         """
  2936.         self._repeat()
  2937.  
  2938.     def _repeat(self, direction=1, table=None):
  2939.         self.get_offset()
  2940.         self.direction = direction
  2941.         # Note: appends must be one at a time (this way, repeats can draw from themselves if required)
  2942.         for i in xrange(self.length):
  2943.             byte = self.output[ self.offset + i * direction ]
  2944.             self.output.append( table[byte] if table else byte )
  2945.  
  2946.  
  2947.  
  2948. def connect(tiles):
  2949.     """
  2950.     Combine 8x8 tiles into a 2bpp image.
  2951.     """
  2952.     return [byte for tile in tiles for byte in tile]
  2953.  
  2954. def transpose(tiles, width=None):
  2955.     """
  2956.     Transpose a tile arrangement along line y=-x.
  2957.  
  2958.       00 01 02 03 04 05     00 06 0c 12 18 1e
  2959.       06 07 08 09 0a 0b     01 07 0d 13 19 1f
  2960.       0c 0d 0e 0f 10 11 <-> 02 08 0e 14 1a 20
  2961.       12 13 14 15 16 17     03 09 0f 15 1b 21
  2962.       18 19 1a 1b 1c 1d     04 0a 10 16 1c 22
  2963.       1e 1f 20 21 22 23     05 0b 11 17 1d 23
  2964.  
  2965.       00 01 02 03     00 04 08
  2966.       04 05 06 07 <-> 01 05 09
  2967.       08 09 0a 0b     02 06 0a
  2968.                       03 07 0b
  2969.     """
  2970.     if width == None:
  2971.         width = int(sqrt(len(tiles))) # assume square image
  2972.     tiles = sorted(enumerate(tiles), key= lambda i_tile: i_tile[0] % width)
  2973.     return [tile for i, tile in tiles]
  2974.  
  2975. def transpose_tiles(image, width=None):
  2976.     return connect(transpose(get_tiles(image), width))
  2977.  
  2978. def bitflip(x, n):
  2979.     r = 0
  2980.     while n:
  2981.         r = (r << 1) | (x & 1)
  2982.         x >>= 1
  2983.         n -= 1
  2984.     return r
  2985.  
  2986.  
  2987. class Decompressor:
  2988.     """
  2989.     pokered pic decompression.
  2990.  
  2991.     Ported to python 2.7 from the python 3 code at https://github.com/magical/pokemon-sprites-rby.
  2992.     """
  2993.  
  2994.     table1 = [(2 << i) - 1 for i in range(16)]
  2995.     table2 = [
  2996.         [0x0, 0x1, 0x3, 0x2, 0x7, 0x6, 0x4, 0x5, 0xf, 0xe, 0xc, 0xd, 0x8, 0x9, 0xb, 0xa],
  2997.         [0xf, 0xe, 0xc, 0xd, 0x8, 0x9, 0xb, 0xa, 0x0, 0x1, 0x3, 0x2, 0x7, 0x6, 0x4, 0x5], # prev ^ 0xf
  2998.         [0x0, 0x8, 0xc, 0x4, 0xe, 0x6, 0x2, 0xa, 0xf, 0x7, 0x3, 0xb, 0x1, 0x9, 0xd, 0x5],
  2999.         [0xf, 0x7, 0x3, 0xb, 0x1, 0x9, 0xd, 0x5, 0x0, 0x8, 0xc, 0x4, 0xe, 0x6, 0x2, 0xa], # prev ^ 0xf
  3000.     ]
  3001.     table3 = [bitflip(i, 4) for i in range(16)]
  3002.  
  3003.     tilesize = 8
  3004.  
  3005.  
  3006.     def __init__(self, f=None, d=None, mirror=False, planar=True):
  3007.         if f is not None:
  3008.             self.bs = fbitstream( f )
  3009.         elif d is not None:
  3010.             self.bs = bitstream( d )
  3011.         else:
  3012.             print("No decompressed data specified")
  3013.             raise
  3014.         self.mirror = mirror
  3015.         self.planar = planar
  3016.         self.data = None
  3017.    
  3018.     def decompress(self):
  3019.         rams = [[], []]
  3020.  
  3021.         self.sizex  = self._readint(4) * self.tilesize
  3022.         self.sizey  = self._readint(4)
  3023.  
  3024.         self.size = self.sizex * self.sizey
  3025.  
  3026.         self.ramorder = self._readbit()
  3027.  
  3028.         r1 = self.ramorder
  3029.         r2 = self.ramorder ^ 1
  3030.  
  3031.         self._fillram(rams[r1])
  3032.         mode = self._readbit()
  3033.         if mode:
  3034.             mode += self._readbit()
  3035.         self._fillram(rams[r2])
  3036.  
  3037.         rams[0] = bytearray(bitgroups_to_bytes(rams[0]))
  3038.         rams[1] = bytearray(bitgroups_to_bytes(rams[1]))
  3039.  
  3040.         if mode == 0:
  3041.             self._decode(rams[0])
  3042.             self._decode(rams[1])
  3043.         elif mode == 1:
  3044.             self._decode(rams[r1])
  3045.             self._xor(rams[r1], rams[r2])
  3046.         elif mode == 2:
  3047.             self._decode(rams[r2], mirror=False)
  3048.             self._decode(rams[r1])
  3049.             self._xor(rams[r1], rams[r2])
  3050.         else:
  3051.             raise Exception("Invalid deinterlace mode!")
  3052.  
  3053.         data = []
  3054.         if self.planar:
  3055.             for a, b in zip(rams[0], rams[1]):
  3056.                 data += [a, b]
  3057.             self.data = bytearray(data)
  3058.         else:
  3059.             for a, b in zip(bitstream(rams[0]), bitstream(rams[1])):
  3060.                 data.append(a | (b << 1))
  3061.             self.data = bitgroups_to_bytes(data)
  3062.  
  3063.     def _fillram(self, ram):
  3064.         mode = ['rle', 'data'][self._readbit()]
  3065.         size = self.size * 4
  3066.         while len(ram) < size:
  3067.             if mode == 'rle':
  3068.                 self._read_rle_chunk(ram)
  3069.                 mode = 'data'
  3070.             elif mode == 'data':
  3071.                 self._read_data_chunk(ram, size)
  3072.                 mode = 'rle'
  3073.         '''if len(ram) > size:
  3074.             #ram = ram[:size]
  3075.             raise ValueError(size, len(ram))
  3076.         '''
  3077.         ram[:] = self._deinterlace_bitgroups(ram)
  3078.  
  3079.     def _read_rle_chunk(self, ram):
  3080.  
  3081.         i = 0
  3082.         while self._readbit():
  3083.             i += 1
  3084.  
  3085.         n = self.table1[i]
  3086.         a = self._readint(i + 1)
  3087.         n += a
  3088.  
  3089.         for i in range(n):
  3090.             ram.append(0)
  3091.  
  3092.     def _read_data_chunk(self, ram, size):
  3093.         while 1:
  3094.             bitgroup = self._readint(2)
  3095.             if bitgroup == 0:
  3096.                 break
  3097.             ram.append(bitgroup)
  3098.  
  3099.             if size <= len(ram):
  3100.                 break
  3101.  
  3102.     def _decode(self, ram, mirror=None):
  3103.         if mirror is None:
  3104.             mirror = self.mirror
  3105.  
  3106.         for x in range(self.sizex):
  3107.             bit = 0
  3108.             for y in range(self.sizey):
  3109.                 i = y * self.sizex + x
  3110.                 a = (ram[i] >> 4) & 0xf
  3111.                 b = ram[i] & 0xf
  3112.  
  3113.                 a = self.table2[bit][a]
  3114.                 bit = a & 1
  3115.                 if mirror:
  3116.                     a = self.table3[a]
  3117.  
  3118.                 b = self.table2[bit][b]
  3119.                 bit = b & 1
  3120.                 if mirror:
  3121.                     b = self.table3[b]
  3122.  
  3123.                 ram[i] = (a << 4) | b
  3124.  
  3125.     def _xor(self, ram1, ram2, mirror=None):
  3126.         if mirror is None:
  3127.             mirror = self.mirror
  3128.  
  3129.         for i in range(len(ram2)):
  3130.             if mirror:
  3131.                 a = (ram2[i] >> 4) & 0xf
  3132.                 b = ram2[i] & 0xf
  3133.                 a = self.table3[a]
  3134.                 b = self.table3[b]
  3135.                 ram2[i] = (a << 4) | b
  3136.  
  3137.             ram2[i] ^= ram1[i]
  3138.  
  3139.     def _deinterlace_bitgroups(self, bits):
  3140.         l = []
  3141.         for y in range(self.sizey):
  3142.             for x in range(self.sizex):
  3143.                 i = 4 * y * self.sizex + x
  3144.                 for j in range(4):
  3145.                     l.append(bits[i])
  3146.                     i += self.sizex
  3147.         return l
  3148.  
  3149.  
  3150.     def _readbit(self):
  3151.         return next(self.bs)
  3152.  
  3153.     def _readint(self, count):
  3154.         return readint(self.bs, count)
  3155.  
  3156. def decompress(f, offset=None, mirror=False):
  3157.     """
  3158.     Decompress a pic given a file object. Return a planar 2bpp image.
  3159.  
  3160.     Optional: offset (for roms).
  3161.     """
  3162.     if offset is not None:
  3163.         f.seek(offset)
  3164.     dcmp = Decompressor(f, mirror=mirror)
  3165.     dcmp.decompress()
  3166.     return dcmp.data
  3167.  
  3168. def decomp_main( in_path, out_path ):
  3169.     if os.path.exists( out_path ):
  3170.         print( out_path + " already exists, use a different name" )
  3171.     else:
  3172.         if not os.path.exists( in_path ):
  3173.             print( in_path + " does not exist" )
  3174.         else:
  3175.             with open( in_path, 'rb' ) as in_file:
  3176.                 sprite = decompress( in_file )
  3177.                 with open( out_path, 'wb' ) as out_file:
  3178.                     out_file.write( sprite )
  3179.  
  3180. # hex converter
  3181.  
  3182. def str2byt(x):
  3183.     done = False
  3184.     out = b''
  3185.     byte = 0
  3186.     for nybble in x:
  3187.         if not done:
  3188.             byte = int( nybble, 16 )
  3189.             byte <<= 4
  3190.         else:
  3191.             byte |= ( int( nybble, 16 ) & 0xF )
  3192.             out = out + bytes([byte])
  3193.         done = not done
  3194.     return out
  3195.  
  3196. hx1 = lambda n: hex(n)[2:].zfill(2)
  3197.  
  3198. REGEX_DEC = re.compile(r'^  d[bw]   ((?:[0-9]{3},?)+)\s*(?:;.*)?$')
  3199. REGEX_HEX = re.compile(r'^  d[bw]   ((?:0(?:[A-Fa-f0-9]{2})+h,?)+)\s*(?:;.*)?$')
  3200.  
  3201. def divhx(x):
  3202.     pcs = []
  3203.     for i in range(len(x) // 2):
  3204.         pcs.append(x[i*2:i*2+2])
  3205.     return ''.join(pcs[::-1])
  3206.    
  3207. def divhxl(x):
  3208.     out = ''
  3209.     for k in x:
  3210.         out += divhx(k)
  3211.     return out
  3212.  
  3213. def hex_convert_main( input_string, data_type=None, v=None ):
  3214.     lins = input_string.splitlines()
  3215.     if not data_type: # we have to guess the type
  3216.         r1 = REGEX_DEC
  3217.         r2 = REGEX_HEX
  3218.         for i in range( len(lins) ):
  3219.             if r1.match(lins[i]):
  3220.                 data_type = 0
  3221.                 break
  3222.             elif r2.match(lins[i]):
  3223.                 data_type = 1
  3224.                 break
  3225.         else:
  3226.             raise Exception
  3227.     if data_type == 0: # decimal
  3228.         reg = REGEX_DEC
  3229.     else:
  3230.         reg = REGEX_HEX
  3231.     datout = ''
  3232.     uuct = 0
  3233.     for i,l in enumerate(lins):
  3234.         mm = reg.match(l)
  3235.         if mm:
  3236.             cur_dats = mm.groups()[0].split(',')
  3237.             if data_type == 0:
  3238.                 cur_dats_2 = [hx1(int(x[1:-1])) for x in cur_dats]
  3239.             else:
  3240.                 cur_dats_2 = [x[1:-1] for x in cur_dats]
  3241.             datout += ''.join(cur_dats_2)
  3242.         else:
  3243.             if v:
  3244.                 print('Line does not match pattern:')
  3245.                 print(i+1, l)
  3246.                 uuct += 1
  3247.                 if uuct > 10:
  3248.                     input()
  3249.                     uuct = 0
  3250.    
  3251.     try:
  3252.         return bytes.fromhex( datout )
  3253.     except AttributeError:
  3254.         return bytearray.fromhex( datout )
  3255.  
  3256.  
  3257. # makeimg.py
  3258.  
  3259. GBGRY = ((232, 232, 232), (160, 160, 160), (88, 88, 88), (16, 16, 16))
  3260. GBGRH = ((255, 255, 255), (176, 176, 176), (104, 104, 104), (0, 0, 0))
  3261. GBGRN = ((224, 248, 208), (136, 192, 112), (52, 104, 86), (8, 24, 32))
  3262. # GBGRHR = ((255, 255, 255), (104, 104, 104), (176, 176, 176), (0, 0, 0))
  3263. GBGRHR = ((255, 255, 255), (85, 85, 85), (170, 170, 170), (0, 0, 0))
  3264. #          255 * 1       ,  255 * (1/3),   255 * (2/3)  ,  255 * 0
  3265.  
  3266. def makeimg_main(args):
  3267.     dat = None
  3268.     # is args.data a data string or a file name?
  3269.     if re.match(r'^(?:[A-Fa-f0-9]{2})+$', args.data): # is args.data a data string?
  3270.         if not os.path.exists( args.data ): # is it *REALLY* a data string and not a file path?
  3271.             dat = bytearray(args.data, hex_char_encoding) # if yes then use it directly
  3272.     else: # if not, then open the filename and convert it to a datastring
  3273.         with open( args.data, 'rb' ) as f:
  3274.             raw = f.read()
  3275.             try:
  3276.                 dat = bytearray( raw, hex_char_encoding )
  3277.             except TypeError:
  3278.                 dat = bytearray( raw )
  3279.    
  3280.     if args.flag_ishex: # Decode a hex-coded file'
  3281.         string = dat.decode( hex_char_encoding )
  3282.         if args.flag_guess:
  3283.             dat = hex_convert_main( string )
  3284.         else:
  3285.             if args.flag_decimal:
  3286.                 dat = hex_convert_main( string, data_type = 0 )
  3287.             else:
  3288.                 dat = hex_convert_main( string, data_type = 1 )
  3289.    
  3290.     if args.flag_iscbb:
  3291.         i = 16
  3292.         while i < len(dat):
  3293.             del dat[i:i+16]
  3294.             i += 16
  3295.    
  3296.     if args.flag_compressed: # decompress a file
  3297.         decomp = Decompressor( d = dat, mirror = False )
  3298.         decomp.decompress()
  3299.         dat = decomp.data
  3300.    
  3301.     try:
  3302.         dat = dat.hex()
  3303.     except AttributeError:
  3304.         dat = "".join("%02x" % b for b in dat)
  3305.    
  3306.     imglen = len(dat) // 2
  3307.     if args.width:
  3308.         imgw = args.width
  3309.     elif args.square:
  3310.         imgw = int((imglen // 16) ** 0.5)
  3311.     else:
  3312.         imgw = 1
  3313.     if args.depth:
  3314.         assert args.depth in (1, 2, 4, 8)
  3315.         bitd = args.depth
  3316.     else:
  3317.         bitd = 2
  3318.     if args.palette == 'green':
  3319.         cols = GBGRN
  3320.     elif args.palette == 'gray':
  3321.         cols = GBGRY
  3322.     elif args.palette == 'grayhi':
  3323.         cols = GBGRH
  3324.     elif args.palette == 'grayhir':
  3325.         cols = GBGRHR
  3326.     else:
  3327.         cols = []
  3328.         if args.sprite:
  3329.             for i in range(2 ** bitd - 1):
  3330.                 pcnt = i / (2 ** bitd - 2)
  3331.                 # ~ print(pcnt)
  3332.                 pcnt = math.sqrt(pcnt)
  3333.                 # ~ print(pcnt)
  3334.                 rgb = int(255 * pcnt)
  3335.                 cols.append( [rgb, rgb, rgb] )
  3336.             if args.reverse:
  3337.                 cols = cols[::-1]
  3338.             cols.insert(0, [255, 255, 255])
  3339.         else:
  3340.             for i in range(2 ** bitd):
  3341.                 pcnt = i / (2 ** bitd - 1)
  3342.                 rgb = int(255 * pcnt)
  3343.                 cols.append([rgb, rgb, rgb])
  3344.             if args.reverse:
  3345.                 cols = cols[::-1]
  3346.     imgh = imglen // bitd // imgw // 8
  3347.     if imgh * imgw * bitd * 8 != imglen:
  3348.         imgh += 1
  3349.    
  3350.     out_tmp = [[0 for x in range(imgw*8*3)] for y in range(imgh*8)]
  3351.    
  3352.     #out = Image.new('RGB', (imgw*8, imgh*8))
  3353.     #pxa = out.load()
  3354.     i = 0
  3355.     binimg = ''
  3356.     for nib in dat:
  3357.         binimg += bin(int(nib, 16))[2:].zfill(4)
  3358.     if bitd != 2:
  3359.         if args.subblk:
  3360.             for blky2 in range(imgh // 2):
  3361.                 for blkx2 in range(imgw // 2):
  3362.                     for blkyy in range(2):
  3363.                         for blkxx in range(2):
  3364.                             for yy in range(8):
  3365.                                 for xx in range(8):
  3366.                                     blkx = blkx2 * 2 + blkxx
  3367.                                     blky = blky2 * 2 + blkyy
  3368.                                     if args.vertical:
  3369.                                         x = blky * 8 + xx
  3370.                                         y = blkx * 8 + yy
  3371.                                     else:
  3372.                                         x = blkx * 8 + xx
  3373.                                         y = blky * 8 + yy
  3374.                                     if i >= len(binimg):
  3375.                                         continue
  3376.                                     colid = binimg[i*bitd:(i+1)*bitd]
  3377.                                     out_tmp[y][(x*3)+0] = cols[int(colid, 2)][0]
  3378.                                     out_tmp[y][(x*3)+1] = cols[int(colid, 2)][1]
  3379.                                     out_tmp[y][(x*3)+2] = cols[int(colid, 2)][2]
  3380.                                     i += 1
  3381.         else:
  3382.             for blky in range(imgh):
  3383.                 for blkx in range(imgw):
  3384.                     for yy in range(8):
  3385.                         for xx in range(8):
  3386.                             if args.vertical:
  3387.                                 x = blky * 8 + xx
  3388.                                 y = blkx * 8 + yy
  3389.                             else:
  3390.                                 x = blkx * 8 + xx
  3391.                                 y = blky * 8 + yy
  3392.                             if i >= len(binimg):
  3393.                                 continue
  3394.                             colid = binimg[i*bitd:(i+1)*bitd]
  3395.                             out_tmp[y][(x*3)+0] = cols[int(colid, 2)][0]
  3396.                             out_tmp[y][(x*3)+1] = cols[int(colid, 2)][1]
  3397.                             out_tmp[y][(x*3)+2] = cols[int(colid, 2)][2]
  3398.                             i += 1
  3399.     else:
  3400.         if args.subblk:
  3401.             for blky2 in range(imgh // 2):
  3402.                 for blkx2 in range(imgw // 2):
  3403.                     for blkyy in range(2):
  3404.                         for blkxx in range(2):
  3405.                             for yy in range(8):
  3406.                                 for xx in range(8):
  3407.                                     blkx = blkx2 * 2 + blkxx
  3408.                                     blky = blky2 * 2 + blkyy
  3409.                                     if args.vertical:
  3410.                                         x = blky * 8 + xx
  3411.                                         y = blkx * 8 + yy
  3412.                                     else:
  3413.                                         x = blkx * 8 + xx
  3414.                                         y = blky * 8 + yy
  3415.                                     if i >= len(binimg):
  3416.                                         continue
  3417.                                     colidhi = binimg[i]
  3418.                                     colidlo = binimg[i + 8]
  3419.                                     colid = colidhi + colidlo
  3420.                                     out_tmp[y][(x*3)+0] = cols[int(colid, 2)][0]
  3421.                                     out_tmp[y][(x*3)+1] = cols[int(colid, 2)][1]
  3422.                                     out_tmp[y][(x*3)+2] = cols[int(colid, 2)][2]
  3423.                                     i += 1
  3424.                                 i += 8
  3425.         else:
  3426.             for blky in range(imgh):
  3427.                 for blkx in range(imgw):
  3428.                     for yy in range(8):
  3429.                         for xx in range(8):
  3430.                             if args.vertical:
  3431.                                 x = blky * 8 + xx
  3432.                                 y = blkx * 8 + yy
  3433.                             else:
  3434.                                 x = blkx * 8 + xx
  3435.                                 y = blky * 8 + yy
  3436.                             if i >= len(binimg):
  3437.                                 continue
  3438.                             try:
  3439.                                 colidhi = binimg[i]
  3440.                                 colidlo = binimg[i + 8]
  3441.                                 colid = colidhi + colidlo
  3442.                                 out_tmp[y][(x*3)+0] = cols[int(colid, 2)][0]
  3443.                                 out_tmp[y][(x*3)+1] = cols[int(colid, 2)][1]
  3444.                                 out_tmp[y][(x*3)+2] = cols[int(colid, 2)][2]
  3445.                             except IndexError:
  3446.                                 pass
  3447.                             i += 1
  3448.                         i += 8
  3449.     if args.scale:
  3450.         print("Sprite scaling is not implemented")
  3451.     #   oldw, oldh = out.size
  3452.     #   neww = oldw * args.scale
  3453.     #   newh = oldh * args.scale
  3454.     #   out = out.resize((neww, newh))
  3455.     #   # ~ out = transform.scale(out, (neww, newh))
  3456.     out = from_array( out_tmp, 'RGB' )
  3457.     out.save(args.out)
  3458. #
  3459.  
  3460. if __name__ == '__main__':
  3461.     parser = argparse.ArgumentParser(
  3462.         description='Make a DMG image file from a string of bytes',
  3463.         epilog='example: "makeimg_standalone.py -H -C -s 1 -d 2 -l grayhir -tq SPRITE.DAT sprite_out.png"'
  3464.     )
  3465.     parser.add_argument('data', type=str, help='byte string OR file to read')
  3466.     parser.add_argument('out', type=str, help='picture out')
  3467.     parser.add_argument('-w', dest='width', type=int, help='width (in 8x8 tiles) of the image')
  3468.     parser.add_argument('-d', dest='depth', type=int, help='bit depth (1, 2, 4, 8)')
  3469.     parser.add_argument('-s', dest='scale', type=int, help='<- make the sprite this much bigger (not implemented)')
  3470.     parser.add_argument('-r', dest='reverse', action='store_true', help='reverse colors')
  3471.     parser.add_argument('-p', dest='sprite', action='store_true', help='use sprite colors')
  3472.     parser.add_argument('-k', dest='subblk', action='store_true', help='subblk')
  3473.     parser.add_argument('-v', dest='view', action='store_true', help='View the output file automatically')
  3474.     parser.add_argument('-l', dest='palette', type=str, help='The palette to use for the sprite (use grayhir for now)')
  3475.     parser.add_argument('-t', dest='vertical', action='store_true', help='vertical (?)')
  3476.     parser.add_argument('-q', dest='square', action='store_true', help=  'Assume square image, autodetect width')
  3477.     parser.add_argument('-x', dest='extradat', action='store_true', help='extradat (?)')
  3478.     parser.add_argument('-cbb', dest='flag_iscbb', action='store_true', help='The input file is a CBB graphic')
  3479.     parser.add_argument('-H', dest='flag_ishex', action='store_true', help='The input file is a text-encoded binary')
  3480.     parser.add_argument('-D', dest='flag_decimal', action='store_true', help='(if -H) Input data type is decimal')
  3481.     parser.add_argument('-G', dest='flag_guess', action='store_true', help='(if -H) Try to guess input data type')
  3482.     parser.add_argument('-C', dest='flag_compressed', action='store_true', help='The input file is compressed')
  3483.     #parser.add_argument('-simple', dest="flag_simple", action='store_true', help='The same as -H -C -s 1')
  3484.    
  3485.     args = parser.parse_args()
  3486.    
  3487.     makeimg_main(args)
  3488. #
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement