+int FileGIF::write_frame(VFrame *frame)
+{
+ int w = frame->get_w(), h = frame->get_h();
+ ColorMapObject *cmap = 0;
+ int cmap_sz = depth >= 0 ? 1 << depth : 0;
+ int64_t len = w * h * sizeof(GifByteType);
+ GifByteType *bfr = (GifByteType *) malloc(len);
+ int result = !bfr ? 1 : 0;
+ if( !result ) {
+ VFrame gbrp(w, h, BC_GBRP);
+ gbrp.transfer_from(frame);
+ if( !(cmap = GifMakeMapObject(cmap_sz, 0)) )
+ result = 1;
+ if( !result ) {
+ GifByteType *gp = (GifByteType *)gbrp.get_r();
+ GifByteType *bp = (GifByteType *)gbrp.get_g();
+ GifByteType *rp = (GifByteType *)gbrp.get_b();
+ if( GifQuantizeBuffer(w, h, &cmap_sz, rp, gp, bp,
+ bfr, cmap->Colors) == GIF_ERROR )
+ result = 1;
+ }
+ }
+ if( !result && !writes &&
+ EGifPutScreenDesc(gif_file, w, h, depth, 0, 0) == GIF_ERROR )
+ result = 1;
+ if( !result &&
+ EGifPutImageDesc(gif_file, 0, 0, w, h, 0, cmap) == GIF_ERROR )
+ result = 1;
+
+ GifByteType *bp = bfr;
+ for( int y=0; !result && y<h; ++y ) {
+ if( EGifPutLine(gif_file, bp, w) == GIF_ERROR )
+ result = 1;
+ bp += w;
+ }
+ GifFreeMapObject(cmap);
+ if( bfr ) free(bfr);
+ ++writes;
+ return result;
+}
+
+static int write_data(GifFileType *gif_file, const GifByteType *bfr, int bytes)
+{
+ FileGIF *file = (FileGIF*)gif_file->UserData;
+ VFrame *output = file->output;
+ long size = output->get_compressed_size();
+ long alloc = output->get_compressed_allocated();
+ long len = size + bytes;
+ if( len > alloc )
+ output->allocate_compressed_data(2*size + bytes);
+ unsigned char *data = output->get_data() + size;
+ memcpy(data, bfr, bytes);
+ output->set_compressed_size(len);
+ return bytes;
+}
+
+int FileGIF::wopen_data(VFrame *output)
+{
+ int result = 0;
+ gif_file = EGifOpen(this, write_data, &err);
+ if( !gif_file ) {
+ eprintf("FileGIF::wopen_data %d: %s\n", __LINE__, GifErrorString(err));
+ result = 1;
+ }
+ if( !result ) {
+ output->set_compressed_size(0);
+ this->output = output;
+ writes = 0;
+ }
+ return result;
+}
+
+
+FileGIFList::FileGIFList(Asset *asset, File *file)
+ : FileList(asset, file, "GIFLIST", ".gif", FILE_UNKNOWN, FILE_GIF_LIST)
+{
+}
+
+FileGIFList::~FileGIFList()
+{
+}
+
+int FileGIFList::check_sig(Asset *asset)
+{
+ FILE *stream = fopen(asset->path, "rb");
+ if( stream ) {
+ unsigned char test[16];
+ int ret = fread(test, 16, 1, stream);
+ fclose(stream);
+ if( ret < 1 ) return 1;
+ if( test[0] == 'G' && test[1] == 'I' && test[2] == 'F' &&
+ test[3] == 'L' && test[4] == 'I' && test[5] == 'S' && test[6] == 'T')
+ return 1;
+ }
+ return 0;
+}
+
+int FileGIFList::colormodel_supported(int colormodel) { return BC_RGB888; }
+int FileGIFList::get_best_colormodel(Asset *asset, int driver) { return BC_RGB888; }
+
+int FileGIFList::read_frame_header(char *path)
+{
+ FILE *stream = fopen(path, "rb");
+ if( stream ) {
+ unsigned char test[16];
+ int ret = fread(test, 16, 1, stream);
+ fclose(stream);
+ if( ret < 1 ) return 1;
+ asset->format = FILE_GIF_LIST;
+ asset->width = test[6] | (test[7] << 8);
+ asset->height = test[8] | (test[9] << 8);
+ return 0;
+ }
+ perror(path);
+ return 1;
+}
+
+int FileGIFList::read_frame(VFrame *output, char *path)
+{
+ Asset *asset = new Asset(path);
+ FileGIF gif(asset, file);
+ int ret = gif.ropen_path(path);
+ if( !ret )
+ ret = gif.read_frame(output);
+ asset->remove_user();
+ return ret;
+}
+
+int FileGIFList::write_frame(VFrame *frame, VFrame *data, FrameWriterUnit *unit)
+{
+ int native_cmodel = BC_RGB888;
+ if( frame->get_color_model() != native_cmodel ) {
+ GIFUnit *gif_unit = (GIFUnit *)unit;
+ if( !gif_unit->temp_frame ) gif_unit->temp_frame =
+ new VFrame(frame->get_w(), frame->get_h(), native_cmodel);
+ gif_unit->temp_frame->transfer_from(frame);
+ frame = gif_unit->temp_frame;
+ }
+
+ FileGIF gif(asset, file);
+ int ret = gif.wopen_data(data);
+ if( !ret )
+ ret = gif.write_frame(frame);
+ return ret;
+}
+
+FrameWriterUnit* FileGIFList::new_writer_unit(FrameWriter *writer)
+{
+ return new GIFUnit(this, writer);
+}
+
+GIFUnit::GIFUnit(FileGIFList *file, FrameWriter *writer)
+ : FrameWriterUnit(writer)
+{
+ this->file = file;
+ temp_frame = 0;
+}
+
+GIFUnit::~GIFUnit()
+{
+ delete temp_frame;
+}
+