Bug Summary

File:src/nrrd/formatPNG.c
Location:line 573, column 3
Description:Value stored to 'row' is never read

Annotated Source Code

1/*
2 Teem: Tools to process and visualize scientific data and images .
3 Copyright (C) 2013, 2012, 2011, 2010, 2009 University of Chicago
4 Copyright (C) 2008, 2007, 2006, 2005 Gordon Kindlmann
5 Copyright (C) 2004, 2003, 2002, 2001, 2000, 1999, 1998 University of Utah
6
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public License
9 (LGPL) as published by the Free Software Foundation; either
10 version 2.1 of the License, or (at your option) any later version.
11 The terms of redistributing and/or modifying this software also
12 include exceptions to the LGPL that facilitate static linking.
13
14 This library is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Lesser General Public License for more details.
18
19 You should have received a copy of the GNU Lesser General Public License
20 along with this library; if not, write to Free Software Foundation, Inc.,
21 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22*/
23
24#include "nrrd.h"
25#include "privateNrrd.h"
26
27#include <teemPng.h>
28#if TEEM_PNG1
29#include <png.h>
30#endif
31
32#define MAGIC"\211PNG" "\211PNG"
33
34static int
35_nrrdFormatPNG_available(void) {
36
37#if TEEM_PNG1
38 return AIR_TRUE1;
39#else
40 return AIR_FALSE0;
41#endif
42}
43
44static int
45_nrrdFormatPNG_nameLooksLike(const char *filename) {
46
47 return airEndsWith(filename, NRRD_EXT_PNG".png");
48}
49
50static int
51_nrrdFormatPNG_fitsInto(const Nrrd *nrrd, const NrrdEncoding *encoding,
52 int useBiff) {
53 static const char me[]="_nrrdFormatPNG_fitsInto";
54
55#if !TEEM_PNG1 /* ------------------------------------------- */
56
57 AIR_UNUSED(nrrd)(void)(nrrd);
58 AIR_UNUSED(encoding)(void)(encoding);
59 biffMaybeAddf(useBiff, NRRDnrrdBiffKey,
60 "%s: %s format not available in this Teem build",
61 me, nrrdFormatPNG->name);
62 return AIR_FALSE0;
63
64#else /* ------------------------------------------- */
65
66 int ret;
67
68 if (!( nrrd && encoding )) {
69 biffMaybeAddf(useBiff, NRRDnrrdBiffKey, "%s: got NULL nrrd (%p) or encoding (%p)",
70 me, AIR_CVOIDP(nrrd)((const void *)(nrrd)), AIR_CVOIDP(encoding)((const void *)(encoding)));
71 return AIR_FALSE0;
72 }
73 if (!( nrrdTypeUChar == nrrd->type || nrrdTypeUShort == nrrd->type )) {
74 biffMaybeAddf(useBiff, NRRDnrrdBiffKey,
75 "%s: type must be %s or %s (not %s)", me,
76 airEnumStr(nrrdType, nrrdTypeUChar),
77 airEnumStr(nrrdType, nrrdTypeUShort),
78 airEnumStr(nrrdType, nrrd->type));
79 return AIR_FALSE0;
80 }
81 /* else */
82 /* encoding ignored- always gzip */
83 if (2 == nrrd->dim) {
84 /* its a gray-scale image */
85 ret = AIR_TRUE1;
86 } else if (3 == nrrd->dim) {
87 if (!( 1 == nrrd->axis[0].size
88 || 2 == nrrd->axis[0].size
89 || 3 == nrrd->axis[0].size
90 || 4 == nrrd->axis[0].size )) {
91 char stmp[AIR_STRLEN_SMALL(128+1)];
92 biffMaybeAddf(useBiff, NRRDnrrdBiffKey,
93 "%s: 1st axis size is %s, not 1, 2, 3, or 4", me,
94 airSprintSize_t(stmp, nrrd->axis[0].size));
95 return AIR_FALSE0;
96 }
97 /* else */
98 ret = AIR_TRUE1;
99 } else {
100 biffMaybeAddf(useBiff, NRRDnrrdBiffKey,
101 "%s: dimension is %d, not 2 or 3", me, nrrd->dim);
102 return AIR_FALSE0;
103 }
104 return ret;
105
106#endif /* ------------------------------------------- */
107}
108
109static int
110_nrrdFormatPNG_contentStartsLike(NrrdIoState *nio) {
111
112 return !strcmp(MAGIC"\211PNG", nio->line);
113}
114
115#if TEEM_PNG1
116static void
117_nrrdErrorHandlerPNG (png_structp png, png_const_charp message)
118{
119 static const char me[]="_nrrdErrorHandlerPNG";
120 /* add PNG error message to biff */
121 biffAddf(NRRDnrrdBiffKey, "%s: PNG error: %s", me, message);
122 /* longjmp back to the setjmp, return 1 */
123 longjmp(png_jmpbuf(png)(*png_set_longjmp_fn((png), longjmp, (sizeof (jmp_buf)))), 1);
124}
125
126static void
127_nrrdWarningHandlerPNG (png_structp png, png_const_charp message)
128{
129 static const char me[]="_nrrdWarningHandlerPNG";
130 AIR_UNUSED(png)(void)(png);
131 /* add the png warning message to biff */
132 biffAddf(NRRDnrrdBiffKey, "%s: PNG warning: %s", me, message);
133 /* no longjump, execution continues */
134}
135
136/* we need to use the file I/O callbacks on windows
137 to make sure we can mix VC6 libpng with VC7 Teem */
138#ifdef _WIN32
139static void
140_nrrdReadDataPNG (png_structp png, png_bytep data, png_size_t len)
141{
142 png_size_t read;
143 read = (png_size_t)fread(data, (png_size_t)1, len, (FILE*)png_get_io_ptr(png));
144 if (read != len) png_error(png, "file read error");
145}
146static void
147_nrrdWriteDataPNG (png_structp png, png_bytep data, png_size_t len)
148{
149 png_size_t written;
150 written = fwrite(data, 1, len, (FILE*)png_get_io_ptr(png));
151 if (written != len) png_error(png, "file write error");
152}
153
154static void
155_nrrdFlushDataPNG (png_structp png)
156{
157 FILE *io_ptr = png_get_io_ptr(png);
158 if (io_ptr != NULL((void*)0)) fflush(io_ptr);
159}
160#endif /* _WIN32 */
161#endif /* TEEM_PNG */
162
163static int
164_nrrdFormatPNG_read(FILE *file, Nrrd *nrrd, NrrdIoState *nio) {
165 static const char me[]="_nrrdFormatPNG_read";
166#if TEEM_PNG1
167 png_structp png;
168 png_infop info;
169 png_bytep *row;
170 png_uint_32 width, height, rowsize, hi;
171 png_text* txt;
172 int depth, type, i, channels, numtxt, ret;
173 int ntype, ndim;
174 size_t nsize[3];
175#endif /* TEEM_PNG */
176
177 AIR_UNUSED(file)(void)(file);
178 AIR_UNUSED(nrrd)(void)(nrrd);
179 if (!_nrrdFormatPNG_contentStartsLike(nio)) {
180 biffAddf(NRRDnrrdBiffKey, "%s: this doesn't look like a %s file", me,
181 nrrdFormatPNG->name);
182 return 1;
183 }
184
185#if TEEM_PNG1
186 /* create png struct with the error handlers above */
187 png = png_create_read_struct(PNG_LIBPNG_VER_STRING"1.6.29", NULL((void*)0),
188 _nrrdErrorHandlerPNG,
189 _nrrdWarningHandlerPNG);
190 if (png == NULL((void*)0)) {
191 biffAddf(NRRDnrrdBiffKey, "%s: failed to create PNG read struct", me);
192 return 1;
193 }
194 /* create image info struct */
195 info = png_create_info_struct(png);
196 if (info == NULL((void*)0)) {
197 png_destroy_read_struct(&png, NULL((void*)0), NULL((void*)0));
198 biffAddf(NRRDnrrdBiffKey, "%s: failed to create PNG image info struct", me);
199 return 1;
200 }
201 /* set up png style error handling */
202 if (setjmp(png_jmpbuf(png)(*png_set_longjmp_fn((png), longjmp, (sizeof (jmp_buf)))))) {
203 /* the error is reported inside the handler,
204 but we still need to clean up and return */
205 png_destroy_read_struct(&png, &info, NULL((void*)0));
206 return 1;
207 }
208 /* initialize png I/O */
209#ifdef _WIN32
210 png_set_read_fn(png, (png_voidp)file, _nrrdReadDataPNG);
211#else
212 png_init_io(png, file);
213#endif
214 /* if we are here, we have already read 6 bytes from the file */
215 png_set_sig_bytes(png, 6);
216 /* png_read_info() returns all information from the file
217 before the first data chunk */
218 png_read_info(png, info);
219 png_get_IHDR(png, info, &width, &height, &depth, &type,
220 NULL((void*)0), NULL((void*)0), NULL((void*)0));
221 /* expand paletted colors into rgb triplets */
222 if (type == PNG_COLOR_TYPE_PALETTE(2 | 1))
223 png_set_palette_to_rgb(png);
224 /* expand grayscale images to 8 bits from 1, 2, or 4 bits */
225 if (type == PNG_COLOR_TYPE_GRAY0 && depth < 8)
226#if PNG_LIBPNG_VER_MINOR6 > 1
227 png_set_expand_gray_1_2_4_to_8(png);
228#else
229 png_set_expand(png);
230#endif
231 /* expand paletted or rgb images with transparency to full alpha
232 channels so the data will be available as rgba quartets */
233 if (png_get_valid(png, info, PNG_INFO_tRNS0x0010U))
234 png_set_tRNS_to_alpha(png);
235 /* fix endianness for 16 bit formats */
236 if (depth > 8 && airMyEndian() == airEndianLittle)
237 png_set_swap(png);
238#if 0
239 /* HEY GLK asks why is this commented out? */
240 /* set up gamma correction */
241 /* NOTE: screen_gamma is platform dependent,
242 it can hardwired or set from a parameter/environment variable */
243 if (png_get_sRGB(png_ptr, info_ptr, &intent)) {
244 /* if the image has sRGB info,
245 pass in standard nrrd file gamma 1.0 */
246 png_set_gamma(png_ptr, screen_gamma, 1.0);
247 } else {
248 double gamma;
249 /* set image gamma if present */
250 if (png_get_gAMA(png, info, &gamma))
251 png_set_gamma(png, screen_gamma, gamma);
252 else
253 png_set_gamma(png, screen_gamma, 1.0);
254 }
255#endif
256 /* update reader */
257 png_read_update_info(png, info);
258 /* allocate memory for the image data */
259 ntype = depth > 8 ? nrrdTypeUShort : nrrdTypeUChar;
260 switch (type) {
261 case PNG_COLOR_TYPE_GRAY0:
262 ndim = 2; nsize[0] = width; nsize[1] = height;
263 nsize[2] = 1; /* to simplify code below */
264 break;
265 case PNG_COLOR_TYPE_GRAY_ALPHA(4):
266 ndim = 3; nsize[0] = 2; nsize[1] = width; nsize[2] = height;
267 break;
268 case PNG_COLOR_TYPE_RGB(2):
269 ndim = 3; nsize[0] = 3; nsize[1] = width; nsize[2] = height;
270 break;
271 case PNG_COLOR_TYPE_RGB_ALPHA(2 | 4):
272 ndim = 3; nsize[0] = 4; nsize[1] = width; nsize[2] = height;
273 break;
274 case PNG_COLOR_TYPE_PALETTE(2 | 1):
275 /* TODO: merge this with the outer switch, needs to be tested */
276 channels = png_get_channels(png, info);
277 if (channels < 2) {
278 ndim = 2; nsize[0] = width; nsize[1] = height;
279 } else {
280 ndim = 3; nsize[0] = channels; nsize[1] = width; nsize[2] = height;
281 }
282 break;
283 default:
284 png_destroy_read_struct(&png, &info, NULL((void*)0));
285 biffAddf(NRRDnrrdBiffKey, "%s: unknown png type: %d", me, type);
286 return 1;
287 break;
288 }
289 if (nio->oldData
290 && (nio->oldDataSize
291 == (size_t)(nrrdTypeSize[ntype]*nsize[0]*nsize[1]*nsize[2]))) {
292 ret = nrrdWrap_nva(nrrd, nio->oldData, ntype, ndim, nsize);
293 } else {
294 ret = nrrdMaybeAlloc_nva(nrrd, ntype, ndim, nsize);
295 }
296 if (ret) {
297 png_destroy_read_struct(&png, &info, NULL((void*)0));
298 biffAddf(NRRDnrrdBiffKey, "%s: failed to allocate nrrd", me);
299 return 1;
300 }
301 /* query row size */
302 rowsize = png_get_rowbytes(png, info);
303 /* check byte size */
304 if (nrrdElementNumber(nrrd)*nrrdElementSize(nrrd) != height*rowsize) {
305 png_destroy_read_struct(&png, &info, NULL((void*)0));
306 biffAddf(NRRDnrrdBiffKey, "%s: size mismatch", me);
307 return 1;
308 }
309 /* set up row pointers */
310 row = (png_bytep*)malloc(sizeof(png_bytep)*height);
311 for (hi=0; hi<height; hi++) {
312 row[hi] = &((png_bytep)nrrd->data)[hi*rowsize];
313 }
314 /* read the entire image in one pass */
315 png_read_image(png, row);
316 /* read all text fields from the text chunk */
317 numtxt = png_get_text(png, info, &txt, NULL((void*)0));
318 for (i=0; i<numtxt; i++) {
319 if (!strcmp(txt[i].key, NRRD_PNG_FIELD_KEY"NRRD")) {
320 nio->pos = 0;
321 /* Reading PNGs teaches Gordon that his scheme for parsing nrrd header
322 information is inappropriately specific to reading PNMs and NRRDs,
323 since in this case the text from which we parse a nrrd field
324 descriptor did NOT come from a line of text as read by
325 _nrrdOneLine */
326 nio->line = (char *)airFree(nio->line);
327 nio->line = airStrdup(txt[i].text);
328 ret = _nrrdReadNrrdParseField(nio, AIR_FALSE0);
329 if (ret) {
330 const char* fs = airEnumStr(nrrdField, ret);
331 if (nrrdField_comment == ret) {
332 ret = 0;
333 goto plain;
334 }
335 if (!_nrrdFieldValidInImage[ret]) {
336 if (1 <= nrrdStateVerboseIO) {
337 fprintf(stderr__stderrp, "(%s: field \"%s\" (not allowed in PNG) "
338 "--> plain comment)\n", me, fs);
339 }
340 ret = 0;
341 goto plain;
342 }
343 if (!nio->seen[ret]
344 && nrrdFieldInfoParse[ret](file, nrrd, nio, AIR_FALSE0)) {
345 if (1 <= nrrdStateVerboseIO) {
346 fprintf(stderr__stderrp, "(%s: unparsable info \"%s\" for field \"%s\" "
347 "--> plain comment)\n", me, nio->line + nio->pos, fs);
348 }
349 ret = 0;
350 goto plain;
351 }
352 nio->seen[ret] = AIR_TRUE1;
353 plain:
354 if (!ret) {
355 if (nrrdCommentAdd(nrrd, nio->line)) {
356 png_destroy_read_struct(&png, &info, NULL((void*)0));
357 biffAddf(NRRDnrrdBiffKey, "%s: couldn't add comment", me);
358 return 1;
359 }
360 }
361 }
362 } else if (!strcmp(txt[i].key, NRRD_PNG_COMMENT_KEY"NRRD#")) {
363 char *p, *c;
364 c = airStrtok(txt[i].text, "\n", &p);
365 while (c) {
366 if (nrrdCommentAdd(nrrd, c)) {
367 png_destroy_read_struct(&png, &info, NULL((void*)0));
368 biffAddf(NRRDnrrdBiffKey, "%s: couldn't add comment", me);
369 return 1;
370 }
371 c = airStrtok(NULL((void*)0), "\n", &p);
372 }
373 } else {
374 if (nrrdKeyValueAdd(nrrd, txt[i].key, txt[i].text)) {
375 png_destroy_read_struct(&png, &info, NULL((void*)0));
376 biffAddf(NRRDnrrdBiffKey, "%s: couldn't add key/value pair", me);
377 return 1;
378 }
379 }
380 }
381 /* finish reading */
382 png_read_end(png, info);
383 /* clean up */
384 row = (png_byte**)airFree(row);
385 png_destroy_read_struct(&png, &info, NULL((void*)0));
386
387 return 0;
388#else
389 biffAddf(NRRDnrrdBiffKey, "%s: Sorry, this nrrd not compiled with PNG enabled", me);
390 return 1;
391#endif
392}
393
394static int
395_nrrdFormatPNG_write(FILE *file, const Nrrd *nrrd, NrrdIoState *nio) {
396 static const char me[]="_nrrdFormatPNG_write";
397#if TEEM_PNG1
398 int fi, depth, type, csize;
399 unsigned int jj, numtxt, txtidx;
400 png_structp png;
401 png_infop info;
402 png_bytep *row;
403 png_uint_32 width, height, rowsize, hi;
404 png_text *txt;
405 char *key, *value;
406
407 /* no need to check type and format, done in FitsInFormat */
408 /* create png struct with the error handlers above */
409 png = png_create_write_struct(PNG_LIBPNG_VER_STRING"1.6.29", NULL((void*)0),
410 _nrrdErrorHandlerPNG,
411 _nrrdWarningHandlerPNG);
412 if (png == NULL((void*)0)) {
413 biffAddf(NRRDnrrdBiffKey, "%s: failed to create PNG write struct (compiled with "
414 "PNG_LIBPNG_VER_STRING=" PNG_LIBPNG_VER_STRING"1.6.29" ")", me);
415 return 1;
416 }
417 /* create image info struct */
418 info = png_create_info_struct(png);
419 if (info == NULL((void*)0)) {
420 png_destroy_write_struct(&png, NULL((void*)0));
421 biffAddf(NRRDnrrdBiffKey, "%s: failed to create PNG image info struct", me);
422 return 1;
423 }
424 /* set up error png style error handling */
425 if (setjmp(png_jmpbuf(png)(*png_set_longjmp_fn((png), longjmp, (sizeof (jmp_buf))))))
426 {
427 /* the error is reported inside the error handler,
428 but we still need to clean up an return with an error */
429 png_destroy_write_struct(&png, &info);
430 return 1;
431 }
432 /* initialize png I/O */
433#ifdef _WIN32
434 png_set_write_fn(png, file, _nrrdWriteDataPNG, _nrrdFlushDataPNG);
435#else
436 png_init_io(png, file);
437#endif
438 /* calculate depth, width, height, and row size */
439 depth = nrrd->type == nrrdTypeUChar ? 8 : 16;
440 switch (nrrd->dim) {
441 char stmp[AIR_STRLEN_SMALL(128+1)];
442 case 2: /* g only */
443 width = nrrd->axis[0].size;
444 height = nrrd->axis[1].size;
445 type = PNG_COLOR_TYPE_GRAY0;
446 rowsize = width*nrrdElementSize(nrrd);
447 break;
448 case 3: /* g, ga, rgb, rgba */
449 width = nrrd->axis[1].size;
450 height = nrrd->axis[2].size;
451 rowsize = width*nrrd->axis[0].size*nrrdElementSize(nrrd);
452 switch (nrrd->axis[0].size) {
453 case 1:
454 type = PNG_COLOR_TYPE_GRAY0;
455 break;
456 case 2:
457 type = PNG_COLOR_TYPE_GRAY_ALPHA(4);
458 break;
459 case 3:
460 type = PNG_COLOR_TYPE_RGB(2);
461 break;
462 case 4:
463 type = PNG_COLOR_TYPE_RGB_ALPHA(2 | 4);
464 break;
465 default:
466 png_destroy_write_struct(&png, &info);
467 biffAddf(NRRDnrrdBiffKey, "%s: nrrd->axis[0].size (%s) not compatible with PNG", me,
468 airSprintSize_t(stmp, nrrd->axis[0].size));
469 return 1;
470 break;
471 }
472 break;
473 default:
474 png_destroy_write_struct(&png, &info);
475 biffAddf(NRRDnrrdBiffKey, "%s: dimension (%d) not compatible with PNG",
476 me, nrrd->dim);
477 return 1;
478 break;
479 }
480 /* set image header info */
481 png_set_IHDR(png, info, width, height, depth, type,
482 PNG_INTERLACE_NONE0, PNG_COMPRESSION_TYPE_BASE0,
483 PNG_FILTER_TYPE_BASE0);
484 /* calculate numtxt and allocate txt[] array */
485 numtxt = 0;
486 for (fi=nrrdField_unknown+1; fi<nrrdField_last; fi++) {
487 if (_nrrdFieldValidInImage[fi] && _nrrdFieldInteresting(nrrd, nio, fi)) {
488 numtxt++;
489 }
490 }
491 for (jj=0; jj<nrrdKeyValueSize(nrrd); jj++) {
492 nrrdKeyValueIndex(nrrd, &key, &value, jj);
493 /* HEY: why is the NULL check needed?? */
494 if (NULL((void*)0) != key && NULL((void*)0) != value) {
495 numtxt++;
496 }
497 free(key);
498 free(value);
499 key = NULL((void*)0);
500 value = NULL((void*)0);
501 }
502 if (nrrd->cmtArr->len > 0) {
503 /* all comments are put into single text field */
504 numtxt += 1;
505 }
506 if (0 == numtxt) {
507 txt = NULL((void*)0);
508 } else {
509 txt = AIR_CAST(png_text *, calloc(numtxt, sizeof(png_text)))((png_text *)(calloc(numtxt, sizeof(png_text))));
510 /* add nrrd fields to the text chunk */
511 csize = 0;
512 txtidx = 0;
513 for (fi=nrrdField_unknown+1; fi<nrrdField_last; fi++) {
514 if (_nrrdFieldValidInImage[fi] && _nrrdFieldInteresting(nrrd, nio, fi)) {
515 txt[txtidx].key = airStrdup(NRRD_PNG_FIELD_KEY"NRRD");
516 txt[txtidx].compression = PNG_TEXT_COMPRESSION_NONE-1;
517 _nrrdSprintFieldInfo(&(txt[txtidx].text), "", nrrd, nio, fi,
518 (3 == nrrd->dim && 1 == nrrd->axis[0].size));
519 txtidx++;
520 }
521 }
522 /* add nrrd key/value pairs to the chunk */
523 for (jj=0; jj<nrrdKeyValueSize(nrrd); jj++) {
524 nrrdKeyValueIndex(nrrd, &key, &value, jj);
525 if (NULL((void*)0) != key && NULL((void*)0) != value) {
526 txt[txtidx].key = key;
527 txt[txtidx].text = value;
528 txt[txtidx].compression = PNG_TEXT_COMPRESSION_NONE-1;
529 txtidx++;
530 }
531 }
532 /* add nrrd comments as a single text field */
533 if (nrrd->cmtArr->len > 0) {
534 txt[txtidx].key = airStrdup(NRRD_PNG_COMMENT_KEY"NRRD#");
535 txt[txtidx].compression = PNG_TEXT_COMPRESSION_NONE-1;
536 for (jj=0; jj<nrrd->cmtArr->len; jj++) {
537 csize += airStrlen(nrrd->cmt[jj]) + 1;
538 }
539 txt[txtidx].text = (png_charp)malloc(csize + 1);
540 txt[txtidx].text[0] = 0;
541 for (jj=0; jj<nrrd->cmtArr->len; jj++) {
542 strcat(txt[txtidx].text, nrrd->cmt[jj])__builtin___strcat_chk (txt[txtidx].text, nrrd->cmt[jj], __builtin_object_size
(txt[txtidx].text, 2 > 1 ? 1 : 0))
;
543 strcat(txt[txtidx].text, "\n")__builtin___strcat_chk (txt[txtidx].text, "\n", __builtin_object_size
(txt[txtidx].text, 2 > 1 ? 1 : 0))
;
544 }
545 txtidx++;
546 }
547 png_set_text(png, info, txt, numtxt);
548 }
549 /* write header */
550 png_write_info(png, info);
551 /* fix endianness for 16 bit formats */
552 if (depth > 8 && airMyEndian() == airEndianLittle) {
553 png_set_swap(png);
554 }
555 /* set up row pointers */
556 row = (png_bytep*)malloc(sizeof(png_bytep)*height);
557 for (hi=0; hi<height; hi++) {
558 row[hi] = &((png_bytep)nrrd->data)[hi*rowsize];
559 }
560 png_set_rows(png, info, row);
561 /* write the entire image in one pass */
562 png_write_image(png, row);
563 /* finish writing */
564 png_write_end(png, info);
565 /* clean up */
566 if (txt) {
567 for (jj=0; jj<numtxt; jj++) {
568 txt[jj].key = (char *)airFree(txt[jj].key);
569 txt[jj].text = (char *)airFree(txt[jj].text);
570 }
571 free(txt);
572 }
573 row = (png_byte**)airFree(row);
Value stored to 'row' is never read
574 png_destroy_write_struct(&png, &info);
575
576 return 0;
577#else
578 AIR_UNUSED(file)(void)(file);
579 AIR_UNUSED(nrrd)(void)(nrrd);
580 AIR_UNUSED(nio)(void)(nio);
581 biffAddf(NRRDnrrdBiffKey, "%s: Sorry, this nrrd not compiled with PNG enabled", me);
582 return 1;
583#endif
584}
585
586const NrrdFormat
587_nrrdFormatPNG = {
588 "PNG",
589 AIR_TRUE1, /* isImage */
590 AIR_TRUE1, /* readable */
591 AIR_FALSE0, /* usesDIO */
592 _nrrdFormatPNG_available,
593 _nrrdFormatPNG_nameLooksLike,
594 _nrrdFormatPNG_fitsInto,
595 _nrrdFormatPNG_contentStartsLike,
596 _nrrdFormatPNG_read,
597 _nrrdFormatPNG_write
598};
599
600const NrrdFormat *const
601nrrdFormatPNG = &_nrrdFormatPNG;