Пример #1
0
bool FliFormat::onSave(FileOp* fop)
{
  Sprite* sprite = fop->document->getSprite();
  unsigned char cmap[768];
  unsigned char omap[768];
  s_fli_header fli_header;
  int c, times;
  Palette *pal;

  /* prepare fli header */
  fli_header.filesize = 0;
  fli_header.frames = 0;
  fli_header.width = sprite->getWidth();
  fli_header.height = sprite->getHeight();

  if ((fli_header.width == 320) && (fli_header.height == 200))
    fli_header.magic = HEADER_FLI;
  else
    fli_header.magic = HEADER_FLC;

  fli_header.depth = 8;
  fli_header.flags = 3;
  fli_header.speed = get_time_precision(sprite);
  fli_header.created = 0;
  fli_header.updated = 0;
  fli_header.aspect_x = 1;
  fli_header.aspect_y = 1;
  fli_header.oframe1 = fli_header.oframe2 = 0;

  /* open the file to write in binary mode */
  FileHandle f(open_file_with_exception(fop->filename, "wb"));

  fseek(f, 128, SEEK_SET);

  // Create the bitmaps
  base::UniquePtr<Image> bmp(Image::create(IMAGE_INDEXED, sprite->getWidth(), sprite->getHeight()));
  base::UniquePtr<Image> old(Image::create(IMAGE_INDEXED, sprite->getWidth(), sprite->getHeight()));

  // Write frame by frame
  for (FrameNumber frpos(0);
       frpos < sprite->getTotalFrames();
       ++frpos) {
    /* get color map */
    pal = sprite->getPalette(frpos);
    for (c=0; c<256; c++) {
      cmap[3*c  ] = rgba_getr(pal->getEntry(c));
      cmap[3*c+1] = rgba_getg(pal->getEntry(c));
      cmap[3*c+2] = rgba_getb(pal->getEntry(c));
    }

    /* render the frame in the bitmap */
    clear_image(bmp, 0);
    layer_render(sprite->getFolder(), bmp, 0, 0, frpos);

    /* how many times this frame should be written to get the same
       time that it has in the sprite */
    times = sprite->getFrameDuration(frpos) / fli_header.speed;

    for (c=0; c<times; c++) {
      /* write this frame */
      if (frpos == 0 && c == 0)
        fli_write_frame(f, &fli_header, NULL, NULL,
                        (unsigned char *)bmp->getPixelAddress(0, 0), cmap, W_ALL);
      else
        fli_write_frame(f, &fli_header,
                        (unsigned char *)old->getPixelAddress(0, 0), omap,
                        (unsigned char *)bmp->getPixelAddress(0, 0), cmap, W_ALL);

      /* update the old image and color-map to the new ones to compare later */
      copy_image(old, bmp, 0, 0);
      memcpy(omap, cmap, 768);
    }

    /* update progress */
    fop_progress(fop, (float)(frpos.next()) / (float)(sprite->getTotalFrames()));
  }

  // Write the header and close the file
  fli_write_header(f, &fli_header);

  return true;
}
Пример #2
0
static void read_compressed_image(FILE* f, Image* image, size_t chunk_end, FileOp* fop, ASE_Header* header)
{
  PixelIO<ImageTraits> pixel_io;
  z_stream zstream;
  int y, err;

  zstream.zalloc = (alloc_func)0;
  zstream.zfree  = (free_func)0;
  zstream.opaque = (voidpf)0;

  err = inflateInit(&zstream);
  if (err != Z_OK)
    throw base::Exception("ZLib error %d in inflateInit().", err);

  std::vector<uint8_t> scanline(ImageTraits::scanline_size(image->w));
  std::vector<uint8_t> uncompressed(image->h * ImageTraits::scanline_size(image->w));
  std::vector<uint8_t> compressed(4096);
  int uncompressed_offset = 0;

  while (true) {
    size_t input_bytes;

    if (ftell(f)+compressed.size() > chunk_end) {
      input_bytes = chunk_end - ftell(f); // Remaining bytes
      ASSERT(input_bytes < compressed.size());

      if (input_bytes == 0)
        break;                  // Done, we consumed all chunk
    }
    else
      input_bytes = compressed.size();

    fread(&compressed[0], 1, input_bytes, f);

    zstream.next_in = (Bytef*)&compressed[0];
    zstream.avail_in = input_bytes;

    do {
      zstream.next_out = (Bytef*)&scanline[0];
      zstream.avail_out = scanline.size();

      err = inflate(&zstream, Z_NO_FLUSH);
      if (err != Z_OK && err != Z_STREAM_END)
        throw base::Exception("ZLib error %d in inflate().", err);

      size_t input_bytes = scanline.size() - zstream.avail_out;
      if (input_bytes > 0) {
        if (uncompressed_offset+input_bytes > uncompressed.size())
          throw base::Exception("Bad compressed image.");

        std::copy(scanline.begin(), scanline.begin()+input_bytes,
                  uncompressed.begin()+uncompressed_offset);
        uncompressed_offset += input_bytes;
      }
    } while (zstream.avail_out == 0);

    fop_progress(fop, (float)ftell(f) / (float)header->size);
  }

  uncompressed_offset = 0;
  for (y=0; y<image->h; y++) {
    typename ImageTraits::address_t address = image_address_fast<ImageTraits>(image, 0, y);
    pixel_io.read_scanline(address, image->w, &uncompressed[uncompressed_offset]);

    uncompressed_offset += ImageTraits::scanline_size(image->w);
  }

  err = inflateEnd(&zstream);
  if (err != Z_OK)
    throw base::Exception("ZLib error %d in inflateEnd().", err);
}
Пример #3
0
bool JpegFormat::onLoad(FileOp* fop)
{
  struct jpeg_decompress_struct cinfo;
  struct error_mgr jerr;
  Image *image;
  FILE *file;
  JDIMENSION num_scanlines;
  JSAMPARRAY buffer;
  JDIMENSION buffer_height;
  int c;

  file = fopen(fop->filename.c_str(), "rb");
  if (!file)
    return false;

  // Initialize the JPEG decompression object with error handling.
  jerr.fop = fop;
  cinfo.err = jpeg_std_error(&jerr.head);

  jerr.head.error_exit = error_exit;
  jerr.head.output_message = output_message;

  // Establish the setjmp return context for error_exit to use.
  if (setjmp(jerr.setjmp_buffer)) {
    jpeg_destroy_decompress(&cinfo);
    fclose(file);
    return false;
  }

  jpeg_create_decompress(&cinfo);

  // Specify data source for decompression.
  jpeg_stdio_src(&cinfo, file);

  // Read file header, set default decompression parameters.
  jpeg_read_header(&cinfo, true);

  if (cinfo.jpeg_color_space == JCS_GRAYSCALE)
    cinfo.out_color_space = JCS_GRAYSCALE;
  else
    cinfo.out_color_space = JCS_RGB;

  // Start decompressor.
  jpeg_start_decompress(&cinfo);

  // Create the image.
  image = fop_sequence_image(fop,
			     (cinfo.out_color_space == JCS_RGB ? IMAGE_RGB:
								 IMAGE_GRAYSCALE),
			     cinfo.output_width,
			     cinfo.output_height);
  if (!image) {
    jpeg_destroy_decompress(&cinfo);
    fclose(file);
    return false;
  }

  // Create the buffer.
  buffer_height = cinfo.rec_outbuf_height;
  buffer = (JSAMPARRAY)base_malloc(sizeof(JSAMPROW) * buffer_height);
  if (!buffer) {
    jpeg_destroy_decompress(&cinfo);
    fclose(file);
    return false;
  }

  for (c=0; c<(int)buffer_height; c++) {
    buffer[c] = (JSAMPROW)base_malloc(sizeof(JSAMPLE) *
				      cinfo.output_width * cinfo.output_components);
    if (!buffer[c]) {
      for (c--; c>=0; c--)
        base_free(buffer[c]);
      base_free(buffer);
      jpeg_destroy_decompress(&cinfo);
      fclose(file);
      return false;
    }
  }

  // Generate a grayscale palette if is necessary.
  if (image->imgtype == IMAGE_GRAYSCALE)
    for (c=0; c<256; c++)
      fop_sequence_set_color(fop, c, c, c, c);

  // Read each scan line.
  while (cinfo.output_scanline < cinfo.output_height) {
    // TODO
/*     if (plugin_want_close())  */
/*       break; */

    num_scanlines = jpeg_read_scanlines(&cinfo, buffer, buffer_height);

    /* RGB */
    if (image->imgtype == IMAGE_RGB) {
      uint8_t* src_address;
      uint32_t* dst_address;
      int x, y, r, g, b;

      for (y=0; y<(int)num_scanlines; y++) {
        src_address = ((uint8_t**)buffer)[y];
        dst_address = ((uint32_t**)image->line)[cinfo.output_scanline-1+y];

        for (x=0; x<image->w; x++) {
          r = *(src_address++);
          g = *(src_address++);
          b = *(src_address++);
          *(dst_address++) = _rgba(r, g, b, 255);
        }
      }
    }
    /* Grayscale */
    else {
      uint8_t* src_address;
      uint16_t* dst_address;
      int x, y;

      for (y=0; y<(int)num_scanlines; y++) {
        src_address = ((uint8_t**)buffer)[y];
        dst_address = ((uint16_t**)image->line)[cinfo.output_scanline-1+y];

        for (x=0; x<image->w; x++)
          *(dst_address++) = _graya(*(src_address++), 255);
      }
    }

    fop_progress(fop, (float)(cinfo.output_scanline+1) / (float)(cinfo.output_height));
    if (fop_is_stop(fop))
      break;
  }

  /* destroy all data */
  for (c=0; c<(int)buffer_height; c++)
    base_free(buffer[c]);
  base_free(buffer);

  jpeg_finish_decompress(&cinfo);
  jpeg_destroy_decompress(&cinfo);

  fclose(file);
  return true;
}
Пример #4
0
bool AseFormat::onLoad(FileOp *fop)
{
  Sprite *sprite = NULL;
  ASE_Header header;
  ASE_FrameHeader frame_header;
  int current_level;
  int frame_pos;
  int chunk_pos;
  int chunk_size;
  int chunk_type;
  int c, frame;

  FileHandle f(fop->filename.c_str(), "rb");
  if (!f)
    return false;

  if (!ase_file_read_header(f, &header)) {
    fop_error(fop, "Error reading header\n");
    return false;
  }

  // Create the new sprite
  sprite = new Sprite(header.depth == 32 ? IMAGE_RGB:
                      header.depth == 16 ? IMAGE_GRAYSCALE: IMAGE_INDEXED,
                      header.width, header.height, header.ncolors);
  if (!sprite) {
    fop_error(fop, "Error creating sprite with file spec\n");
    return false;
  }

  // Set frames and speed
  sprite->setTotalFrames(header.frames);
  sprite->setDurationForAllFrames(header.speed);

  // Set transparent entry
  sprite->setTransparentColor(header.transparent_index);

  // Prepare variables for layer chunks
  Layer* last_layer = sprite->getFolder();
  current_level = -1;

  /* read frame by frame to end-of-file */
  for (frame=0; frame<sprite->getTotalFrames(); frame++) {
    /* start frame position */
    frame_pos = ftell(f);
    fop_progress(fop, (float)frame_pos / (float)header.size);

    /* read frame header */
    ase_file_read_frame_header(f, &frame_header);

    /* correct frame type */
    if (frame_header.magic == ASE_FILE_FRAME_MAGIC) {
      /* use frame-duration field? */
      if (frame_header.duration > 0)
        sprite->setFrameDuration(frame, frame_header.duration);

      /* read chunks */
      for (c=0; c<frame_header.chunks; c++) {
        /* start chunk position */
        chunk_pos = ftell(f);
        fop_progress(fop, (float)chunk_pos / (float)header.size);

        /* read chunk information */
        chunk_size = fgetl(f);
        chunk_type = fgetw(f);

        switch (chunk_type) {

          /* only for 8 bpp images */
          case ASE_FILE_CHUNK_FLI_COLOR:
          case ASE_FILE_CHUNK_FLI_COLOR2:
            /* fop_error(fop, "Color chunk\n"); */

            if (sprite->getPixelFormat() == IMAGE_INDEXED) {
              Palette *prev_pal = sprite->getPalette(frame);
              Palette *pal =
                chunk_type == ASE_FILE_CHUNK_FLI_COLOR ?
                ase_file_read_color_chunk(f, sprite, frame):
                ase_file_read_color2_chunk(f, sprite, frame);

              if (prev_pal->countDiff(pal, NULL, NULL) > 0) {
                sprite->setPalette(pal, true);
              }

              delete pal;
            }
            else
              fop_error(fop, "Warning: was found a color chunk in non-8bpp file\n");
            break;

          case ASE_FILE_CHUNK_LAYER: {
            /* fop_error(fop, "Layer chunk\n"); */

            ase_file_read_layer_chunk(f, sprite,
                                      &last_layer,
                                      &current_level);
            break;
          }

          case ASE_FILE_CHUNK_CEL: {
            /* fop_error(fop, "Cel chunk\n"); */

            ase_file_read_cel_chunk(f, sprite, frame,
                                    sprite->getPixelFormat(), fop, &header,
                                    chunk_pos+chunk_size);
            break;
          }

          case ASE_FILE_CHUNK_MASK: {
            Mask *mask;

            /* fop_error(fop, "Mask chunk\n"); */

            mask = ase_file_read_mask_chunk(f);
            if (mask)
              delete mask;      // TODO add the mask in some place?
            else
              fop_error(fop, "Warning: error loading a mask chunk\n");

            break;
          }

          case ASE_FILE_CHUNK_PATH:
            /* fop_error(fop, "Path chunk\n"); */
            break;

          default:
            fop_error(fop, "Warning: Unsupported chunk type %d (skipping)\n", chunk_type);
            break;
        }

        /* skip chunk size */
        fseek(f, chunk_pos+chunk_size, SEEK_SET);
      }
    }

    /* skip frame size */
    fseek(f, frame_pos+frame_header.size, SEEK_SET);

    /* just one frame? */
    if (fop->oneframe)
      break;

    if (fop_is_stop(fop))
      break;
  }

  fop->document = new Document(sprite);

  if (ferror(f)) {
    fop_error(fop, "Error reading file.\n");
    return false;
  }
  else {
    return true;
  }
}
Пример #5
0
bool JpegFormat::onSave(FileOp* fop)
{
  struct jpeg_compress_struct cinfo;
  struct error_mgr jerr;
  Image *image = fop->seq.image;
  FILE *file;
  JSAMPARRAY buffer;
  JDIMENSION buffer_height;
  SharedPtr<JpegOptions> jpeg_options = fop->seq.format_options;
  int c;

  // Open the file for write in it.
  file = fopen(fop->filename.c_str(), "wb");
  if (!file) {
    fop_error(fop, "Error creating file.\n");
    return false;
  }

  // Allocate and initialize JPEG compression object.
  jerr.fop = fop;
  cinfo.err = jpeg_std_error(&jerr.head);
  jpeg_create_compress(&cinfo);

  // SPECIFY data destination file.
  jpeg_stdio_dest(&cinfo, file);

  // SET parameters for compression.
  cinfo.image_width = image->w;
  cinfo.image_height = image->h;

  if (image->imgtype == IMAGE_GRAYSCALE) {
    cinfo.input_components = 1;
    cinfo.in_color_space = JCS_GRAYSCALE;
  }
  else {
    cinfo.input_components = 3;
    cinfo.in_color_space = JCS_RGB;
  }

  jpeg_set_defaults(&cinfo);
  jpeg_set_quality(&cinfo, (int)MID(0, 100.0f * jpeg_options->quality, 100), true);
  cinfo.dct_method = JDCT_ISLOW;
  cinfo.smoothing_factor = 0;

  // START compressor.
  jpeg_start_compress(&cinfo, true);

  // CREATE the buffer.
  buffer_height = 1;
  buffer = (JSAMPARRAY)base_malloc(sizeof(JSAMPROW) * buffer_height);
  if (!buffer) {
    fop_error(fop, "Not enough memory for the buffer.\n");
    jpeg_destroy_compress(&cinfo);
    fclose(file);
    return false;
  }

  for (c=0; c<(int)buffer_height; c++) {
    buffer[c] = (JSAMPROW)base_malloc(sizeof(JSAMPLE) *
				      cinfo.image_width * cinfo.num_components);
    if (!buffer[c]) {
      fop_error(fop, "Not enough memory for buffer scanlines.\n");
      for (c--; c>=0; c--)
        base_free(buffer[c]);
      base_free(buffer);
      jpeg_destroy_compress(&cinfo);
      fclose(file);
      return false;
    }
  }

  // Write each scan line.
  while (cinfo.next_scanline < cinfo.image_height) {
    // RGB
    if (image->imgtype == IMAGE_RGB) {
      uint32_t* src_address;
      uint8_t* dst_address;
      int x, y;
      for (y=0; y<(int)buffer_height; y++) {
        src_address = ((uint32_t**)image->line)[cinfo.next_scanline+y];
        dst_address = ((uint8_t**)buffer)[y];
        for (x=0; x<image->w; x++) {
          c = *(src_address++);
          *(dst_address++) = _rgba_getr(c);
          *(dst_address++) = _rgba_getg(c);
          *(dst_address++) = _rgba_getb(c);
        }
      }
    }
    // Grayscale.
    else {
      uint16_t* src_address;
      uint8_t* dst_address;
      int x, y;
      for (y=0; y<(int)buffer_height; y++) {
        src_address = ((uint16_t**)image->line)[cinfo.next_scanline+y];
        dst_address = ((uint8_t**)buffer)[y];
        for (x=0; x<image->w; x++)
          *(dst_address++) = _graya_getv(*(src_address++));
      }
    }
    jpeg_write_scanlines(&cinfo, buffer, buffer_height);
    
    fop_progress(fop, (float)(cinfo.next_scanline+1) / (float)(cinfo.image_height));
  }

  // Destroy all data.
  for (c=0; c<(int)buffer_height; c++)
    base_free(buffer[c]);
  base_free(buffer);

  // Finish compression.
  jpeg_finish_compress(&cinfo);

  // Release JPEG compression object.
  jpeg_destroy_compress(&cinfo);

  // We can close the output file.
  fclose(file);

  // All fine.
  return true;
}