bool rpng_nbio_load_image_argb_iterate(uint8_t *buf, struct rpng_t *rpng, unsigned *ret) { unsigned i; struct png_chunk chunk = {0}; if (!read_chunk_header(buf, &chunk)) return false; #if 0 for (i = 0; i < 4; i++) { fprintf(stderr, "chunktype: %c\n", chunk.type[i]); } #endif switch (png_chunk_type(&chunk)) { case PNG_CHUNK_NOOP: default: break; case PNG_CHUNK_ERROR: goto error; case PNG_CHUNK_IHDR: if (rpng->has_ihdr || rpng->has_idat || rpng->has_iend) goto error; if (chunk.size != 13) goto error; if (!png_parse_ihdr(buf, &rpng->ihdr)) goto error; if (!png_process_ihdr(&rpng->ihdr)) goto error; rpng->has_ihdr = true; break; case PNG_CHUNK_PLTE: { unsigned entries = chunk.size / 3; if (!rpng->has_ihdr || rpng->has_plte || rpng->has_iend || rpng->has_idat) goto error; if (chunk.size % 3) goto error; if (!png_read_plte_into_buf(buf, rpng->palette, entries)) goto error; rpng->has_plte = true; } break; case PNG_CHUNK_IDAT: if (!(rpng->has_ihdr) || rpng->has_iend || (rpng->ihdr.color_type == PNG_IHDR_COLOR_PLT && !(rpng->has_plte))) goto error; if (!png_realloc_idat(&chunk, &rpng->idat_buf)) goto error; buf += 8; for (i = 0; i < chunk.size; i++) rpng->idat_buf.data[i + rpng->idat_buf.size] = buf[i]; rpng->idat_buf.size += chunk.size; rpng->has_idat = true; break; case PNG_CHUNK_IEND: if (!(rpng->has_ihdr) || !(rpng->has_idat)) goto error; rpng->has_iend = true; goto error; } *ret = 4 + 4 + chunk.size + 4; return true; error: return false; }
bool rpng_load_image_argb(const char *path, uint32_t **data, unsigned *width, unsigned *height) { long pos; *data = NULL; *width = 0; *height = 0; bool ret = true; FILE *file = fopen(path, "rb"); if (!file) return false; fseek(file, 0, SEEK_END); long file_len = ftell(file); rewind(file); bool has_ihdr = false; bool has_idat = false; bool has_iend = false; bool has_plte = false; uint8_t *inflate_buf = NULL; size_t inflate_buf_size = 0; z_stream stream = {0}; struct idat_buffer idat_buf = {0}; struct png_ihdr ihdr = {0}; uint32_t palette[256] = {0}; char header[8]; if (fread(header, 1, sizeof(header), file) != sizeof(header)) GOTO_END_ERROR(); if (memcmp(header, png_magic, sizeof(png_magic)) != 0) GOTO_END_ERROR(); // feof() apparently isn't triggered after a seek (IEND). for (pos = ftell(file); pos < file_len && pos >= 0; pos = ftell(file)) { struct png_chunk chunk = {0}; if (!read_chunk_header(file, &chunk)) GOTO_END_ERROR(); switch (png_chunk_type(&chunk)) { case PNG_CHUNK_NOOP: default: if (fseek(file, chunk.size + sizeof(uint32_t), SEEK_CUR) < 0) GOTO_END_ERROR(); break; case PNG_CHUNK_ERROR: GOTO_END_ERROR(); case PNG_CHUNK_IHDR: if (has_ihdr || has_idat || has_iend) GOTO_END_ERROR(); if (!png_parse_ihdr(file, &chunk, &ihdr)) GOTO_END_ERROR(); has_ihdr = true; break; case PNG_CHUNK_PLTE: if (!has_ihdr || has_plte || has_iend || has_idat) GOTO_END_ERROR(); if (chunk.size % 3) GOTO_END_ERROR(); if (!png_read_plte(file, palette, chunk.size / 3)) GOTO_END_ERROR(); has_plte = true; break; case PNG_CHUNK_IDAT: if (!has_ihdr || has_iend || (ihdr.color_type == 3 && !has_plte)) GOTO_END_ERROR(); if (!png_append_idat(file, &chunk, &idat_buf)) GOTO_END_ERROR(); has_idat = true; break; case PNG_CHUNK_IEND: if (!has_ihdr || !has_idat) GOTO_END_ERROR(); if (fseek(file, sizeof(uint32_t), SEEK_CUR) < 0) GOTO_END_ERROR(); has_iend = true; break; } } if (!has_ihdr || !has_idat || !has_iend) GOTO_END_ERROR(); if (inflateInit(&stream) != Z_OK) GOTO_END_ERROR(); png_pass_geom(&ihdr, ihdr.width, ihdr.height, NULL, NULL, &inflate_buf_size); if (ihdr.interlace == 1) // To be sure. inflate_buf_size *= 2; inflate_buf = (uint8_t*)malloc(inflate_buf_size); if (!inflate_buf) GOTO_END_ERROR(); stream.next_in = idat_buf.data; stream.avail_in = idat_buf.size; stream.avail_out = inflate_buf_size; stream.next_out = inflate_buf; if (inflate(&stream, Z_FINISH) != Z_STREAM_END) { inflateEnd(&stream); GOTO_END_ERROR(); } inflateEnd(&stream); *width = ihdr.width; *height = ihdr.height; *data = (uint32_t*)malloc(ihdr.width * ihdr.height * sizeof(uint32_t)); if (!*data) GOTO_END_ERROR(); if (ihdr.interlace == 1) { if (!png_reverse_filter_adam7(*data, &ihdr, inflate_buf, stream.total_out, palette)) GOTO_END_ERROR(); } else if (!png_reverse_filter(*data, &ihdr, inflate_buf, stream.total_out, palette)) GOTO_END_ERROR(); end: if (file) fclose(file); if (!ret) free(*data); free(idat_buf.data); free(inflate_buf); return ret; }
bool rpng_nbio_load_image_argb_iterate(uint8_t *buf, struct rpng_t *rpng) { unsigned i; rpng->chunk.size = 0; rpng->chunk.type[0] = '\0'; if (!read_chunk_header(buf, &rpng->chunk)) return false; #if 0 for (i = 0; i < 4; i++) { fprintf(stderr, "chunktype: %c\n", chunk.type[i]); } #endif switch (png_chunk_type(&rpng->chunk)) { case PNG_CHUNK_NOOP: default: break; case PNG_CHUNK_ERROR: return false; case PNG_CHUNK_IHDR: if (rpng->has_ihdr || rpng->has_idat || rpng->has_iend) return false; if (rpng->chunk.size != 13) return false; if (!png_parse_ihdr(buf, &rpng->ihdr)) return false; rpng->has_ihdr = true; break; case PNG_CHUNK_PLTE: { unsigned entries = rpng->chunk.size / 3; if (!rpng->has_ihdr || rpng->has_plte || rpng->has_iend || rpng->has_idat) return false; if (rpng->chunk.size % 3) return false; if (!png_read_plte_into_buf(buf, rpng->palette, entries)) return false; rpng->has_plte = true; } break; case PNG_CHUNK_IDAT: if (!(rpng->has_ihdr) || rpng->has_iend || (rpng->ihdr.color_type == 3 && !(rpng->has_plte))) return false; if (!png_realloc_idat(&rpng->chunk, &rpng->idat_buf)) return false; buf += 8; for (i = 0; i < rpng->chunk.size; i++) rpng->idat_buf.data[i + rpng->idat_buf.size] = buf[i]; rpng->idat_buf.size += rpng->chunk.size; rpng->has_idat = true; break; case PNG_CHUNK_IEND: if (!(rpng->has_ihdr) || !(rpng->has_idat)) return false; rpng->has_iend = true; return false; } return true; }
static bool rpng_load_image_argb_iterate(FILE **fd, rpng_t *rpng) { struct png_chunk chunk = {0}; FILE *file = *fd; if (!read_chunk_header_fio(fd, &chunk)) return false; switch (png_chunk_type(&chunk)) { case PNG_CHUNK_NOOP: default: if (fseek(file, chunk.size + sizeof(uint32_t), SEEK_CUR) < 0) return false; break; case PNG_CHUNK_ERROR: return false; case PNG_CHUNK_IHDR: if (rpng_is_valid(rpng)) return false; if (!png_parse_ihdr_fio(fd, &chunk, &rpng->ihdr)) { png_free_chunk(&chunk); return false; } if (!png_process_ihdr(&rpng->ihdr)) { png_free_chunk(&chunk); return false; } png_free_chunk(&chunk); rpng->has_ihdr = true; break; case PNG_CHUNK_PLTE: { uint8_t buf[256 * 3]; unsigned entries = chunk.size / 3; if (!rpng->has_ihdr || rpng->has_plte || rpng->has_iend || rpng->has_idat) return false; if (chunk.size % 3) return false; if (entries > 256) return false; if (fread(rpng->palette, 3, entries, *fd) != entries) return false; if (!png_read_plte(&buf[0], rpng->palette, entries)) return false; if (fseek(*fd, sizeof(uint32_t), SEEK_CUR) < 0) return false; rpng->has_plte = true; } break; case PNG_CHUNK_IDAT: if (!rpng->has_ihdr || rpng->has_iend || (rpng->ihdr.color_type == PNG_IHDR_COLOR_PLT && !rpng->has_plte)) return false; if (!png_realloc_idat(&chunk, &rpng->idat_buf)) return false; if (fread(rpng->idat_buf.data + rpng->idat_buf.size, 1, chunk.size, file) != chunk.size) return false; if (fseek(file, sizeof(uint32_t), SEEK_CUR) < 0) return false; rpng->idat_buf.size += chunk.size; rpng->has_idat = true; break; case PNG_CHUNK_IEND: if (!rpng->has_ihdr || !rpng->has_idat) return false; if (fseek(file, sizeof(uint32_t), SEEK_CUR) < 0) return false; rpng->has_iend = true; break; } return true; }
bool rpng_iterate_image(rpng_t *rpng) { unsigned i; struct png_chunk chunk = {0}; uint8_t *buf = (uint8_t*)rpng->buff_data; if (!read_chunk_header(buf, &chunk)) return false; *buf += 8; #if 0 for (i = 0; i < 4; i++) { fprintf(stderr, "chunktype: %c\n", chunk.type[i]); } #endif switch (png_chunk_type(&chunk)) { case PNG_CHUNK_NOOP: default: break; case PNG_CHUNK_ERROR: goto error; case PNG_CHUNK_IHDR: if (rpng->has_ihdr || rpng->has_idat || rpng->has_iend) goto error; if (chunk.size != 13) goto error; if (!png_parse_ihdr(buf, &rpng->ihdr)) goto error; if (!png_process_ihdr(&rpng->ihdr)) goto error; rpng->has_ihdr = true; break; case PNG_CHUNK_PLTE: { unsigned entries = chunk.size / 3; if (!rpng->has_ihdr || rpng->has_plte || rpng->has_iend || rpng->has_idat || rpng->has_trns) goto error; if (chunk.size % 3) goto error; if (entries > 256) goto error; buf += 8; if (!png_read_plte(buf, rpng->palette, entries)) goto error; rpng->has_plte = true; } break; case PNG_CHUNK_tRNS: { unsigned entries = chunk.size / 3; if (rpng->has_idat) goto error; if (rpng->ihdr.color_type == PNG_IHDR_COLOR_PLT) { /* we should compare with the number of palette entries */ if (chunk.size > 256) goto error; if (!png_read_trns(buf, rpng->palette, chunk.size)) goto error; } /* TODO: support colorkey in grayscale and truecolor images */ rpng->has_trns = true; } break; case PNG_CHUNK_IDAT: if (!(rpng->has_ihdr) || rpng->has_iend || (rpng->ihdr.color_type == PNG_IHDR_COLOR_PLT && !(rpng->has_plte))) goto error; if (!png_realloc_idat(&chunk, &rpng->idat_buf)) goto error; buf += 8; for (i = 0; i < chunk.size; i++) rpng->idat_buf.data[i + rpng->idat_buf.size] = buf[i]; rpng->idat_buf.size += chunk.size; rpng->has_idat = true; break; case PNG_CHUNK_IEND: if (!(rpng->has_ihdr) || !(rpng->has_idat)) goto error; rpng->has_iend = true; goto error; } rpng->buff_data += chunk.size + 12; return true; error: return false; }