Example #1
0
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;
}
Example #2
0
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;
}
Example #3
0
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;
}
Example #4
0
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;
}
Example #5
0
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;
}