Rewrite the start of the Writing section to use from_array GitOrigin-RevId: 5f0b4260815f40cc9e13ed1d51477048e9c7f75f Change-Id: Ide05f7116ed913fef92b8a7f1f7ec317b0397d5e
diff --git a/man/ex.rst b/man/ex.rst index f833aaf..e0d8b04 100644 --- a/man/ex.rst +++ b/man/ex.rst
@@ -12,73 +12,90 @@ Writing ------- -The basic strategy is to create a `~png.Writer` object (an instance of -`png.Writer`) and then call its `~png.Writer.write` method -with a binary file (that is open for writing), and the pixel data. +The simplest way to write a PNG is to make a 2D array, pass it +to `png.from_array` and save it:: + + import png + + rows = [ + [0, 1, 1, 1, 1, 1, 1, 0], + [1, 0, 0, 0, 0, 0, 0, 1], + [1, 0, 1, 0, 0, 1, 0, 1], + [1, 0, 0, 0, 0, 0, 0, 1], + [1, 0, 1, 0, 0, 1, 0, 1], + [1, 0, 0, 1, 1, 0, 0, 1], + [1, 0, 0, 0, 0, 0, 0, 1], + [0, 1, 1, 1, 1, 1, 1, 0], + ] + image = png.from_array(rows, "L;1") + image.save("smile.png") + +Python doesn't really have 2D arrays, so here i use a list of +lists. +Those who are already objecting that this isn't space efficient +should be reassured that it is possible to use an +`array.array +<https://docs.python.org/3/library/array.html#array.array>`_ +which saves space horizontally, and it is also possible to +stream using an iterator which saves space vertically. + +The ``"L;1"`` argument to `~png.from_array` is the *mode*. +``"L"`` makes a greyscale image, one that has only *lightness*. +The ``";1"`` sets the *bitdepth*. +The bitdepth can be anywhere from 1 (with a maximum channel +value of 1) to 16 (with a maximum channel value of 65,535). + +The default bitdepth is 8, which has a maximum channel value of 255. + +You can write colour RGB images with a mode of "RGB", and you +can add an alpha channel to either mode to get "LA" or "RGBA". + +Writer objects +^^^^^^^^^^^^^^ + +`png.from_array` is in some ways a simplification. +It uses a `png.Writer` object and you can use that too. +While the `png.Writer` interface is currently more flexible (you +can write extra chunks for example), it is also more +complicated. + +The basic strategy is to create a `~png.Writer` object and then call its `~png.Writer.write` method +with an open binary (writable) file, and the row data. The `~png.Writer` object encapsulates all the information about the PNG file: image size, colour, bit depth, and so on. -A Ramp -^^^^^^ - -Create a one row image, that has all grey values from 0 to 255. This is -a bit like Netpbm's ``pgmramp``. :: - - import png - f = open('ramp.png', 'wb') # binary mode is important - w = png.Writer(256, 1, greyscale=True) - w.write(f, [range(256)]) - f.close() - -Note that our single row, generated by ``range(256)``, must itself be -enclosed in a list. That's because the :meth:`~png.Writer.write` method expects -a list of rows. - - -A Little Message -^^^^^^^^^^^^^^^^ - -A list of strings holds a graphic in ASCII graphic form. We convert it -to a list of integer lists (the required form for the -:meth:`~png.Writer.write` method), -and write it out as a black-and-white PNG (bilevel greyscale). :: - - import png - s = ['110010010011', - '101011010100', - '110010110101', - '100010010011'] - s = [[int(c) for c in row] for row in s] - - w = png.Writer(len(s[0]), len(s), greyscale=True, bitdepth=1) - f = open('png.png', 'wb') - w.write(f, s) - f.close() - -Note how we use ``len(s[0])`` (the length of the first row) for the *x* -argument and ``len(s)`` (the number of rows) for the *y* argument. - A Palette ^^^^^^^^^ -The previous example, "a little message", can be converted to colour -simply by creating a PNG file with a palette. The only difference is -that a *palette* argument is passed to the :meth:`~png.Writer.write` method instead of -``greyscale=True``:: +The previous example, a black-and-white smiley face, can +be converted to colour +by creating a PNG file with a palette. + +`~png.from_array` can't currently create a PNG file with a +palette. +But `~png.Writer` can, +by passing a *palette* argument to the :meth:`~png.Writer.write` +method:: import png - s = ['110010010011', - '101011010100', - '110010110101', - '100010010011'] - s = [[int(c) for c in row] for row in s] - palette=[(0x55,0x55,0x55), (0xff,0x99,0x99)] - w = png.Writer(len(s[0]), len(s), palette=palette, bitdepth=1) - f = open('png.png', 'wb') - w.write(f, s) + rows = [ + [0, 1, 1, 1, 1, 1, 1, 0], + [1, 0, 0, 0, 0, 0, 0, 1], + [1, 0, 1, 0, 0, 1, 0, 1], + [1, 0, 0, 0, 0, 0, 0, 1], + [1, 0, 1, 0, 0, 1, 0, 1], + [1, 0, 0, 1, 1, 0, 0, 1], + [1, 0, 0, 0, 0, 0, 0, 1], + [0, 1, 1, 1, 1, 1, 1, 0], + ] + + palette = [(0x55, 0x55, 0x55), (0xFF, 0x99, 0x99)] + w = png.Writer(size=(8, 8), palette=palette, bitdepth=1) + f = open("pal.png", "wb") + w.write(f, rows) Note that the palette consists of two entries (the bit depth is 1 so there are only 2 possible colours). Each entry is an RGB triple. If we