static int gifdrv_open_memmap(const char *filename, int x_size, int y_size, BYTE *palette) { unsigned int i; GifColorType ColorMap256[256]; #if GIFLIB_MAJOR >= 5 int ec; #endif gifdrv_memmap_ext_filename = util_add_extension_const(filename, gif_drv.default_extension); gifdrv_memmap_fd = VICE_EGifOpenFileName(gifdrv_memmap_ext_filename, 0, &ec); if (gifdrv_memmap_fd == NULL) { lib_free(gifdrv_memmap_ext_filename); return -1; } gif_colors = VICE_MakeMapObject(256, ColorMap256); for (i = 0; i < 256; i++) { gif_colors->Colors[i].Blue = palette[(i * 3) + 2]; gif_colors->Colors[i].Green = palette[(i * 3) + 1]; gif_colors->Colors[i].Red = palette[i * 3]; } #if GIFLIB_MAJOR < 5 EGifSetGifVersion("87a"); #endif if (EGifPutScreenDesc(gifdrv_memmap_fd, x_size, y_size, 8, 0, gif_colors) == GIF_ERROR || EGifPutImageDesc(gifdrv_memmap_fd, 0, 0, x_size, y_size, 0, NULL) == GIF_ERROR) { VICE_EGifCloseFile(gifdrv_memmap_fd); VICE_FreeMapObject(gif_colors); lib_free(gifdrv_memmap_ext_filename); return -1; } return 0; }
bool toGif(QImage& img, QString& path) { int errcode; if(QFile(path).exists()) // Remove old file QFile::remove(path); GifFileType* t = EGifOpenFileName(path.toLocal8Bit().data(),true, &errcode); if(!t){ EGifCloseFile(t, &errcode); QTextStream(stdout) << "Can't open\n"; return false; } EGifSetGifVersion(t, true); GifColorType* colorArr = new GifColorType[256]; ColorMapObject* cmo = GifMakeMapObject(256, colorArr); bool unfinished = false; QImage tarQImg(img.width(), img.height(), QImage::Format_Indexed8); QVector<QRgb> table; for(int y = 0; y < img.height(); y++){ for(int x = 0; x < img.width(); x++){ if(table.size() >= 256){ unfinished = true; break; } QRgb pix; if(!table.contains(pix = img.pixel(x,y))){ table.push_back(pix); tarQImg.setColor(tarQImg.colorCount(), pix); } tarQImg.setPixel(x,y,table.indexOf(pix)); } if(table.size() >= 256){ unfinished = true; break; } } if(unfinished){ EGifCloseFile(t, &errcode); QTextStream(stdout) << "Unfinished\n"; return false; } for(int l = tarQImg.colorCount(); l < 256; l++){ tarQImg.setColor(l,0); } if(tarQImg.colorTable().size() != 256){ EGifCloseFile(t, &errcode); QTextStream(stdout) << "A lot of colors\n"; return false; } QVector<QRgb> clTab = tarQImg.colorTable(); for(int i = 0; i < 255; i++){ QRgb rgb = clTab[i]; colorArr[i].Red = qRed(rgb); colorArr[i].Green = qGreen(rgb); colorArr[i].Blue = qBlue(rgb); } cmo->Colors = colorArr; errcode = EGifPutScreenDesc(t, img.width(), img.height(), 256, 0, cmo); if(errcode != GIF_OK){ EGifCloseFile(t, &errcode); QTextStream(stdout) << "EGifPutScreenDesc error 1\n"; return false; } errcode = EGifPutImageDesc(t, 0, 0, img.width(), img.height(), false, 0); if(errcode != GIF_OK){ EGifCloseFile(t, &errcode); QTextStream(stdout) << "EGifPutImageDesc error 2\n"; return false; } //gen byte array GifByteType* byteArr = tarQImg.bits(); for(int h = 0; h < tarQImg.height(); h++){ errcode = EGifPutLine(t, byteArr, tarQImg.width()); if(errcode != GIF_OK){ EGifCloseFile(t, &errcode); QTextStream(stdout) << "EGifPutLine error 3\n"; return false; } byteArr += tarQImg.width(); byteArr += ((tarQImg.width() % 4)!=0 ? 4 - (tarQImg.width() % 4) : 0); } if(errcode != GIF_OK){ QTextStream(stdout) << "GIF error 4\n"; return false; } EGifCloseFile(t, &errcode); return true; }
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 Graphics::toGif(QImage &img, QString &path) { int errcode; if(QFile(path).exists()) // Remove old file QFile::remove(path); GifFileType *t = EGifOpenFileName(path.toStdString().c_str(), true, &errcode); if(!t) { EGifCloseFile(t, &errcode); std::cout << "Can't open\n"; return false; } EGifSetGifVersion(t, true); std::vector<GifColorType>colorArr; colorArr.resize(256); ColorMapObject *cmo = GifMakeMapObject(256, colorArr.data()); bool unfinished = false; QImage tarQImg(img.width(), img.height(), QImage::Format_Indexed8); QVector<QRgb> table; for(int y = 0; y < img.height(); y++) { for(int x = 0; x < img.width(); x++) { if(table.size() >= 256) { unfinished = true; break; } QRgb pix; if(!table.contains(pix = img.pixel(x, y))) { table.push_back(pix); tarQImg.setColor(tarQImg.colorCount(), pix); } tarQImg.setPixel(x, y, static_cast<uint>(table.indexOf(pix))); } if(table.size() >= 256) { unfinished = true; break; } } if(unfinished) { GifFreeMapObject(cmo); EGifCloseFile(t, &errcode); std::cout << "Unfinished\n"; return false; } for(int l = tarQImg.colorCount(); l < 256; l++) tarQImg.setColor(l, 0); if(tarQImg.colorTable().size() != 256) { GifFreeMapObject(cmo); EGifCloseFile(t, &errcode); std::cout << "A lot of colors\n"; return false; } std::vector<QRgb> clTab = tarQImg.colorTable().toStdVector(); for(size_t i = 0; i < 255; i++) { QRgb rgb = clTab[i]; colorArr[i].Red = static_cast<unsigned char>(qRed(rgb)); colorArr[i].Green = static_cast<unsigned char>(qGreen(rgb)); colorArr[i].Blue = static_cast<unsigned char>(qBlue(rgb)); } cmo->Colors = colorArr.data(); errcode = EGifPutScreenDesc(t, img.width(), img.height(), 256, 0, cmo); if(errcode != GIF_OK) { GifFreeMapObject(cmo); EGifCloseFile(t, &errcode); std::cout << "EGifPutScreenDesc error 1\n"; return false; } errcode = EGifPutImageDesc(t, 0, 0, img.width(), img.height(), false, 0); if(errcode != GIF_OK) { GifFreeMapObject(cmo); EGifCloseFile(t, &errcode); std::cout << "EGifPutImageDesc error 2\n"; return false; } //gen byte array GifByteType *byteArr = tarQImg.bits(); for(int h = 0; h < tarQImg.height(); h++) { errcode = EGifPutLine(t, byteArr, tarQImg.width()); if(errcode != GIF_OK) { GifFreeMapObject(cmo); EGifCloseFile(t, &errcode); std::cout << "EGifPutLine error 3\n"; return false; } byteArr += tarQImg.width(); byteArr += ((tarQImg.width() % 4) != 0 ? 4 - (tarQImg.width() % 4) : 0); } GifFreeMapObject(cmo); EGifCloseFile(t, &errcode); return true; }
bool ParupaintPanvasInputOutput::exportGIF(ParupaintPanvas * panvas, const QString & filename, QString & errorStr) { Q_ASSERT(panvas); if(filename.isEmpty()) return (errorStr = "Enter a filename to save to.").isEmpty(); #ifndef PARUPAINT_NOGIF int error = 0; GifFileType * gif = EGifOpenFileName(filename.toStdString().c_str(), false, &error); foreach(const QImage & image, panvas->mergedImageFrames(true)){ error = 0; bool alpha = false; QImage toWrite = convertToIndexed8(image, &alpha); QVector<QRgb> colorTable = toWrite.colorTable(); ColorMapObject cmap; int numColors = 1 << BitSize(toWrite.colorCount()); numColors = 256; cmap.ColorCount = numColors; cmap.BitsPerPixel = 8; /// @todo based on numColors (or not? we did ask for Format_Indexed8, so the data is always 8-bit, right?) GifColorType* colorValues = (GifColorType*)malloc(cmap.ColorCount * sizeof(GifColorType)); cmap.Colors = colorValues; int c = 0; for(; c < toWrite.colorCount(); ++c) { //qDebug("color %d has %02X%02X%02X", c, qRed(colorTable[c]), qGreen(colorTable[c]), qBlue(colorTable[c])); colorValues[c].Red = qRed(colorTable[c]); colorValues[c].Green = qGreen(colorTable[c]); colorValues[c].Blue = qBlue(colorTable[c]); } // In case we had an actual number of colors that's not a power of 2, // fill the rest with something (black perhaps). for (; c < numColors; ++c) { colorValues[c].Red = 0; colorValues[c].Green = 0; colorValues[c].Blue = 0; } /// @todo how to specify which version, or decide based on features in use // Because of this call, libgif is not re-entrant EGifSetGifVersion(gif, true); if ((error = EGifPutScreenDesc(gif, toWrite.width(), toWrite.height(), numColors, 0, &cmap)) == GIF_ERROR) qCritical("EGifPutScreenDesc returned error %d", error); int fps = (100.0/panvas->frameRate()); char flags = 1 << 3; if(alpha) flags |= 1; char graphics_ext[] = { flags, (char)(fps % 256), (char)(fps / 256), (char)(alpha ? 0x00 : 0xff) }; EGifPutExtension(gif, GRAPHICS_EXT_FUNC_CODE, 4, graphics_ext); if ((error = EGifPutImageDesc(gif, 0, 0, toWrite.width(), toWrite.height(), 0, &cmap)) == GIF_ERROR) qCritical("EGifPutImageDesc returned error %d", error); int lc = toWrite.height(); int llen = toWrite.bytesPerLine(); for (int l = 0; l < lc; ++l) { uchar* line = toWrite.scanLine(l); if ((error = EGifPutLine(gif, (GifPixelType*)line, llen)) == GIF_ERROR) { qCritical("EGifPutLine returned error %d", error); } } if(true){ // loop forever unsigned char loopblock[3] = {1, 0, 0}; EGifPutExtensionLeader(gif, APPLICATION_EXT_FUNC_CODE); EGifPutExtensionBlock(gif, 11, "NETSCAPE2.0"); EGifPutExtensionBlock(gif, 3, loopblock); EGifPutExtensionTrailer(gif); } } EGifCloseFile(gif, &error); return true; #endif return (errorStr = "GIF export not available.").isEmpty(); }