Esempio n. 1
0
int
image_gif_load(image *im)
{
  int x, y, ofs;
  GifRecordType RecordType;
  GifPixelType *line = NULL;
  int ExtFunction = 0;
  GifByteType *ExtData;
  SavedImage *sp;
  SavedImage temp_save;
  int BackGround = 0;
  int trans_index = 0; // transparent index if any
  ColorMapObject *ColorMap;
  GifColorType *ColorMapEntry;

  temp_save.ExtensionBlocks = NULL;
  temp_save.ExtensionBlockCount = 0;

  // If reusing the object a second time, start over
  if (im->used) {
    DEBUG_TRACE("Recreating giflib objects\n");
    image_gif_finish(im);

    if (im->fh != NULL) {
      // reset file to begining of image
      PerlIO_seek(im->fh, im->image_offset, SEEK_SET);
    }
    else {
      // reset SV read
      im->sv_offset = im->image_offset;
    }

    buffer_clear(im->buf);

    image_gif_read_header(im);
  }

  do {
    if (DGifGetRecordType(im->gif, &RecordType) == GIF_ERROR) {
      warn("Image::Scale unable to read GIF file (%s)\n", SvPVX(im->path));
      image_gif_finish(im);
      return 0;
    }

    switch (RecordType) {
      case IMAGE_DESC_RECORD_TYPE:
        if (DGifGetImageDesc(im->gif) == GIF_ERROR) {
          warn("Image::Scale unable to read GIF file (%s)\n", SvPVX(im->path));
          image_gif_finish(im);
          return 0;
        }

        sp = &im->gif->SavedImages[im->gif->ImageCount - 1];

        im->width  = sp->ImageDesc.Width;
        im->height = sp->ImageDesc.Height;

        BackGround = im->gif->SBackGroundColor; // XXX needed?
        ColorMap = im->gif->Image.ColorMap ? im->gif->Image.ColorMap : im->gif->SColorMap;

        if (ColorMap == NULL) {
          warn("Image::Scale GIF image has no colormap (%s)\n", SvPVX(im->path));
          image_gif_finish(im);
          return 0;
        }

        // Allocate storage for decompressed image
        image_alloc(im, im->width, im->height);

        New(0, line, im->width, GifPixelType);

        if (im->gif->Image.Interlace) {
          int i;
          for (i = 0; i < 4; i++) {
            for (x = InterlacedOffset[i]; x < im->height; x += InterlacedJumps[i]) {
              ofs = x * im->width;
              if (DGifGetLine(im->gif, line, 0) != GIF_OK) {
                warn("Image::Scale unable to read GIF file (%s)\n", SvPVX(im->path));
                image_gif_finish(im);
                return 0;
              }

              for (y = 0; y < im->width; y++) {
                ColorMapEntry = &ColorMap->Colors[line[y]];
                im->pixbuf[ofs++] = COL_FULL(
                  ColorMapEntry->Red,
                  ColorMapEntry->Green,
                  ColorMapEntry->Blue,
                  trans_index == line[y] ? 0 : 255
                );
              }
            }
          }
        }
        else {
          ofs = 0;
          for (x = 0; x < im->height; x++) {
            if (DGifGetLine(im->gif, line, 0) != GIF_OK) {
              warn("Image::Scale unable to read GIF file (%s)\n", SvPVX(im->path));
              image_gif_finish(im);
              return 0;
            }

            for (y = 0; y < im->width; y++) {
              ColorMapEntry = &ColorMap->Colors[line[y]];
              im->pixbuf[ofs++] = COL_FULL(
                ColorMapEntry->Red,
                ColorMapEntry->Green,
                ColorMapEntry->Blue,
                trans_index == line[y] ? 0 : 255
              );
            }
          }
        }

        Safefree(line);
        break;

      case EXTENSION_RECORD_TYPE:
        if (DGifGetExtension(im->gif, &ExtFunction, &ExtData) == GIF_ERROR) {
          warn("Image::Scale unable to read GIF file (%s)\n", SvPVX(im->path));
          image_gif_finish(im);
          return 0;
        }

        if (ExtFunction == 0xF9) { // transparency info
          if (ExtData[1] & 1)
            trans_index = ExtData[4];
          else
            trans_index = -1;
          im->has_alpha = 1;
          DEBUG_TRACE("GIF transparency index: %d\n", trans_index);
        }

        while (ExtData != NULL) {
          /* Create an extension block with our data */
#ifdef GIFLIB_API_50
          if (GifAddExtensionBlock(&im->gif->ExtensionBlockCount, &im->gif->ExtensionBlocks, ExtFunction, ExtData[0], &ExtData[1]) == GIF_ERROR) {
#else
          temp_save.Function = ExtFunction;
          if (AddExtensionBlock(&temp_save, ExtData[0], &ExtData[1]) == GIF_ERROR) {
#endif
#ifdef GIFLIB_API_41
            PrintGifError();
#endif
            warn("Image::Scale unable to read GIF file (%s)\n", SvPVX(im->path));
            image_gif_finish(im);
            return 0;
          }

          if (DGifGetExtensionNext(im->gif, &ExtData) == GIF_ERROR) {
#ifdef GIFLIB_API_41
            PrintGifError();
#endif
            warn("Image::Scale unable to read GIF file (%s)\n", SvPVX(im->path));
            image_gif_finish(im);
            return 0;
          }

          ExtFunction = 0; // CONTINUE_EXT_FUNC_CODE
        }
        break;

      case TERMINATE_RECORD_TYPE:
      default:
        break;
    }
  } while (RecordType != TERMINATE_RECORD_TYPE);

  return 1;
}

void
image_gif_finish(image *im)
{
  if (im->gif != NULL) {
#ifdef GIFLIB_API_51
    if (DGifCloseFile(im->gif, NULL) != GIF_OK) {
#else
    if (DGifCloseFile(im->gif) != GIF_OK) {
#endif
#ifdef GIFLIB_API_41
      PrintGifError();
#endif
      warn("Image::Scale unable to close GIF file (%s)\n", SvPVX(im->path));
    }
    im->gif = NULL;

    DEBUG_TRACE("image_gif_finish\n");
  }
}
Esempio n. 2
0
int
image_init(HV *self, image *im)
{
  unsigned char *bptr;
  char *file = NULL;
  int ret = 1;
  
  if (my_hv_exists(self, "file")) {
    // Input from file
    SV *path = *(my_hv_fetch(self, "file"));
    file = SvPVX(path);
    im->fh = IoIFP(sv_2io(*(my_hv_fetch(self, "_fh"))));
    im->path = newSVsv(path);
  }
  else {
    // Input from scalar ref
    im->fh = NULL;
    im->path = newSVpv("(data)", 0);
    im->sv_data = *(my_hv_fetch(self, "data"));
    if (SvROK(im->sv_data))
      im->sv_data = SvRV(im->sv_data);
    else
      croak("data is not a scalar ref\n");
  }
  
  im->pixbuf           = NULL;
  im->outbuf           = NULL;
  im->outbuf_size      = 0;
  im->type             = UNKNOWN;
  im->sv_offset        = 0;
  im->image_offset     = 0;
  im->image_length     = 0;
  im->width            = 0;
  im->height           = 0;
  im->width_padding    = 0;
  im->width_inner      = 0;
  im->height_padding   = 0;
  im->height_inner     = 0;
  im->flipped          = 0;
  im->bpp              = 0;
  im->channels         = 0;
  im->has_alpha        = 0;
  im->orientation      = ORIENTATION_NORMAL;
  im->orientation_orig = ORIENTATION_NORMAL;
  im->memory_limit     = 0;
  im->target_width     = 0;
  im->target_height    = 0;
  im->keep_aspect      = 0;
  im->resize_type      = IMAGE_SCALE_TYPE_GD_FIXED;
  im->filter           = 0;
  im->bgcolor          = 0;
  im->used             = 0;
  im->palette          = NULL;
  
#ifdef HAVE_JPEG
  im->cinfo            = NULL;
#endif
#ifdef HAVE_PNG
  im->png_ptr          = NULL;
  im->info_ptr         = NULL;
#endif
#ifdef HAVE_GIF
  im->gif              = NULL;
#endif

  // Read new() options
  if (my_hv_exists(self, "offset")) {
    im->image_offset = SvIV(*(my_hv_fetch(self, "offset")));
    if (im->fh != NULL)
      PerlIO_seek(im->fh, im->image_offset, SEEK_SET);
  }
  
  if (my_hv_exists(self, "length"))
    im->image_length = SvIV(*(my_hv_fetch(self, "length")));
  
  Newz(0, im->buf, sizeof(Buffer), Buffer);
  buffer_init(im->buf, BUFFER_SIZE);
  im->memory_used = BUFFER_SIZE;
  
  // Determine type of file from magic bytes
  if (im->fh != NULL) {
    if ( !_check_buf(im->fh, im->buf, 8, BUFFER_SIZE) ) {
      image_finish(im);
      croak("Unable to read image header for %s\n", file);
    }
  }
  else {
    im->sv_offset = MIN(sv_len(im->sv_data) - im->image_offset, BUFFER_SIZE);
    buffer_append(im->buf, SvPVX(im->sv_data) + im->image_offset, im->sv_offset);
  }
  
  bptr = buffer_ptr(im->buf);
  
  switch (bptr[0]) {
    case 0xff:
      if (bptr[1] == 0xd8 && bptr[2] == 0xff) {
#ifdef HAVE_JPEG
        im->type = JPEG;
#else
        image_finish(im);
        croak("Image::Scale was not built with JPEG support\n");
#endif
      }
      break;
    case 0x89:
      if (bptr[1] == 'P' && bptr[2] == 'N' && bptr[3] == 'G'
        && bptr[4] == 0x0d && bptr[5] == 0x0a && bptr[6] == 0x1a && bptr[7] == 0x0a) {
#ifdef HAVE_PNG
          im->type = PNG;
#else
          image_finish(im);
          croak("Image::Scale was not built with PNG support\n");
#endif
      }
      break;
    case 'G':
      if (bptr[1] == 'I' && bptr[2] == 'F' && bptr[3] == '8'
        && (bptr[4] == '7' || bptr[4] == '9') && bptr[5] == 'a') {
#ifdef HAVE_GIF
          im->type = GIF;
#else
          image_finish(im);
          croak("Image::Scale was not built with GIF support\n");
#endif
      }
      break;
    case 'B':
      if (bptr[1] == 'M') {
        im->type = BMP;
      }
      break;
  }
  
  DEBUG_TRACE("Image type: %d\n", im->type);
    
  // Read image header via type-specific function to determine dimensions
  switch (im->type) {
#ifdef HAVE_JPEG
    case JPEG:
      if ( !image_jpeg_read_header(im) ) {
        ret = 0;
        goto out;
      }
      break;
#endif
#ifdef HAVE_PNG
    case PNG:
      if ( !image_png_read_header(im) ) {
        ret = 0;
        goto out;
      }
      break;
#endif
#ifdef HAVE_GIF
    case GIF:
      if ( !image_gif_read_header(im) ) {
        ret = 0;
        goto out;
      }
      break;
#endif
    case BMP:
      image_bmp_read_header(im);
      break;
    case UNKNOWN:
      warn("Image::Scale unknown file type (%s), first 8 bytes were: %02x %02x %02x %02x %02x %02x %02x %02x\n",
        SvPVX(im->path), bptr[0], bptr[1], bptr[2], bptr[3], bptr[4], bptr[5], bptr[6], bptr[7]);
      ret = 0;
      break;
  }
  
  DEBUG_TRACE("Image dimenensions: %d x %d, channels %d\n", im->width, im->height, im->channels);
  
out:
  if (ret == 0)
    image_finish(im);
  
  return ret;
}