Handle<Value> MerlinImage::CoalesceImages(const Arguments& args) { HandleScope scope; MagickWand* wand = MerlinImage::ReadImage( ObjectWrap::Unwrap<MerlinImage>(args.This()) ); const int len = args.Length(); for (int i = 0; i < len; i++) { MerlinImage *mi = ObjectWrap::Unwrap<MerlinImage>(args[i]->ToObject()); MagickAddImage(wand, MerlinImage::ReadImage(mi)); } MagickWand* mosaicWand = MagickCoalesceImages(wand); return scope.Close(MerlinImage::WriteImage(mosaicWand)); }
//--------------------------------------------------------------------- // 出力プラグイン処理本体 //--------------------------------------------------------------------- BOOL func_output( OUTPUT_INFO *oip ) { const double mabiki = 1; //2にすると2フレーム中1フレームの間引き //intだと四捨五入の計算ができない if( oip->n > 500 / mabiki ) if( MessageBox( NULL, (LPCSTR) "大量のフレームが選択されています。\n本当に続行しますか?", (LPCSTR) "アニメーションGIF出力プラグイン", MB_YESNO | MB_ICONQUESTION ) == IDNO ) return TRUE; const int delay = round( mabiki * 100 * oip->scale / oip->rate ); //間引き×100÷フレームレートを四捨五入 MagickWandGenesis(); MagickWand *dest = NewMagickWand(); for( int i = 0; i < oip->n; i = i + mabiki ) { if( oip->func_is_abort() ) { if( MessageBox( NULL, (LPCSTR) "ここまでの出力データをアニメーションGIFに書き込みますか?", (LPCSTR) "アニメーションGIF出力プラグイン", MB_YESNO | MB_ICONQUESTION ) == IDYES ) break; else { DestroyMagickWand( dest ); MagickWandTerminus(); return TRUE; } } oip->func_rest_time_disp( i, oip->n ); int copy = 0; //コピーフレーム数 for( int j = 1; i + j < oip->n; j++ ) { if( oip->func_get_flag( i + j ) & OUTPUT_INFO_FRAME_FLAG_COPYFRAME ) copy++; else break; } MagickWand *source = NewMagickWand(); if( !MagickConstituteImage( source, oip->w, oip->h, "BGR", CharPixel, oip->func_get_video_ex( i, 0 ) ) ) //NULLだと警告 MessageBox( NULL, (LPCSTR) "データ取得失敗", (LPCSTR) "アニメーションGIF出力プラグイン", MB_OK|MB_ICONSTOP ); MagickFlipImage( source ); //AviUtlからはボトムアップで渡されるが、MagickConstituteImageはトップダウン固定 MagickSetImageDelay( source, delay * ( copy + 1 ) ); //コピーフレーム数0なら1倍 //MagickSetImageDispose( source, 0 ); MagickAddImage( dest, source ); DestroyMagickWand( source ); i = i + copy; //コピーフレーム数分だけ先送り oip->func_update_preview(); } MagickSetFirstIterator( dest ); MagickQuantizeImages( dest, 256, RGBColorspace, 0, FloydSteinbergDitherMethod, MagickFalse ); //MagickSetFirstIterator( dest ); //MagickSetImageIterations( dest, 0 ); if( !MagickSetFormat( dest, "GIF" ) ) MessageBox( NULL, (LPCSTR) "GIFセット失敗", (LPCSTR) "アニメーションGIF出力プラグイン", MB_OK|MB_ICONSTOP ); dest = MagickOptimizeImageLayers( MagickCoalesceImages( dest ) ); //ここでdisposeが1になる MagickOptimizeImageTransparency( dest ); //6.7.8-7以降が必要 if( !MagickWriteImages( dest, oip->savefile, MagickTrue ) ) MessageBox( NULL, (LPCSTR) "出力失敗", (LPCSTR) "アニメーションGIF出力プラグイン", MB_OK|MB_ICONSTOP ); DestroyMagickWand( dest ); MagickWandTerminus(); return TRUE; }
unsigned char *get_thumbnail(char *full_filename, char *thumbnail_str, size_t *thumbnail_size, int is_rotate, int rotate_degree) { unsigned char *image_data = NULL; if (full_filename == NULL || thumbnail_str == NULL) return NULL; MagickBooleanType status; MagickWand *tmp_magick_wand = NULL; MagickWand *magick_wand = NULL; magick_wand = NewMagickWand(); status = MagickReadImage(magick_wand, full_filename); if (status == MagickFalse) { ThrowWandException(magick_wand); return NULL; } PixelWand *background = NULL; size_t height = MagickGetImageHeight(magick_wand); size_t old_height = height; size_t width = MagickGetImageWidth(magick_wand); size_t old_width = width; ssize_t i = 0, j = 0; int is_crop = 0; char is_gif_flag = 0; char is_jpeg_flag = 0; int do_quality = 0; char *fileformat = NULL; fileformat = MagickGetImageFormat(magick_wand); if (fileformat == NULL) { return NULL; } if (0 == strcasecmp(fileformat, image_format[GIFEXT])) { is_gif_flag = 1; } else if (0 == strcasecmp(fileformat, image_format[JPEGEXT])) { is_jpeg_flag = 1; } else if (0 == strcasecmp(fileformat, image_format[JPGEXT])) { is_jpeg_flag = 1; } fileformat = (char *)MagickRelinquishMemory(fileformat); //free(); if( 'C' == *thumbnail_str ||'c' == *thumbnail_str ) { is_crop = 1; } if(is_crop) { ParseMetaGeometry(thumbnail_str + 1, &i, &j, &width, &height); } else { ParseMetaGeometry(thumbnail_str, &i, &j, &width, &height); } if (old_width == width && height == old_height) { image_data = MagickGetImagesBlob(magick_wand, thumbnail_size); } else if (width <= 0 || height <= 0) { logError("%s%s:Geometry %s error\n", __FILE__, __func__, thumbnail_str); } else { /* * if type of the image is GIF, maybe have more than one frame, so do this different * from others */ if (is_gif_flag) { tmp_magick_wand = magick_wand; magick_wand = MagickCoalesceImages(tmp_magick_wand); tmp_magick_wand = DestroyMagickWand(tmp_magick_wand); } /* * if size of the image less than 800 * 600 and that's type is JPEG, then do * quality 100 OP */ if ((old_width < 800) && (old_height < 600) && is_jpeg_flag && is_crop != 1) { do_quality = 1; } MagickResetIterator(magick_wand); while (MagickNextImage(magick_wand) != MagickFalse) { if(do_quality) { MagickSetImageCompressionQuality(magick_wand, 100); MagickStripImage(magick_wand); } if(is_crop == 0) MagickThumbnailImage(magick_wand, width, height); else { logInfo("crop Image %ld, %ld", i, j); MagickCropImage(magick_wand, width, height, i, j); } if(is_rotate == 1) { background=NewPixelWand(); status=PixelSetColor(background,"#000000"); MagickRotateImage(magick_wand, background,(double)rotate_degree); background=DestroyPixelWand(background); } } image_data = MagickGetImagesBlob(magick_wand, thumbnail_size); } magick_wand = DestroyMagickWand(magick_wand); return image_data; }