Пример #1
0
static bool png_parse_ihdr(FILE *file, struct png_chunk *chunk, struct png_ihdr *ihdr)
{
   unsigned i;
   bool ret = true;
   if (!png_read_chunk(file, chunk))
      return false;

   if (chunk->size != 13)
      GOTO_END_ERROR();

   ihdr->width       = dword_be(chunk->data + 0);
   ihdr->height      = dword_be(chunk->data + 4);
   ihdr->depth       = chunk->data[8];
   ihdr->color_type  = chunk->data[9];
   ihdr->compression = chunk->data[10];
   ihdr->filter      = chunk->data[11];
   ihdr->interlace   = chunk->data[12];

   if (ihdr->width == 0 || ihdr->height == 0)
      GOTO_END_ERROR();

   if (ihdr->color_type == 2 || ihdr->color_type == 4 || ihdr->color_type == 6)
   {
      if (ihdr->depth != 8 && ihdr->depth != 16)
         GOTO_END_ERROR();
   }
   else if (ihdr->color_type == 0)
   {
      static const unsigned valid_bpp[] = { 1, 2, 4, 8, 16 };
      bool correct_bpp = false;
      for (i = 0; i < ARRAY_SIZE(valid_bpp); i++)
      {
         if (valid_bpp[i] == ihdr->depth)
         {
            correct_bpp = true;
            break;
         }
      }

      if (!correct_bpp)
         GOTO_END_ERROR();
   }
   else if (ihdr->color_type == 3)
   {
      static const unsigned valid_bpp[] = { 1, 2, 4, 8 };
      bool correct_bpp = false;
      for (i = 0; i < ARRAY_SIZE(valid_bpp); i++)
      {
         if (valid_bpp[i] == ihdr->depth)
         {
            correct_bpp = true;
            break;
         }
      }

      if (!correct_bpp)
         GOTO_END_ERROR();
   }
   else
      GOTO_END_ERROR();

#ifdef RPNG_TEST
   fprintf(stderr, "IHDR: (%u x %u), bpc = %u, palette = %s, color = %s, alpha = %s, adam7 = %s.\n",
         ihdr->width, ihdr->height,
         ihdr->depth, ihdr->color_type == 3 ? "yes" : "no",
         ihdr->color_type & 2 ? "yes" : "no",
         ihdr->color_type & 4 ? "yes" : "no",
         ihdr->interlace == 1 ? "yes" : "no");
#endif

   if (ihdr->compression != 0)
      GOTO_END_ERROR();

   //if (ihdr->interlace != 0) // No Adam7 supported.
   //   GOTO_END_ERROR();

end:
   png_free_chunk(chunk);
   return ret;
}
Пример #2
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;
}