INLINE void * gif_save(const Image *image, const ColorMapObject *color_map, Frame *frames, int count, int frame_size, int *size) { GifBuffer buf = {0,}; int estimated = count * (image->columns * image->rows); buf.alloc = estimated; buf.data = malloc(estimated); GifFileType *gif_file = EGifOpen(&buf, gif_buffer_write, NULL); if (!gif_file) { return NULL; } if (EGifPutScreenDesc(gif_file, image->columns, image->rows, NCOLORS, 0, color_map) == GIF_ERROR) { EGifCloseFile(gif_file, NULL); return NULL; } if (GIF_BEGIN_APP_EXTENSION(gif_file) == GIF_ERROR) { EGifCloseFile(gif_file, NULL); return NULL; } unsigned char meta[] = { 0x01, // data sub-block index (always 1) 0xFF, 0xFF // 65535 repetitions - unsigned }; if (GIF_END_APP_EXTENSION(gif_file, meta) == GIF_ERROR) { EGifCloseFile(gif_file, NULL); return NULL; } int ii; unsigned char *p = (unsigned char*)frames; for (ii = 0; ii < count; ii++, p += frame_size) { Frame *frame = (Frame*)p; // GCE unsigned char gce[] = { 0x08, // no transparency frame->duration % 256, // LSB of delay frame->duration / 256, // MSB of delay in millisecs 0x00, // no transparent color }; if (EGifPutExtension(gif_file, GRAPHICS_EXT_FUNC_CODE, sizeof(gce), gce) == GIF_ERROR) { EGifCloseFile(gif_file, NULL); return NULL; } if (EGifPutImageDesc(gif_file, 0, 0, frame->width, frame->height, 0, NULL) == GIF_ERROR) { EGifCloseFile(gif_file, NULL); return NULL; } int yy; GifPixelType *p = frame->data; for (yy = 0; yy < frame->height; yy++, p += frame->width) { if (EGifPutLine(gif_file, p, frame->width) == GIF_ERROR) { EGifCloseFile(gif_file, NULL); return NULL; } } } EGifCloseFile(gif_file, NULL); *size = buf.size; return buf.data; }
/*! * \brief pixWriteMemGif() * * \param[out] pdata data of gif compressed image * \param[out] psize size of returned data * \param[in] pix * \return 0 if OK, 1 on error * * <pre> * Notes: * (1) See comments in pixReadMemGif() * (2) For Giflib version >= 5.1, this uses the EGifOpen() buffer * interface. No temp files are required. * </pre> */ l_int32 pixWriteMemGif(l_uint8 **pdata, size_t *psize, PIX *pix) { #if (GIFLIB_MAJOR == 5 && GIFLIB_MINOR >= 1) || GIFLIB_MAJOR > 5 int giferr; l_int32 result; GifFileType *gif; L_BBUFFER *buffer; #else char *fname; #endif /* 5.1 and beyond */ PROCNAME("pixWriteMemGif"); if (!pdata) return ERROR_INT("&data not defined", procName, 1 ); *pdata = NULL; if (!psize) return ERROR_INT("&size not defined", procName, 1 ); *psize = 0; if (!pix) return ERROR_INT("&pix not defined", procName, 1 ); #if (GIFLIB_MAJOR == 5 && GIFLIB_MINOR >= 1) || GIFLIB_MAJOR > 5 if((buffer = bbufferCreate(NULL, 0)) == NULL) { return ERROR_INT("failed to create buffer", procName, 1); } if ((gif = EGifOpen((void*)buffer, gifWriteFunc, NULL)) == NULL) { bbufferDestroy(&buffer); return ERROR_INT("failed to create GIF image handle", procName, 1); } result = pixToGif(pix, gif); EGifCloseFile(gif, &giferr); if(result == 0) { *pdata = bbufferDestroyAndSaveData(&buffer, psize); } else { bbufferDestroy(&buffer); } return result; #else L_INFO("writing to a temp file, not directly to memory\n", procName); /* Write to a temp file */ fname = l_makeTempFilename(NULL); pixWrite(fname, pix, IFF_GIF); /* Read back into memory */ *pdata = l_binaryRead(fname, psize); lept_rmfile(fname); LEPT_FREE(fname); return 0; #endif }
bool compress_custom(void* input_data, InputFunc input_func, void* output_data, OutputFunc output_func, int sample_size) { GifFileType* input_gif = NULL; GifFileType* output_gif = NULL; int result = GIF_ERROR; // Check sample if (sample_size <= 0) { return false; } input_gif = DGifOpen(input_data, input_func, &error_code); if (input_gif == NULL) { LOGE(EMSG("Can't open input gif")); return false; } DGifSlurp(input_gif); if (input_gif->ImageCount == 0) { LOGE(EMSG("Gif frame count is 0")); DGifCloseFile(input_gif, &error_code); return false; } // Save gif output_gif = EGifOpen(output_data, output_func, &error_code); if (output_gif == NULL) { LOGE(EMSG("Can't open output gif")); DGifCloseFile(input_gif, &error_code); return false; } if (do_compress(input_gif, output_gif, sample_size)) { result = EGifSpew(output_gif); } // Free GifFreeExtensions(&output_gif->ExtensionBlockCount, &output_gif->ExtensionBlocks); if (output_gif->SavedImages) { GifFreeSavedImages(output_gif); output_gif->SavedImages = NULL; } // Close gif DGifCloseFile(input_gif, &error_code); return result == GIF_OK; }
/*! * \brief pixWriteMemGif() * * \param[out] pdata data of gif compressed image * \param[out] psize size of returned data * \param[in] pix * \return 0 if OK, 1 on error * * <pre> * Notes: * (1) See comments in pixReadMemGif() * </pre> */ l_int32 pixWriteMemGif(l_uint8 **pdata, size_t *psize, PIX *pix) { int giferr; l_int32 result; GifFileType *gif; L_BBUFFER *buffer; PROCNAME("pixWriteMemGif"); /* 5.1+ and not 5.1.2 */ #if (GIFLIB_MAJOR < 5 || (GIFLIB_MAJOR == 5 && GIFLIB_MINOR == 0)) L_ERROR("Require giflib-5.1 or later\n", procName); return 1; #endif /* < 5.1 */ #if GIFLIB_MAJOR == 5 && GIFLIB_MINOR == 1 && GIFLIB_RELEASE == 2 /* 5.1.2 */ L_ERROR("Can't use giflib-5.1.2; suggest 5.1.3 or later\n", procName); return 1; #endif /* 5.1.2 */ if (!pdata) return ERROR_INT("&data not defined", procName, 1 ); *pdata = NULL; if (!psize) return ERROR_INT("&size not defined", procName, 1 ); *psize = 0; if (!pix) return ERROR_INT("&pix not defined", procName, 1 ); if ((buffer = bbufferCreate(NULL, 0)) == NULL) return ERROR_INT("failed to create buffer", procName, 1); if ((gif = EGifOpen((void*)buffer, gifWriteFunc, NULL)) == NULL) { bbufferDestroy(&buffer); return ERROR_INT("failed to create GIF image handle", procName, 1); } result = pixToGif(pix, gif); EGifCloseFile(gif, &giferr); if (result == 0) { *pdata = bbufferDestroyAndSaveData(&buffer, psize); } else { bbufferDestroy(&buffer); } return result; }
static void saveGif(ByteOutputStream &out, GifFileType *gf) { int error; GifFileType *gifOut = NULL; try { gifOut = EGifOpen(&out, writeGifStreamFunction, &error); if(gifOut == NULL) { THROWGIFERROR(error); } gifOut->SWidth = gf->SWidth; gifOut->SHeight = gf->SHeight; gifOut->SColorResolution = gf->SColorResolution; gifOut->SBackGroundColor = gf->SBackGroundColor; gifOut->SColorMap = GifMakeMapObject(gf->SColorMap->ColorCount ,gf->SColorMap->Colors); for(int i = 0; i < gf->ImageCount; i++) { GifMakeSavedImage(gifOut, &gf->SavedImages[i]); } if(gifOut->ImageCount > 0) { SavedImage *image0 = gifOut->SavedImages; addNetscapeBlock(image0); } EGifSetGifVersion(gifOut, true); if(EGifSpew(gifOut) != GIF_OK) { THROWGIFERROR(gifOut->Error); } } catch(Exception e) { if(gifOut != NULL) { EGifCloseFile(gifOut, &error); } throw e; } catch(...) { if(gifOut != NULL) { EGifCloseFile(gifOut, &error); } throw; } }
GDALDataset * GIFDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS, int bStrict, char ** papszOptions, GDALProgressFunc pfnProgress, void * pProgressData ) { int nBands = poSrcDS->GetRasterCount(); int nXSize = poSrcDS->GetRasterXSize(); int nYSize = poSrcDS->GetRasterYSize(); int bInterlace = FALSE; /* -------------------------------------------------------------------- */ /* Check for interlaced option. */ /* -------------------------------------------------------------------- */ bInterlace = CSLFetchBoolean(papszOptions, "INTERLACING", FALSE); /* -------------------------------------------------------------------- */ /* Some some rudimentary checks */ /* -------------------------------------------------------------------- */ if( nBands != 1 ) { CPLError( CE_Failure, CPLE_NotSupported, "GIF driver only supports one band images.\n" ); return NULL; } if (nXSize > 65535 || nYSize > 65535) { CPLError( CE_Failure, CPLE_NotSupported, "GIF driver only supports datasets up to 65535x65535 size.\n" ); return NULL; } if( poSrcDS->GetRasterBand(1)->GetRasterDataType() != GDT_Byte && bStrict ) { CPLError( CE_Failure, CPLE_NotSupported, "GIF driver doesn't support data type %s. " "Only eight bit bands supported.\n", GDALGetDataTypeName( poSrcDS->GetRasterBand(1)->GetRasterDataType()) ); return NULL; } /* -------------------------------------------------------------------- */ /* Open the output file. */ /* -------------------------------------------------------------------- */ GifFileType *hGifFile; VSILFILE *fp; fp = VSIFOpenL( pszFilename, "wb" ); if( fp == NULL ) { CPLError( CE_Failure, CPLE_OpenFailed, "Failed to create %s:\n%s", pszFilename, VSIStrerror( errno ) ); return NULL; } #if defined(GIFLIB_MAJOR) && GIFLIB_MAJOR >= 5 int nError; hGifFile = EGifOpen( fp, VSIGIFWriteFunc, &nError ); #else hGifFile = EGifOpen( fp, VSIGIFWriteFunc ); #endif if( hGifFile == NULL ) { VSIFCloseL( fp ); CPLError( CE_Failure, CPLE_OpenFailed, "EGifOpenFilename(%s) failed. Does file already exist?", pszFilename ); return NULL; } /* -------------------------------------------------------------------- */ /* Prepare colortable. */ /* -------------------------------------------------------------------- */ GDALRasterBand *poBand = poSrcDS->GetRasterBand(1); ColorMapObject *psGifCT; int iColor; if( poBand->GetColorTable() == NULL ) { psGifCT = GifMakeMapObject( 256, NULL ); for( iColor = 0; iColor < 256; iColor++ ) { psGifCT->Colors[iColor].Red = (GifByteType) iColor; psGifCT->Colors[iColor].Green = (GifByteType) iColor; psGifCT->Colors[iColor].Blue = (GifByteType) iColor; } } else { GDALColorTable *poCT = poBand->GetColorTable(); int nFullCount = 1; while( nFullCount < poCT->GetColorEntryCount() ) nFullCount = nFullCount * 2; psGifCT = GifMakeMapObject( nFullCount, NULL ); for( iColor = 0; iColor < poCT->GetColorEntryCount(); iColor++ ) { GDALColorEntry sEntry; poCT->GetColorEntryAsRGB( iColor, &sEntry ); psGifCT->Colors[iColor].Red = (GifByteType) sEntry.c1; psGifCT->Colors[iColor].Green = (GifByteType) sEntry.c2; psGifCT->Colors[iColor].Blue = (GifByteType) sEntry.c3; } for( ; iColor < nFullCount; iColor++ ) { psGifCT->Colors[iColor].Red = 0; psGifCT->Colors[iColor].Green = 0; psGifCT->Colors[iColor].Blue = 0; } } /* -------------------------------------------------------------------- */ /* Setup parameters. */ /* -------------------------------------------------------------------- */ if (EGifPutScreenDesc(hGifFile, nXSize, nYSize, psGifCT->ColorCount, 255, psGifCT) == GIF_ERROR) { GifFreeMapObject(psGifCT); GDALPrintGifError(hGifFile, "Error writing gif file."); GIFAbstractDataset::myEGifCloseFile(hGifFile); VSIFCloseL( fp ); return NULL; } GifFreeMapObject(psGifCT); psGifCT = NULL; /* Support for transparency */ int bNoDataValue; double noDataValue = poBand->GetNoDataValue(&bNoDataValue); if (bNoDataValue && noDataValue >= 0 && noDataValue <= 255) { unsigned char extensionData[4]; extensionData[0] = 1; /* Transparent Color Flag */ extensionData[1] = 0; extensionData[2] = 0; extensionData[3] = (unsigned char)noDataValue; EGifPutExtension(hGifFile, 0xf9, 4, extensionData); } if (EGifPutImageDesc(hGifFile, 0, 0, nXSize, nYSize, bInterlace, NULL) == GIF_ERROR ) { GDALPrintGifError(hGifFile, "Error writing gif file."); GIFAbstractDataset::myEGifCloseFile(hGifFile); VSIFCloseL( fp ); return NULL; } /* -------------------------------------------------------------------- */ /* Loop over image, copying image data. */ /* -------------------------------------------------------------------- */ CPLErr eErr; GDALPamDataset *poDS; GByte *pabyScanline; pabyScanline = (GByte *) CPLMalloc( nXSize ); if( !pfnProgress( 0.0, NULL, pProgressData ) ) eErr = CE_Failure; if( !bInterlace ) { for( int iLine = 0; iLine < nYSize; iLine++ ) { eErr = poBand->RasterIO( GF_Read, 0, iLine, nXSize, 1, pabyScanline, nXSize, 1, GDT_Byte, nBands, nBands * nXSize ); if( eErr != CE_None || EGifPutLine( hGifFile, pabyScanline, nXSize ) == GIF_ERROR ) { CPLError( CE_Failure, CPLE_AppDefined, "Error writing gif file." ); goto error; } if( !pfnProgress( (iLine + 1) * 1.0 / nYSize, NULL, pProgressData ) ) { goto error; } } } else { int i, j; int nLinesRead = 0; int nLinesToRead = 0; for ( i = 0; i < 4; i++) { for (j = InterlacedOffset[i]; j < nYSize; j += InterlacedJumps[i]) { nLinesToRead ++; } } /* Need to perform 4 passes on the images: */ for ( i = 0; i < 4; i++) { for (j = InterlacedOffset[i]; j < nYSize; j += InterlacedJumps[i]) { eErr= poBand->RasterIO( GF_Read, 0, j, nXSize, 1, pabyScanline, nXSize, 1, GDT_Byte, 1, nXSize ); if (eErr != CE_None || EGifPutLine(hGifFile, pabyScanline, nXSize) == GIF_ERROR) { CPLError( CE_Failure, CPLE_AppDefined, "Error writing gif file." ); goto error; } nLinesRead ++; if( !pfnProgress( nLinesRead * 1.0 / nYSize, NULL, pProgressData ) ) { goto error; } } } } CPLFree( pabyScanline ); pabyScanline = NULL; /* -------------------------------------------------------------------- */ /* cleanup */ /* -------------------------------------------------------------------- */ if (GIFAbstractDataset::myEGifCloseFile(hGifFile) == GIF_ERROR) { CPLError( CE_Failure, CPLE_AppDefined, "EGifCloseFile() failed.\n" ); hGifFile = NULL; goto error; } hGifFile = NULL; VSIFCloseL( fp ); fp = NULL; /* -------------------------------------------------------------------- */ /* Do we need a world file? */ /* -------------------------------------------------------------------- */ if( CSLFetchBoolean( papszOptions, "WORLDFILE", FALSE ) ) { double adfGeoTransform[6]; if( poSrcDS->GetGeoTransform( adfGeoTransform ) == CE_None ) GDALWriteWorldFile( pszFilename, "wld", adfGeoTransform ); } /* -------------------------------------------------------------------- */ /* Re-open dataset, and copy any auxilary pam information. */ /* -------------------------------------------------------------------- */ /* If outputing to stdout, we can't reopen it, so we'll return */ /* a fake dataset to make the caller happy */ CPLPushErrorHandler(CPLQuietErrorHandler); poDS = (GDALPamDataset*) GDALOpen(pszFilename, GA_ReadOnly); CPLPopErrorHandler(); if (poDS) { poDS->CloneInfo( poSrcDS, GCIF_PAM_DEFAULT ); return poDS; } else { CPLErrorReset(); GIFDataset* poGIF_DS = new GIFDataset(); poGIF_DS->nRasterXSize = nXSize; poGIF_DS->nRasterYSize = nYSize; for(int i=0;i<nBands;i++) poGIF_DS->SetBand( i+1, new GIFRasterBand( poGIF_DS, i+1, NULL, 0 ) ); return poGIF_DS; } error: if (hGifFile) GIFAbstractDataset::myEGifCloseFile(hGifFile); if (fp) VSIFCloseL( fp ); if (pabyScanline) CPLFree( pabyScanline ); return NULL; }
unsigned char * gifconv_lossless2gif(void *image_data, unsigned short width, unsigned short height, void *index_data, unsigned short index_data_count, int tag_no, int format, unsigned long *length) { GifFileType *GifFile = NULL; GifColorType *Colors = NULL; int ColorCount; my_gif_buffer gif_buff; gif_uint_32 gif_width = 0, gif_height = 0; int bpp; gif_bytep gif_image_data = NULL; gif_uint_32 x, y; gif_colorp gif_palette = NULL; // int trans_index = -1; int i; if (format != 3) { fprintf(stderr, "jpegconv_lossless2gif: format=%d not implemented yes.\n", format); return NULL; } bpp = 8; gif_width = width; gif_height = height; ColorCount = 256; Colors = calloc(sizeof(GifColorType), ColorCount); gif_buff.data = NULL; gif_buff.data_len = 0; gif_buff.data_offset = 0; #if GIFLIB_MAJOR >= 5 GifFile = EGifOpen(& gif_buff, gif_data_write_func, NULL); #else GifFile = EGifOpen(& gif_buff, gif_data_write_func); #endif if (GifFile == NULL) { fprintf(stderr, "gifconv_lossless2gif: can't open GIFFile\n"); return NULL; } GifFile->SWidth = gif_width; GifFile->SHeight = gif_height; GifFile->SColorResolution = bpp; gif_palette = (gif_colorp) malloc(sizeof(gif_color)*index_data_count); if (tag_no == 20) { swf_rgb_t *rgb_list = index_data; for (i=0 ; i < index_data_count ; i++) { Colors[i].Red = rgb_list[i].red; Colors[i].Green = rgb_list[i].green; Colors[i].Blue = rgb_list[i].blue; } } else { swf_rgba_t *rgba_list = index_data; for (i=0 ; i < index_data_count ; i++) { // if (rgba_list[i].alpha) Colors[i].Red = rgba_list[i].red; Colors[i].Green = rgba_list[i].green; Colors[i].Blue = rgba_list[i].blue; // gif_palette[i].alpha = ; } } GifFile->SBackGroundColor = 0; // XXX gif_image_data = (gif_bytep) calloc(sizeof(unsigned char), gif_width * gif_height); i = 0; for (y=0 ; y < gif_height ; y++) { for (x=0 ; x < gif_width ; x++) { unsigned char *data = image_data; gif_image_data[i] = data[x + y*((gif_width +3) & -4)]; i++; } } GifFile->SavedImages[0].RasterBits = gif_image_data; #if GIFLIB_MAJOR >= 5 GifFile->SColorMap = GifMakeMapObject(ColorCount, Colors); #else GifFile->SColorMap = MakeMapObject(ColorCount, Colors); #endif EGifSpew(GifFile); // XXX free(gif_image_data); if (GifFile) { #if GIFLIB_MAJOR == 5 && GIFLIB_MINOR >= 1 || GIFLIB_MAJOR > 5 EGifCloseFile(GifFile, NULL); #else EGifCloseFile(GifFile); #endif } *length = gif_buff.data_offset; return gif_buff.data; }
static int write_gif_info(const psx_image* image, image_writer_fn func, void* param, float quality, psx_image_header* header) { size_t buf_size; #if GIFLIB_MAJOR >= 5 int errorcode = 0; #endif struct gif_image_ctx* ctx = (struct gif_image_ctx*)calloc(1, sizeof(struct gif_image_ctx)); if (!ctx) { return -1; // out of memory. } ctx->writer = func; ctx->writer_param = param; #if GIFLIB_MAJOR >= 5 if ((ctx->gif = EGifOpen((void*)ctx, write_gif_from_memory, &errorcode)) == NULL) { free(ctx); return -1; } if (image->num_frames > 1) { EGifSetGifVersion(ctx->gif, true); } #else if ((ctx->gif = EGifOpen((void*)ctx, write_gif_from_memory)) == NULL) { free(ctx); return -1; } if (image->num_frames > 1) { EGifSetGifVersion("89a"); } else { EGifSetGifVersion("87a"); } #endif if (EGifPutScreenDesc(ctx->gif, image->width, image->height, 8, 0, NULL) == GIF_ERROR) { GIF_CLOSE_EFILE(ctx->gif); free(ctx); return -1; } if (image->num_frames > 1) { // add netscape2.0 application extension to an animation gif. #if GIFLIB_MAJOR >= 5 EGifPutExtensionLeader(ctx->gif, APPLICATION_EXT_FUNC_CODE); EGifPutExtensionBlock(ctx->gif, 11, "NETSCAPE2.0"); EGifPutExtensionBlock(ctx->gif, 3, "\x01\x00\x00"); EGifPutExtensionTrailer(ctx->gif); #else EGifPutExtensionFirst(ctx->gif, APPLICATION_EXT_FUNC_CODE, 11, "NETSCAPE2.0"); EGifPutExtensionLast(ctx->gif, APPLICATION_EXT_FUNC_CODE, 3, "\x01\x00\x00"); #endif } buf_size = image->width * image->height * sizeof(GifByteType); ctx->red_buf = (GifByteType*)malloc(buf_size); ctx->green_buf = (GifByteType*)malloc(buf_size); ctx->blue_buf = (GifByteType*)malloc(buf_size); ctx->output_buffer = (GifByteType*)malloc(buf_size); if (!ctx->red_buf || !ctx->green_buf || !ctx->blue_buf || !ctx->output_buffer) { GIF_CLOSE_EFILE(ctx->gif); if (ctx->red_buf) free(ctx->red_buf); if (ctx->green_buf) free(ctx->green_buf); if (ctx->blue_buf) free(ctx->blue_buf); if (ctx->output_buffer) free(ctx->output_buffer); free(ctx); return -1; } header->priv = ctx; header->width = image->width; header->height = image->height; header->pitch = image->pitch; header->depth = get_depth(image->format); header->bpp = get_bpp(image->format); header->format = (int)image->format; header->alpha = 1; header->frames = (int)image->num_frames; return 0; }
bool MCImageEncodeGIF(MCImageIndexedBitmap *p_indexed, IO_handle p_stream, uindex_t &r_bytes_written) { bool t_success = true; int32_t t_transparent = -1; uindex_t t_palette_size; uindex_t t_depth; t_depth = GifBitSize(p_indexed->palette_size); // GIF requires palette size to be 2^depth t_palette_size = 1 << t_depth; int t_err = 0; GifFileType *t_gif = nil; ColorMapObject *t_colormap = nil; MCGIFWriteContext t_context; t_context.stream = p_stream; t_context.byte_count = 0; t_success = nil != (t_gif = EGifOpen(&t_context, gif_writeFunc, &t_err)); if (t_success) t_success = nil != (t_colormap = GifMakeMapObject(t_palette_size, nil)); if (t_success) { for (uindex_t i = 0; i < p_indexed->palette_size; i++) { t_colormap->Colors[i].Red = p_indexed->palette[i].red; t_colormap->Colors[i].Green = p_indexed->palette[i].green; t_colormap->Colors[i].Blue = p_indexed->palette[i].blue; } for (uindex_t i = p_indexed->palette_size; i < t_palette_size; i++) { t_colormap->Colors[i].Red = t_colormap->Colors[i].Green = t_colormap->Colors[i].Blue = 0; } if (MCImageIndexedBitmapHasTransparency(p_indexed)) { t_transparent = p_indexed->transparent_index; t_colormap->Colors[t_transparent].Red = t_colormap->Colors[t_transparent].Green = t_colormap->Colors[t_transparent].Blue = 0xFF; } t_success = GIF_OK == EGifPutScreenDesc(t_gif, p_indexed->width, p_indexed->height, t_depth, 0, t_colormap); } if (t_success) { if (t_transparent != -1) { GraphicsControlBlock t_gcb; MCMemoryClear(&t_gcb, sizeof(t_gcb)); t_gcb.TransparentColor = t_transparent; GifByteType t_extension[4]; uindex_t t_extension_size; t_extension_size = EGifGCBToExtension(&t_gcb, t_extension); // Should always be 4 bytes MCAssert(t_extension_size == sizeof(t_extension)); t_success = GIF_OK == EGifPutExtension(t_gif, GRAPHICS_EXT_FUNC_CODE, sizeof(t_extension), t_extension); } } if (t_success) t_success = GIF_OK == EGifPutImageDesc(t_gif, 0, 0, p_indexed->width, p_indexed->height, false, nil); for (uindex_t y = 0; t_success && y < p_indexed->height; y++) t_success = GIF_OK == EGifPutLine(t_gif, (uint8_t*)p_indexed->data + y * p_indexed->stride, p_indexed->width); int t_error_code; if (GIF_ERROR == EGifCloseFile(t_gif, &t_error_code)) t_success = false; GifFreeMapObject(t_colormap); if (t_success) r_bytes_written = t_context.byte_count; return t_success; }
bool CxImageGIF::Encode(CxFile * fp) { if (EncodeSafeCheck(fp)) return false; GifFileType *GifFile = NULL; ColorMapObject *OutputColorMap = NULL; int i, ColorMapSize; if(head.biBitCount != 8) { if(head.biBitCount < 8)IncreaseBpp(8); else DecreaseBpp(8, true); } try { GifFile = EGifOpen(fp, writeCxFile); ColorMapSize = head.biClrUsed; OutputColorMap = MakeMapObject(ColorMapSize, NULL); RGBQUAD* pPal = GetPalette(); for(i=0; i<ColorMapSize; ++i) { OutputColorMap->Colors[i].Red = pPal[i].rgbRed; OutputColorMap->Colors[i].Green = pPal[i].rgbGreen; OutputColorMap->Colors[i].Blue = pPal[i].rgbBlue; } EGifPutScreenDesc(GifFile, head.biWidth, head.biHeight, OutputColorMap->ColorCount, info.nBkgndIndex== -1 ? 0 : info.nBkgndIndex, OutputColorMap); FreeMapObject(OutputColorMap); OutputColorMap = NULL; if(info.nBkgndIndex != -1) { unsigned char ExtStr[4] = { 1, 0, 0, info.nBkgndIndex }; EGifPutExtension(GifFile, GRAPHICS_EXT_FUNC_CODE, 4, ExtStr); } EGifPutImageDesc(GifFile, 0, 0, head.biWidth, head.biHeight, FALSE, NULL); for (i = 0; i < head.biHeight; i++) EGifPutLine(GifFile, GetBits(head.biHeight - i - 1), head.biWidth); EGifCloseFile(GifFile); GifFile = NULL; } catch (int errid) { strncpy(info.szLastError,GifGetErrorMessage(errid),255); if(OutputColorMap) { FreeMapObject(OutputColorMap); OutputColorMap = NULL; } if(GifFile) { EGifCloseFile(GifFile); GifFile = NULL; } return false; } catch (char *message) { strncpy(info.szLastError,message,255); if(OutputColorMap) { FreeMapObject(OutputColorMap); OutputColorMap = NULL; } if(GifFile) { EGifCloseFile(GifFile); GifFile = NULL; } return false; } return true; }
void EncodeToGifBufferWorker::Execute () { GifByteType * redBuff = (GifByteType *) _pixbuf, * greenBuff = (GifByteType *) _pixbuf + _width * _height, * blueBuff = (GifByteType *) _pixbuf + 2 * _width * _height, * alphaBuff = (GifByteType *) _pixbuf + 3 * _width * _height, * gifimgbuf = (GifByteType *) malloc(_width * _height * sizeof(GifByteType)); // the indexed image ColorMapObject *cmap; SavedImage * simg; if (NULL == gifimgbuf){ SetErrorMessage("Out of memory"); return; } cmap = GifMakeMapObject(_cmapSize, NULL); if (NULL == cmap){ free(gifimgbuf); SetErrorMessage("Out of memory"); return; } if (GIF_ERROR == GifQuantizeBuffer( _width, _height, &_colors, redBuff, greenBuff, blueBuff, gifimgbuf, cmap->Colors )){ free(gifimgbuf); GifFreeMapObject(cmap); SetErrorMessage("Unable to quantize image"); return; } int errcode; gifWriteCbData buffinf = {NULL, 0}; GifFileType * gif; gif = EGifOpen((void *) &buffinf, gifWriteCB, &errcode); if (NULL == gif){ free(gifimgbuf); GifFreeMapObject(cmap); SetErrorMessage(GifErrorString(errcode)); return; } gif->SWidth = _width; gif->SHeight = _height; gif->SColorResolution = _cmapSize; simg = GifMakeSavedImage(gif, NULL); if (NULL == simg){ free(gifimgbuf); EGifCloseFile(gif, &errcode); // will also free cmap SetErrorMessage("Out of memory"); return; } simg->ImageDesc.Left = 0; simg->ImageDesc.Top = 0; simg->ImageDesc.Width = _width; simg->ImageDesc.Height = _height; simg->ImageDesc.Interlace = _interlaced; simg->ImageDesc.ColorMap = cmap; simg->RasterBits = gifimgbuf; // for some reason giflib sometimes creates an invalid file if the global // color table is not set as well gif->SColorMap = cmap; if (_trans){ ExtensionBlock ext; // 1. assign transparent color index in color table GraphicsControlBlock gcb = {0, false, 0, _colors++}; // 2. replace transparent pixels above threshold with this color remapTransparentPixels(gifimgbuf, alphaBuff, _width, _height, gcb.TransparentColor, _threshold); // 3. create a control block size_t extlen = EGifGCBToExtension(&gcb, (GifByteType *) &ext); if (GIF_ERROR == GifAddExtensionBlock( &(simg->ExtensionBlockCount), &(simg->ExtensionBlocks), GRAPHICS_EXT_FUNC_CODE, extlen, (unsigned char *) &ext) ) { EGifCloseFile(gif, &errcode); SetErrorMessage("Out of memory"); return; } } if (GIF_ERROR == EGifSpew(gif)){ EGifCloseFile(gif, &errcode); SetErrorMessage(GifErrorString(gif->Error)); return; } _gifbuf = (char *) buffinf.buff; _gifbufsize = buffinf.buffsize; return; }
void AnimatedGifEncoder::new_frame(unsigned char *data, int delay) { if (!gif_file) { if (write_func != NULL) { int nError; gif_file = EGifOpen(write_user_data, write_func, &nError); if (!gif_file) throw "EGifOpen in AnimatedGifEncoder::new_frame failed"; } else if (file_name.empty()) { // memory writer int nError; gif_file = EGifOpen(&gif, gif_writer, &nError); if (!gif_file) throw "EGifOpen in AnimatedGifEncoder::new_frame failed"; } else { int nError; gif_file = EGifOpenFileName(file_name.c_str(), FALSE, &nError); if (!gif_file) throw "EGifOpenFileName in AnimatedGifEncoder::new_frame failed"; } output_color_map = GifMakeMapObject(color_map_size, ext_web_safe_palette); if (!output_color_map) throw "MakeMapObject in AnimatedGifEncoder::new_frame failed"; gif_buf = (GifByteType *)malloc(sizeof(GifByteType)*width*height); if (!gif_buf) throw "malloc in AnimatedGifEncoder::new_frame failed"; } RGBator rgb(data, width, height, buf_type); if (web_safe_quantize(width, height, rgb.red, rgb.green, rgb.blue, gif_buf) == GIF_ERROR) throw "web_safe_quantize in AnimatedGifEncoder::new_frame failed"; /* if (QuantizeBuffer(width, height, &color_map_size, rgb.red, rgb.green, rgb.blue, gif_buf, output_color_map->Colors) == GIF_ERROR) { throw "QuantizeBuffer in AnimatedGifEncoder::new_frame failed"; } */ if (!headers_set) { if (EGifPutScreenDesc(gif_file, width, height, color_map_size, 0, output_color_map) == GIF_ERROR) { throw "EGifPutScreenDesc in AnimatedGifEncoder::new_frame failed"; } char netscape_extension[] = "NETSCAPE2.0"; EGifPutExtension(gif_file, APPLICATION_EXT_FUNC_CODE, 11, netscape_extension); char animation_extension[] = { 1, 1, 0 }; // repeat one time EGifPutExtension(gif_file, APPLICATION_EXT_FUNC_CODE, 3, animation_extension); headers_set = true; } char frame_flags = 1 << 2; char transp_color_idx = 0; if (transparency_color.color_present) { int i = find_color_index(output_color_map, color_map_size, transparency_color); if (i>=0) { frame_flags |= 1; transp_color_idx = i; } } char extension[] = { frame_flags, delay%256, delay/256, transp_color_idx }; EGifPutExtension(gif_file, GRAPHICS_EXT_FUNC_CODE, 4, extension); if (EGifPutImageDesc(gif_file, 0, 0, width, height, FALSE, NULL) == GIF_ERROR) { throw "EGifPutImageDesc in AnimatedGifEncoder::new_frame failed"; } GifByteType *gif_bufp = gif_buf; for (int i = 0; i < height; i++) { if (EGifPutLine(gif_file, gif_bufp, width) == GIF_ERROR) { throw "EGifPutLine in AnimatedGifEncoder::new_frame failed"; } gif_bufp += width; } }
void GifEncoder::encode() { RGBator rgb(data, width, height, buf_type); int color_map_size = 256; ColorMapObject *output_color_map = GifMakeMapObject(256, ext_web_safe_palette); LOKI_ON_BLOCK_EXIT(GifFreeMapObject, output_color_map); if (!output_color_map) throw "MakeMapObject in GifEncoder::encode failed"; GifByteType *gif_buf = (GifByteType *)malloc(sizeof(GifByteType)*width*height); LOKI_ON_BLOCK_EXIT(free, gif_buf); if (!gif_buf) throw "malloc in GifEncoder::encode failed"; if (web_safe_quantize(width, height, rgb.red, rgb.green, rgb.blue, gif_buf) == GIF_ERROR) throw "web_safe_quantize in GifEncoder::encode failed"; /* if (QuantizeBuffer(width, height, &color_map_size, rgb.red, rgb.green, rgb.blue, gif_buf, output_color_map->Colors) == GIF_ERROR) { throw "QuantizeBuffer in GifEncoder::encode failed"; } */ int nError; GifFileType *gif_file = EGifOpen(&gif, gif_writer, &nError); LOKI_ON_BLOCK_EXIT(EGifCloseFile, gif_file); if (!gif_file) throw "EGifOpen in GifEncoder::encode failed"; if (EGifPutScreenDesc(gif_file, width, height, color_map_size, 0, output_color_map) == GIF_ERROR) { throw "EGifPutScreenDesc in GifEncoder::encode failed"; } if (transparency_color.color_present) { int i = find_color_index(output_color_map, color_map_size, transparency_color); if (i) { char extension[] = { 1, // enable transparency 0, 0, // no time delay i // transparency color index }; EGifPutExtension(gif_file, GRAPHICS_EXT_FUNC_CODE, 4, extension); } } if (EGifPutImageDesc(gif_file, 0, 0, width, height, FALSE, NULL) == GIF_ERROR) { throw "EGifPutImageDesc in GifEncoder::encode failed"; } GifByteType *gif_bufp = gif_buf; for (int i = 0; i < height; i++) { if (EGifPutLine(gif_file, gif_bufp, width) == GIF_ERROR) throw "EGifPutLine in GifEncoder::encode failed"; gif_bufp += width; } }