static bool sWriteMNG(GBitmap *bitmap, Stream &stream, U32 compressionLevel) { TORQUE_UNUSED( bitmap ); TORQUE_UNUSED( stream ); TORQUE_UNUSED( compressionLevel ); return false; #if 0 // ONLY RGB bitmap writing supported at this time! AssertFatal(getFormat() == GFXFormatR8G8B8 || getFormat() == GFXFormatR8G8B8A8 || getFormat() == GFXFormatA8, "GBitmap::writeMNG: ONLY RGB bitmap writing supported at this time."); if(getFormat() != GFXFormatR8G8B8 && getFormat() != GFXFormatR8G8B8A8 && getFormat() != GFXFormatA8) return (false); // maximum image size allowed #define MAX_HEIGHT 4096 if(getHeight() >= MAX_HEIGHT) return false; mngstuff mnginfo; dMemset(&mnginfo, 0, sizeof(mngstuff)); mng_handle mng = mng_initialize(&mnginfo, mngMallocFn, mngFreeFn, MNG_NULL); if(mng == NULL) { return false; } // setup the callbacks mng_setcb_openstream(mng, mngOpenDataFn); mng_setcb_closestream(mng, mngCloseDataFn); mng_setcb_writedata(mng, mngWriteDataFn); // create the file in memory mng_create(mng); mng_putchunk_defi(mng, 0, 0, 0, MNG_FALSE, 0, 0, MNG_FALSE, 0, getWidth(), 0, getHeight()); mnginfo.image = (GBitmap*)this; mnginfo.stream = &stream; switch(getFormat()) { case GFXFormatA8: mng_putchunk_ihdr(mng, getWidth(), getHeight(), MNG_BITDEPTH_8, MNG_COLORTYPE_GRAY, MNG_COMPRESSION_DEFLATE, MNG_FILTER_ADAPTIVE, MNG_INTERLACE_NONE); // not implemented in lib yet //mng_putimgdata_ihdr(mng, getWidth(), getHeight(), // MNG_COLORTYPE_GRAY, // MNG_BITDEPTH_8, // MNG_COMPRESSION_DEFLATE, // MNG_FILTER_ADAPTIVE, // MNG_INTERLACE_NONE, // MNG_CANVAS_GRAY8, mngCanvasLineFn); break; case GFXFormatR8G8B8: mng_putchunk_ihdr(mng, getWidth(), getHeight(), MNG_BITDEPTH_8, MNG_COLORTYPE_RGB, MNG_COMPRESSION_DEFLATE, MNG_FILTER_ADAPTIVE, MNG_INTERLACE_NONE); // not implemented in lib yet //mng_putimgdata_ihdr(mng, getWidth(), getHeight(), // MNG_COLORTYPE_RGB, // MNG_BITDEPTH_8, // MNG_COMPRESSION_DEFLATE, // MNG_FILTER_ADAPTIVE, // MNG_INTERLACE_NONE, // MNG_CANVAS_RGB8, mngCanvasLineFn); break; case GFXFormatR8G8B8A8: mng_putchunk_ihdr(mng, getWidth(), getHeight(), MNG_BITDEPTH_8, MNG_COLORTYPE_RGBA, MNG_COMPRESSION_DEFLATE, MNG_FILTER_ADAPTIVE, MNG_INTERLACE_NONE); // not implemented in lib yet //mng_putimgdata_ihdr(mng, getWidth(), getHeight(), // MNG_COLORTYPE_RGBA, // MNG_BITDEPTH_8, // MNG_COMPRESSION_DEFLATE, // MNG_FILTER_ADAPTIVE, // MNG_INTERLACE_NONE, // MNG_CANVAS_RGBA8, mngCanvasLineFn); break; } // below is a hack until libmng is mature enough to handle this itself //----------------------------------------------------------------------------- U8 *tmpbuffer = new U8[this->byteSize + getHeight()]; if(tmpbuffer == 0) { mng_cleanup(&mng); return false; } // transfer data, add filterbyte U32 effwdt = getWidth() * this->bytesPerPixel; for(U32 Row = 0; Row < getHeight(); Row++) { // first Byte in each scanline is filterbyte: currently 0 -> no filter tmpbuffer[Row * (effwdt + 1)] = 0; // copy the scanline dMemcpy(tmpbuffer + Row * (effwdt + 1) + 1, getAddress(0, Row), effwdt); } // compress data with zlib U8 *dstbuffer = new U8[this->byteSize + getHeight()]; if(dstbuffer == 0) { delete [] tmpbuffer; mng_cleanup(&mng); return false; } U32 dstbufferSize = this->byteSize + getHeight(); if(Z_OK != compress2((Bytef*)dstbuffer,(uLongf*)&dstbufferSize, (const Bytef*)tmpbuffer, dstbufferSize, 9)) { delete [] tmpbuffer; delete [] dstbuffer; mng_cleanup(&mng); return false; } mng_putchunk_idat(mng, dstbufferSize, (mng_ptr*)dstbuffer); //----------------------------------------------------------------------------- mng_putchunk_iend(mng); delete [] tmpbuffer; delete [] dstbuffer; mng_write(mng); mng_cleanup(&mng); return true; #endif }
/** * @brief write frame to MNG file * @param[in] *frame the frame to write to MNG file * @param[in] mng libmng handle * @param[in] width width of canvas * @param[in] height height of canvas * @param[in] first_frame if the frame is the first one in the file * @return 0 on success, 1 on error */ static int vomng_write_frame(struct vomng_frame *frame, mng_handle mng, unsigned int width, unsigned int height, int first_frame) { unsigned int delay_ms; /* determine delay */ if (frame->next) delay_ms = frame->next->time_ms - frame->time_ms; else delay_ms = VOMNG_DEFAULT_DELAY_MS; /* default delay for last frame */ /* write frame headers to MNG file */ if (mng_putchunk_seek(mng, 0, MNG_NULL)) { mp_msg(MSGT_VO, MSGL_ERR, "vomng: writing SEEK chunk failed\n"); return 1; } if (mng_putchunk_fram(mng, MNG_FALSE, /* keep canvas if not 1st frame */ first_frame ? MNG_FRAMINGMODE_1 : MNG_FRAMINGMODE_NOCHANGE, 0, MNG_NULL, /* no frame name */ MNG_CHANGEDELAY_DEFAULT, /* change only delay */ MNG_CHANGETIMOUT_NO, MNG_CHANGECLIPPING_NO, MNG_CHANGESYNCID_NO, delay_ms, /* new delay */ 0, /* no new timeout */ 0, 0, 0, 0, 0, /* no new boundary */ 0, 0)) { /* no count, no IDs */ mp_msg(MSGT_VO, MSGL_ERR, "vomng: writing FRAM chunk failed\n"); return 1; } if (mng_putchunk_defi(mng, 0, /* no ID */ MNG_DONOTSHOW_VISIBLE, MNG_ABSTRACT, MNG_TRUE, 0, 0, /* top left location */ MNG_FALSE, 0, 0, 0, 0)) { /* no clipping */ mp_msg(MSGT_VO, MSGL_ERR, "vomng: writing DEFI chunk failed\n"); return 1; } if (mng_putchunk_ihdr(mng, width, height, /* dimensions */ 8, MNG_COLORTYPE_RGB, /* RBG */ MNG_COMPRESSION_DEFLATE, MNG_FILTER_ADAPTIVE, MNG_INTERLACE_NONE)) { mp_msg(MSGT_VO, MSGL_ERR, "vomng: writing IHDR chunk failed\n"); return 1; } /* write frame data */ if (mng_putchunk_idat(mng, frame->len, frame->data)) { mp_msg(MSGT_VO, MSGL_ERR, "vomng: writing IDAT chunk failed\n"); return 1; } /* write frame footers to MNG file */ if (mng_putchunk_iend(mng)) { mp_msg(MSGT_VO, MSGL_ERR, "vomng: writing IEND chunk failed\n"); return 1; } return 0; }