- Add acknowledgements section and thank Patrick Stein
[zpng.git] / doc / index.html
blob3b59ab2f21be3638f60fc99c35259a7c362c7131
1 <html>
2 <head>
3 <title>ZPNG - Create PNG files from Common Lisp</title>
4 <style type="text/css">
5 a, a:visited { text-decoration: none }
6 a[href]:hover { text-decoration: underline }
7 pre { background: #DDD; padding: 0.25em }
8 p.download { color: red }
9 .transparent { background-image: url(background.gif) }
10 tt.code { background: #DDD }
11 </style>
12 </head>
14 <body>
16 <h2>ZPNG - Create PNG files from Common Lisp</h2>
18 <blockquote class='abstract'>
19 <h3>Abstract</h3>
21 <p>ZPNG is a Common Lisp library for creating PNG files. It
22 uses <a href='http://www.xach.com/lisp/salza2/'>Salza2</a> for
23 compression.
25 The current version is 1.2, released on September 17, 2008.
27 <p class='download'>Download shortcut:
29 <p><a href='http://www.xach.com/lisp/zpng.tgz'>http://www.xach.com/lisp/zpng.tgz</a>
31 </blockquote>
33 <h3>Contents</h3>
35 <ol>
36 <li> <a href='#sect-overview'>Overview and Limitations</a>
37 <li> <a href='#sect-examples'>Examples</a>
38 <li> <a href='#sect-dictionary'>Dictionary</a>
40 <ul>
42 <li>Common Functions
44 <ul>
45 <li> <a href='#samples-per-pixel'><tt>samples-per-pixel</tt></a>
46 <li> <a href='#width'><tt>width</tt></a>
47 <li> <a href='#height'><tt>height</tt></a>
48 <li> <a href='#rowstride'><tt>rowstride</tt></a>
49 <li> <a href='#color-type'><tt>color-type</tt></a>
50 </ul>
53 <li> In-memory PNGs
55 <ul>
56 <li> <a href='#png'><tt>png</tt></a>
57 <li> <a href='#image-data'><tt>image-data</tt></a>
58 <li> <a href='#data-array'><tt>data-array</tt></a>
59 <li> <a href='#copy-png'><tt>copy-png</tt></a>
60 <li> <a href='#png='><tt>png=</tt></a>
61 <li> <a href='#write-png'><tt>write-png</tt></a>
62 <li> <a href='#write-png-stream'><tt>write-png-stream</tt></a>
63 </ul>
65 <li> Streamed, row-at-a-time PNGs
67 <ul>
68 <li> <a href='#streamed-png'><tt>streamed-png</tt></a>
69 <li> <a href='#row-data'><tt>row-data</tt></a>
70 <li> <a href='#start-png'><tt>start-png</tt></a>
71 <li> <a href='#write-row'><tt>write-row</tt></a>
72 <li> <a href='#rows-written'><tt>rows-written</tt></a>
73 <li> <a href='#rows-left'><tt>rows-left</tt></a>
74 <li> <a href='#finish-png'><tt>finish-png</tt></a>
75 </ul>
77 <li> Streamed, pixel-at-a-time PNGs
79 <ul>
80 <li> <a href='#pixel-streamed-png'><tt>pixel-streamed-png</tt></a>
81 <li> <a href='#write-pixel'><tt>write-pixel</tt></a>
82 <li> <a href='#pixels-left-in-row'><tt>pixels-left-in-row</tt></a>
83 </ul>
86 <li> Errors
88 <ul>
89 <li> <a href='#zpng-error'><tt>zpng-error</tt></a>
90 <li> <a href='#invalid-size'><tt>invalid-size</tt></a>
91 <li> <a href='#invalid-size-width'><tt>invalid-size-width</tt></a>
92 <li> <a href='#invalid-size-height'><tt>invalid-size-height</tt></a>
93 <li> <a href='#invalid-row-length'><tt>invalid-row-length</tt></a>
94 <li> <a href='#insufficient-rows'><tt>insufficient-rows</tt></a>
95 <li> <a href='#incomplete-row'><tt>incomplete-row</tt></a>
96 <li> <a href='#too-many-rows'><tt>too-many-rows</tt></a>
97 <li> <a href='#color-type-mismatch'><tt>color-type-mismatch</tt></a>
98 </ul>
100 </ul>
102 <li> <a href='#sect-references'>References</a>
103 <li> <a href='#sect-acknowledgements'>Acknowledgements</a>
104 <li> <a href='#sect-feedback'>Feedback</a>
105 </ol>
107 <a name='sect-overview'><h3>Overview and Limitations</h3></a>
109 <p>ZPNG provides three interfaces creating PNG files. The first is through a
110 <a href='#png'><tt>PNG</tt></a> object, which holds all image sample
111 data and which may be written out to a file all at once. The second is
112 through a <a href='#streamed-png'><tt>STREAMED-PNG</tt></a> object,
113 which writes a single output row of the image at a time. By working
114 with only a single row at a time, images that are too big to fit in
115 memory may still be written out incrementally as a PNG file. The third
116 is through a <a href='#pixel-streamed-png'><tt>PIXEL-STREAMED-PNG</tt></a>
117 object which allows you to write a single pixel at a time. It still
118 buffers a whole row at a time, but it manages all of the buffer
119 handling for you.
121 <p>The PNG file format has many options, and ZPNG supports only a
122 subset of them.
124 <ul>
125 <li> does not load PNG files
126 <li> supports only 8 bits per sample
127 <li> does not support filtering
128 <li> does not support indexed color
129 </ul>
132 <a name='sect-examples'><h3>Examples</h3></a>
135 <pre><div style='float: right' class='transparent'><img src='mandelbrot.png'
136 ></div>(defun draw-mandelbrot (file)
137 (let* ((png (make-instance '<a href='#png'>png</a>
138 :color-type :grayscale-alpha
139 :width 200
140 :height 200))
141 (image (<a href='#data-array'>data-array</a> png))
142 (max 255))
143 (dotimes (y 200 (<a href='#write-png'>write-png</a> png file))
144 (dotimes (x 200)
145 (let ((c (complex (- (/ x 100.0) 1.5) (- (/ y 100.0) 1.0)))
146 (z (complex 0.0 0.0))
147 (iteration 0))
148 (loop
149 (setf z (+ (* z z) c))
150 (incf iteration)
151 (cond ((< 4 (abs z))
152 (setf (aref image y x 1) iteration)
153 (return))
154 ((= iteration max)
155 (setf (aref image y x 1) 255)
156 (return)))))))))
157 </pre>
159 <pre><div style='float: right' class='transparent'><img src='rgb.png'
160 ></div>(defun draw-rgb (file)
161 (let ((png (make-instance '<a
162 href='#pixel-streamed-png'>pixel-streamed-png</a>
163 :color-type :truecolor-alpha
164 :width 200
165 :height 200)))
166 (with-open-file (stream file
167 :direction :output
168 :if-exists :supersede
169 :if-does-not-exist :create
170 :element-type '(unsigned-byte 8))
171 (<a href='#start-png'>start-png</a> png stream)
172 (loop for a from 38 to 255 by 31
173 do (loop for b from 10 to 255 by 10
174 do (loop for g from 38 to 255 by 31
175 do (loop for r from 10 to 255 by 10
176 do (<a href='#write-pixel'
177 >write-pixel</a> (list r g b a) png)))))
178 (<a href='#finish-png'>finish-png</a> png))))
179 </pre>
181 <a name='sect-dictionary'><h3>Dictionary</h3></a>
183 <p>The following symbols are exported from the ZPNG package.
187 <p><a name='samples-per-pixel'>[Function]</a><br>
188 <b>samples-per-pixel</b> <i>png</i> => <i>samples</i>
190 <blockquote>
191 Returns the number of octet samples that make up a single pixel.
193 <p><table cellpadding=0 cellspacing=5>
194 <tr>
195 <th>Image Color Type</th>
196 <th>Samples per Pixel</th>
197 </tr>
198 <tr>
199 <td>Grayscale</td><td align=center>1</td>
200 </tr>
201 <tr>
202 <td>Truecolor</td><td align=center>3</td>
203 </tr>
204 <tr>
205 <td>Grayscale with Alpha</td><td align=center>2</td>
206 </tr>
207 <tr>
208 <td>Truecolor with Alpha</td><td align=center>4</td>
209 </tr>
210 </table>
212 </blockquote>
215 <p><a name='width'><a name='height'>[Functions]</a></a><br>
216 <b>width</b> <i>png</i> => <i>width</i><br>
217 <b>height</b> <i>png</i> => <i>height</i>
219 <blockquote>
220 Returns the width or height of <i>png</i>.
221 </blockquote>
223 <p><a name='rowstride'>[Function]</a><br>
224 <b>rowstride</b> <i>png</i> => <i>rowstride</i>
226 <blockquote>
227 Returns the number of samples in a single row of <i>png</i>. It is
228 equivalent
229 to <tt class=code>(*&nbsp;(<a href='#width'>width</a>&nbsp;png)&nbsp;(<a href='#samples-per-pixel'>samples-per-pixel</a>&nbsp;png))</tt>.
230 </blockquote>
232 <p><a name='color-type'>[Function]</a><br>
233 <b>color-type</b> <i>png</i> => <i>color-type</i>
235 <blockquote>
236 Returns the color type of <i>png</i>, one of
237 of <tt>:grayscale</tt>, <tt>:truecolor</tt>,
238 <tt>:grayscale-alpha</tt>, or <tt>:truecolor-alpha</tt>.
239 </blockquote>
242 <p><a name='png'>[Class]</a><br>
243 <b>png</b>
245 <blockquote>
246 Instances of this class may be created directly. Supported initargs:
248 <ul>
250 <li> <tt>:width</tt> - required, the width of the image
252 <li> <tt>:height</tt> - required, the height of the image
254 <li> <tt>:color-type</tt> - optional, the color type of the image, one
255 of <tt>:grayscale</tt>, <tt>:truecolor</tt> (the
256 default), <tt>:grayscale-alpha</tt>, or <tt>:truecolor-alpha</tt>
258 <li> <tt>:image-data</tt> - optional, the sample data of the image. If
259 specified, this must be an octet vector with a length of
260 <i>width</i>&nbsp;&times;&nbsp;<i>height</i>&nbsp;&times;&nbsp;<i>samples-per-pixel</i>. If
261 not specified, an image data vector of the appropriate size will be
262 created automatically.
264 </ul>
266 </blockquote>
269 <p><a name='image-data'>[Function]</a><br>
270 <b>image-data</b> <i>png</i> => <i>octet-vector</i>
272 <blockquote>
273 Returns the image data of <i>png</i>. Samples are laid out from left
274 to right, top to bottom, so the first samples of data affect the
275 upper-left of the image and the final samples affect the lower-right.
277 <p><table cellpadding=0 cellspacing=5>
278 <tr>
279 <th>Image Color Type</th>
280 <th>Pixel Sample Layout</th>
281 </tr>
282 <tr>
283 <td>Grayscale</td><td>S|S|S...</td>
284 </tr>
285 <tr>
286 <td>Truecolor</td><td>RGB|RGB|RGB...</td>
287 </tr>
288 <tr>
289 <td>Grayscale with Alpha</td><td>SA|SA|SA...</td>
290 </tr>
291 <tr>
292 <td>Truecolor with Alpha</td><td>RGBA|RGBA|RGBA...</td>
293 </tr>
294 </table>
296 <p>Layout of the samples into pixels is done according to the image's
297 color type and is fully documented in
298 the <a href="http://www.w3.org/TR/PNG/">Portable Network Graphics
299 Specification.
300 </blockquote>
303 <p><a name='data-array'>[Function]</a><br>
304 <b>data-array</b> <i>png</i> => <i>data-array</i>
306 <blockquote>
307 Returns a multidimensional array representing the pixels
308 of <i>png</i>. The dimensions correspond to the height, width, and
309 pixel components, respectively. For example, to access the red
310 component at &lt;53,100&gt; of a truecolor PNG, you could use this:
312 <pre>
313 (aref (data-array png) 100 53 0)
314 </pre>
316 <p>Note the reversed order of the coordinate arguments; this is a
317 consequence of Common Lisp's row-major ordering of elements in a
318 multidimensional array and PNG's specified sample layout.
320 </blockquote>
323 <p><a name='copy-png'>[Function]</a><br>
324 <b>copy-png</b> <i>png</i> => <i>png-copy</i>
326 <blockquote>
327 Create a copy of <i>png</i>.
328 </blockquote>
331 <p><a name='png='>[Function]</a><br>
332 <b>png=</b> <i>png1</i> <i>png2</i> => <i>boolean</i>
334 <blockquote>
335 Returns true if png1 and png2 are equal. Equality is defined as having
336 the same dimensions, color type, and image data.
337 </blockquote>
340 <p><a name='write-png'>[Function]</a><br>
341 <b>write-png</b> <i>png</i> <i>file</i>
342 <tt>&amp;key</tt> (<i>if-exists</i> <tt>:supersede</tt>) => pathname
344 <blockquote>
345 Writes <i>png</i> to <i>file</i> and returns the truename
346 of <i>file</i>. <i>if-exists</i> is passed to the
347 underlying <tt>CL:OPEN</tt> call for opening the output file.
348 </blockquote>
351 <p><a name='write-png-stream'>[Function]</a><br>
352 <b>write-png-stream</b> <i>png</i> <i>stream</i> => |
354 <blockquote>
355 Writes <i>png</i> to <i>stream</i>, which should be an output stream
356 that can accept octets.
357 </blockquote>
360 <p><a name='streamed-png'>[Class]</a><br>
361 <b>streamed-png</b>
363 <blockquote>
364 Instances of this class may be created directly. Supports all the
365 initargs of the <a href='#png'><tt>PNG</tt></a> class
366 except <tt>:IMAGE-DATA</tt>.
368 <p>In contrast to <tt>PNG</TT> instances, <tt>STREAMED-PNG</tt>
369 instances do not keep all the image data in one large vector. Instead,
370 instances are used to write out the image data of a PNG file one row
371 at a time. The protocol for incrementally writing out via
372 a <tt>STREAMED-PNG</tt> involves these generic functions:
374 <ul>
375 <li> <a href='#row-data'><tt>ROW-DATA</tt></a>
376 <li> <a href='#start-png'><tt>START-PNG</tt></a>
377 <li> <a href='#write-row'><tt>WRITE-ROW</tt></a>
378 <li> <a href='#rows-written'><tt>ROWS-WRITTEN</tt></a>
379 <li> <a href='#rows-left'><tt>ROWS-LEFT</tt></a>
380 <li> <a href='#finish-png'><tt>FINISH-PNG</tt></a>
381 </ul>
383 </blockquote>
386 <p><a name='row-data'>[Function]</a><br>
387 <b>row-data</b> <i>streamed-png</i> => <i>octet-vector</i>
389 <blockquote>
390 Returns a vector suitable for passing
391 to <a href='#write-row'><tt>WRITE-ROW</tt></a>
392 for <i>streamed-png</i>; it has the appropriate number of entries for
393 the image width and color type of the png. The initial contents are
394 all zeroes. For a given streamed png, each call to <tt>row-data</tt>
395 will return the <i>same</i> vector, not a fresh one.
396 </blockquote>
399 <p><a name='start-png'>[Function]</a><br>
400 <b>start-png</b> <i>png</i> <i>stream</i> => <i>png</i>
402 <blockquote>
403 Writes PNG file header data to <i>stream</i>, which must be an output
404 stream that supports writing <tt>(unsigned-byte&nbsp;8)</tt> data. The
405 header data is taken from <i>png</i>, which must be
406 a <a href='#streamed-png'><tt>STREAMED-PNG</tt></a> instance.
407 </blockquote>
410 <p><a name='write-row'>[Function]</a><br>
411 <b>write-row</b> <i>row</i> <i>png</i>
412 <tt>&key</tt> (<i>start</i> 0) <i>end</i> => |
414 <blockquote>
415 Writes <i>row</i> to the output stream of <i>png</i>. <i>row</i> must
416 be an
417 <tt>(unsigned-byte&nbsp;8)</tt> vector with the appropriate number of
418 entries for <i>png</i>. <i>start</i> defaults to 0 and <i>end</i>
419 defaults to <i>start</i>
420 + <a href='#rowstride'><tt>ROWSTRIDE</tt></a>.
422 The difference between <i>end</i> and <i>start</i> should be equal to
423 <tt class=code>(<a href='#rowstride'>rowstride</a>&nbsp;png</i>)</tt>. <i>png</i>
424 must be a <a href='#streamed-png'><tt>STREAMED-PNG</tt></a> instance.
426 <p>If the row length, as defined by <i>start</i> and <i>end</i>, is
427 not the right size, an error of
428 type <a href='#invalid-row-length'><tt>INVALID-ROW-LENGTH</tt></a> is
429 signaled.
431 <p>If writing <i>row</i> would exceed the number of rows in the image
432 (as defined by <a href='#height'><tt>HEIGHT</tt></a>), an error of
433 type <a href='#too-many-rows'><tt>TOO-MANY-ROWS</tt></a> is signaled.
436 </blockquote>
439 <p><a name='rows-written'>[Function]</a><br>
440 <b>rows-written</b> <i>streamed-png</i> => <i>count</i>
442 <blockquote>
443 Returns the number of rows written to <i>streamed-png</i> so far.
444 </blockquote>
447 <p><a name='rows-left'>[Function]</a><br>
448 <b>rows-left</b> <i>streamed-png</i> => <i>count</i>
450 <blockquote>
451 Returns the number of rows left to write
452 to <i>streamed-png</i>. Equivalent to
453 <tt class=code>(- (<a href='#height'>height</a> png)
454 (<a href='#rows-written'>rows-written</a> png))</tt>.
456 </blockquote>
459 <p><a name='finish-png'>[Function]</a><br>
460 <b>finish-png</b> <i>streamed-png</i> => |
462 <blockquote>
463 Concludes writing PNG file data to the output stream
464 of <i>streamed-png</i>. The internal state of streamed-png is reset in
465 such a way that it can be re-used to write another PNG file, with the
466 same dimensions and color type parameters, using
467 another <a href='#start-png'><tt>START-PNG</tt></a>/<a href='#write-row'><tt>WRITE-ROW</tt></a>/<a href='#finish-png'><tt>FINISH-PNG</tt></a>
468 sequence.
470 <p>This function must be called only after
471 exactly <a href='#height'><tt>HEIGHT</tt></a> rows have been written
472 to <i>streamed-png</i>
473 via <a href='#write-row'><tt>WRITE-ROW</tt></a>. If too few rows have
474 been written to <i>streamed-png</i>, an error of
475 type <a href='#insufficient-rows'><tt>INSUFFICIENT-ROWS</tt></a> is
476 signaled.
477 </blockquote>
480 <p><a name='pixel-streamed-png'>[Class]</a><br>
481 <b>pixel-streamed-png</b>
483 <blockquote>
484 Instances of this class may be created directly. Supports all the
485 initargs of the <a href='#streamed-png'><tt>STREAMED-PNG</tt></a> class.
487 <p>The <tt>PIXEL-STREAMED-PNG</tt> class extends the <tt>STREAMED-PNG</TT>
488 class. Rather than preparing a row of pixels and caling the
489 <a href='#write-row'><tt>WRITE-ROW</tt></a> method, with
490 <tt>PIXEL-STREAMED-PNG</tt> instances, you write a single pixel
491 at a time with the <tt>WRITE-PIXEL</tt> method. The protocol for incrementally writing out via
492 a <tt>PIXEL-STREAMED-PNG</tt> involves these generic functions:
494 <ul>
495 <li> <a href='#start-png'><tt>START-PNG</tt></a>
496 <li> <a href='#write-pixel'><tt>WRITE-PIXEL</tt></a>
497 <li> <a href='#rows-written'><tt>ROWS-WRITTEN</tt></a>
498 <li> <a href='#rows-left'><tt>ROWS-LEFT</tt></a>
499 <li> <a href='#pixels-left-in-row'><tt>PIXELS-LEFT-IN-ROW</tt></a>
500 <li> <a href='#finish-png'><tt>FINISH-PNG</tt></a>
501 </ul>
503 </blockquote>
506 <p><a name='write-pixel'>[Function]</a><br>
507 <b>write-pixel</b> <i>pixel-samples</i> <i>pixel-streamed-png</i>
509 <blockquote>
510 Writes the samples for a single pixel from the sequence
511 <i>pixel-samples</i> to the next available spot in
512 the <a href='#row-data'><tt>ROW-DATA</tt></a> buffer. When the buffer
513 is full, this method invokes the
514 <a href='#write-row'><tt>WRITE-ROW</tt></a> method. The length of the
515 <tt>PIXEL-SAMPLES</tt> sequence must be equal to the <a
516 href='#samples-per-pixel'><tt>SAMPLES-PER-PIXEL</tt></a>.
517 </blockquote>
519 <p><a name='pixels-left-in-row'>[Function]</a><br>
520 <b>pixels-left-in-row</b> <i>pixel-streamed-png</i>
522 <blockquote>
523 Returns the number of pixels left to write to complete the current row
524 of pixels.
525 </blockquote>
528 <p><a name='zpng-error'>[Condition]</a><br>
529 <b>zpng-error</b>
531 <blockquote>
532 All errors signaled by ZPNG are a subtype of <tt>ZPNG-ERROR</tt>,
533 which is a subtype of <tt>CL:ERROR</tt>.
534 </blockquote>
537 <p><a name='invalid-size'>[Condition]</a><br>
538 <b>invalid-size</b>
540 <blockquote>
541 A condition of this type is signaled when a PNG with invalid size is
542 created. Valid PNGs have positive width and height.
543 </blockquote>
546 <p><a name='invalid-size-width'>[Accessors]</a><br>
547 <b>invalid-size-width</b> <i>condition</i> => <i>width</i><br>
548 <b>invalid-size-height</b> <i>condition</i> => <i>height</i>
550 <blockquote>
551 These accessors provide the invalid size used for a PNG.
552 </blockquote>
555 <p><a name='invalid-row-length'>[Condition]</a><br>
556 <b>invalid-row-length</b>
558 <blockquote>
559 A condition of this type is signaled when a row with an incorrect size
560 is passed to <a href='#write-row'><tt>WRITE-ROW</tt></a>.
561 </blockquote>
564 <p><a name='insufficient-rows'>[Condition]</a><br>
565 <b>insufficient-rows</b>
567 <blockquote>
568 A condition of this type is signaled
569 from <a href='#finish-png'><tt>FINISH-PNG</tt></a> when it is called
570 before enough rows have been written
571 via <a href='#write-row'><tt>WRITE-ROW</tt></a>.
572 </blockquote>
575 <p><a name='incomplete-row'>[Condition]</a><br>
576 <b>incomplete-row</b>
578 <blockquote>
579 A condition of this type is signaled from <a
580 href='#finish-png'><tt>FINISH-PNG</tt></a> when it is called on a <a
581 href='#pixel-streamed-png'><tt>PIXEL-STREAMED-PNG</tt></a> before the
582 current row of pixels has been completed.
583 </blockquote>
585 <p><a name='too-many-rows'>[Condition]</a><br>
586 <b>too-many-rows</b>
588 <blockquote>
589 A condition of this type is signaled
590 from <a href='#write-row'><tt>WRITE-ROW</tt></a> if it is called more
591 times than is necessary for the given PNG.
592 </blockquote>
594 <p><a name='color-type-mismatch'>[Condition]</a><br>
595 <b>color-type-mismatch</b>
597 <blockquote>
598 A condition of this type is signaled from <a
599 href='#write-pixel'><tt>WRITE-PIXEL</tt></a> if the number of samples
600 in the pixel is not the expected <a
601 href='#samples-per-pixel'><tt>SAMPLES-PER-PIXEL</tt></a> for the given
602 PNG.
603 </blockquote>
606 <a name='sect-references'><h3>References</h3></a>
608 <ul>
610 <li> W3C, <a href="http://www.w3.org/TR/PNG/">Portable Network
611 Graphics Specification, Second Edition</a>
613 <li>
614 Wikipedia, <a href='http://en.wikipedia.org/wiki/Mandelbrot_set'>Mandelbrot
615 set</a>
617 </ul>
620 <a name='sect-acknowledgements'><h3>Acknowledgements</h3></a>
622 <p>Thanks to Patrick Stein for implementing pixel-at-a-time streamed
623 output.
626 <a name='sect-feedback'><h3>Feedback</h3></a>
628 <p>Please direct any questions, comments, bug reports, or other
629 feedback to <a href='mailto:xach@xach.com'>Zach Beane</a>.