diff --git a/SingleOut/Action.h b/SingleOut/Action.h new file mode 100644 index 00000000..be1d98f0 --- /dev/null +++ b/SingleOut/Action.h @@ -0,0 +1,285 @@ +#pragma once +#include "Hive.h" + +namespace fgo::single_out +{ + // + // このクラスはアクションを担当します。 + // + inline struct Action + { +#pragma pack(push) +#pragma pack(1) + struct PixelARGB { uint8_t b, g, r, a; }; +#pragma pack(pop) + + template + struct Bits + { + int32_t width, height, stride; + std::unique_ptr bits; + + Bits(int32_t width, int32_t height, int32_t stride) + : width(width), height(height), stride(stride) + , bits(std::make_unique(height * stride)) + { + } + + T* get() + { + return reinterpret_cast(bits.get()); + } + + T* get_line(int32_t y) + { + return reinterpret_cast(bits.get() + y * stride); + } + }; + + inline static decltype(AviUtl::FilterPlugin::func_proc) true_exedit_func_proc = 0; + static BOOL hook_exedit_func_proc(AviUtl::FilterPlugin* fp, AviUtl::FilterProcInfo* fpip) + { + MY_TRACE(_T("hook_exedit_func_proc() begin\n")); + + const AviUtl::PixelYC white = { 4096, 0, 0 }; + AviUtl::PixelYC* ycp_edit = (AviUtl::PixelYC*)fpip->ycp_edit; + + for (int y = 0; y < fpip->h; y++) + { + int lineBegin = y * fpip->max_w; + + for (int x = 0; x < fpip->w; x++) + { + ycp_edit[lineBegin + x] = white; + } + } + + BOOL result = true_exedit_func_proc(fp, fpip); + + MY_TRACE(_T("hook_exedit_func_proc() end\n")); + + return result; + } + + static int GetEncoderClsid(const WCHAR* format, CLSID* pClsid) + { + UINT num = 0; // number of image encoders + UINT size = 0; // size of the image encoder array in bytes + + ImageCodecInfo* pImageCodecInfo = NULL; + + GetImageEncodersSize(&num, &size); + if(size == 0) + return -1; // Failure + + pImageCodecInfo = (ImageCodecInfo*)(malloc(size)); + if(pImageCodecInfo == NULL) + return -1; // Failure + + GetImageEncoders(num, size, pImageCodecInfo); + + for(UINT j = 0; j < num; ++j) + { + if( wcscmp(pImageCodecInfo[j].MimeType, format) == 0 ) + { + *pClsid = pImageCodecInfo[j].Clsid; + free(pImageCodecInfo); + return j; // Success + } + } + + free(pImageCodecInfo); + return -1; // Failure + } + + // + // 画像をエクスポートします。 + // + BOOL onExportImage(BOOL hasAlpha, BOOL itemOnly) + { + MY_TRACE_FUNC("%d, %d", hasAlpha, itemOnly); + + auto fp = magi.fp; + auto editp = magi.auin.GetEditp(); + if (!fp || !editp) return FALSE; + if (!fp->exfunc->is_editing(editp)) return FALSE; + + auto exedit = magi.auin.GetFilter(fp, "拡張編集"); + if (!exedit) return FALSE; + + char fileName[MAX_PATH] = {}; + if (!fp->exfunc->dlg_get_save_name(fileName, "PNG / BMP / JPG / GIF / TIFF File\0*.png;*.bmp;*.jpg;*.gif;*.tiff\0All File (*.*)\0*.*\0", 0)) + return FALSE; + + LPCSTR extension = ::PathFindExtensionA(fileName); + MY_TRACE_STR(extension); + + ULONG quality = hive.quality; + EncoderParameters encoderParameters = {}; + encoderParameters.Count = 1; + encoderParameters.Parameter[0].Guid = EncoderQuality; + encoderParameters.Parameter[0].Type = EncoderParameterValueTypeLong; + encoderParameters.Parameter[0].NumberOfValues = 1; + encoderParameters.Parameter[0].Value = &quality; + + CLSID encoder = {}; + int result = -1; + if (::lstrcmpiA(extension, ".bmp") == 0) result = GetEncoderClsid(L"image/bmp", &encoder); + else if (::lstrcmpiA(extension, ".jpg") == 0) result = GetEncoderClsid(L"image/jpeg", &encoder); + else if (::lstrcmpiA(extension, ".gif") == 0) result = GetEncoderClsid(L"image/gif", &encoder); + else if (::lstrcmpiA(extension, ".tif") == 0) result = GetEncoderClsid(L"image/tiff", &encoder); + else if (::lstrcmpiA(extension, ".png") == 0) result = GetEncoderClsid(L"image/png", &encoder); + + if (result == -1) + { + ::MessageBoxW(hive.mainWindow, L"拡張子が無効です", Hive::DisplayName, MB_OK); + + return FALSE; + } + + // フレームの映像サイズを取得します。 + int32_t frame = fp->exfunc->get_frame(editp); + int32_t width = 0, height = 0; + fp->exfunc->get_pixel_filtered(editp, frame, 0, &width, &height); + int32_t stride = width * 3 + width % 4; + + // 出力バッファを確保します。 + Bits output(width, height, width * 4); + + // 選択オブジェクトを囲う点線を消すために func_save_start を呼ぶ + if (exedit) exedit->func_save_start(exedit, frame, frame, editp); + + // 入力バッファを確保します。 + Bits input(width, height, stride); + fp->exfunc->get_pixel_filtered(editp, frame, input.get(), 0, 0); + + if (exedit && hasAlpha) + { + // func_proc をすり替え + true_exedit_func_proc = exedit->func_proc; + exedit->func_proc = hook_exedit_func_proc; + + // アルファ算出用のサブ入力バッファを確保します。 + Bits sub_input(width, height, stride); + fp->exfunc->get_pixel_filtered(editp, frame, sub_input.get(), 0, 0); + + // func_proc を元に戻す + exedit->func_proc = true_exedit_func_proc; + + for (int y = 0; y < height; y++) + { + auto output_line = output.get_line(height - y - 1); + auto input_line = input.get_line(y); + auto sub_input_line = sub_input.get_line(y); + + for (int x = 0; x < width; x++) + { + BYTE ra = (BYTE)(255 - sub_input_line[x].r + input_line[x].r); + BYTE ga = (BYTE)(255 - sub_input_line[x].g + input_line[x].g); + BYTE ba = (BYTE)(255 - sub_input_line[x].b + input_line[x].b); + output_line[x].a = (BYTE)((ra+ga+ba)/3); + output_line[x].r = ra ? (BYTE)(input_line[x].r * 255 / ra) : input_line[x].r; + output_line[x].g = ga ? (BYTE)(input_line[x].g * 255 / ga) : input_line[x].g; + output_line[x].b = ba ? (BYTE)(input_line[x].b * 255 / ba) : input_line[x].b; + } + } + } + else + { + for (int y = 0; y < height; y++) + { + auto output_line = output.get_line(height - y - 1); + auto input_line = input.get_line(y); + + for (int x = 0; x < width; x++) + { + output_line[x].a = 255; + output_line[x].r = input_line[x].r; + output_line[x].g = input_line[x].g; + output_line[x].b = input_line[x].b; + } + } + } + + if (exedit) exedit->func_save_end(exedit, editp); + + if (itemOnly) + { + // アイテムの位置を取得します。 + AviUtlInternal::SelectItem si = {}; + int32_t objectIndex = magi.auin.GetCurrentObjectIndex(); + size_t c = magi.auin.GetSelectItemCount(); + MY_TRACE_INT(c); + for (size_t i = 0; i < c; i++) + { + AviUtlInternal::SelectItem* si2 = magi.auin.GetSelectItem(i); + + MY_TRACE(_T("%d => 0x%08X, %d, %d, %d, %d, %d\n"), + i, si2->flags, si2->objectIndex, si2->x, si2->y, si2->w, si2->h); + + if (si2->flags & 0x04 && si2->objectIndex == objectIndex) + { + si = *si2; + + break; + } + } + + // アイテムの位置を正規化します。 + if (si.x < 0) si.w += si.x, si.x = 0; + if (si.y < 0) si.h += si.y, si.y = 0; + si.w = std::min(si.w, width - si.x); + si.h = std::min(si.h, height - si.y); + + if (si.x < 0 || si.w <= 0 || (si.x + si.w) > width) + { + ::MessageBoxW(hive.mainWindow, L"アイテムの位置情報が無効です", Hive::DisplayName, MB_OK); + + return FALSE; + } + + if (si.y < 0 || si.h <= 0 || (si.y + si.h) > height) + { + ::MessageBoxW(hive.mainWindow, L"アイテムの位置情報が無効です", Hive::DisplayName, MB_OK); + + return FALSE; + } + + PixelARGB* dstHead = output.get(); + PixelARGB* srcHead = output.get() + si.y * width + si.x; + + for (int y = 0; y < si.h; y++) + { + PixelARGB* dstLine = dstHead + y * si.w; + PixelARGB* srcLine = srcHead + y * width; + + for (int x = 0; x < si.w; x++) + { + dstLine[x] = srcLine[x]; + } + } + + width = si.w; + height = si.h; + } + + Bitmap bitmap(width, height, width * 4, PixelFormat32bppARGB, (BYTE*)output.get()); + + Status status; + if (::lstrcmpiA(extension, ".jpg") == 0) + status = bitmap.Save((_bstr_t)fileName, &encoder, &encoderParameters); + else + status = bitmap.Save((_bstr_t)fileName, &encoder); + MY_TRACE_COM_ERROR(status); + + if (status != S_OK) + { + ::MessageBoxW(hive.mainWindow, L"ファイルの保存に失敗しました", Hive::DisplayName, MB_OK); + + return FALSE; + } + + return TRUE; + } + } action; +} diff --git a/SingleOut/Config.h b/SingleOut/Config.h new file mode 100644 index 00000000..40bc397d --- /dev/null +++ b/SingleOut/Config.h @@ -0,0 +1,68 @@ +#pragma once +#include "Hive.h" +#include "MainWindow.h" + +namespace fgo::single_out +{ + // + // このクラスはコンフィグを管理します。 + // + inline struct Config + { + // + // コンフィグファイルのフルパスを返します。 + // + inline static std::wstring getConfigFileName() + { + return magi.getConfigFileName(hive.Name) + L".ini"; + } + + // + // コンフィグファイル名を取得し、設定を読み込みます。 + // + BOOL init() + { + MY_TRACE_FUNC(""); + + return load(getConfigFileName().c_str()); + } + + // + // コンフィグファイル名を取得し、設定を保存します。 + // + BOOL exit() + { + MY_TRACE_FUNC(""); + + return save(getConfigFileName().c_str()); + } + + // + // 指定されたファイルから設定を読み込みます。 + // + BOOL load(LPCWSTR path) + { + MY_TRACE_FUNC("%ws", path); + + getPrivateProfileInt(path, L"Config", L"quality", hive.quality); + getPrivateProfileWindow(path, L"MainWindow", mainWindow); + + mainWindow.mainDialog.updateControls(); + + return TRUE; + } + + // + // 指定されたファイルに設定を保存します。 + // + BOOL save(LPCWSTR path) + { + MY_TRACE_FUNC("%ws", path); + + setPrivateProfileInt(path, L"Config", L"quality", hive.quality); + setPrivateProfileWindow(path, L"MainWindow", mainWindow); + + return TRUE; + } + } config; +} diff --git a/SingleOut/Hive.h b/SingleOut/Hive.h index 16d0889e..9fa73b14 100644 --- a/SingleOut/Hive.h +++ b/SingleOut/Hive.h @@ -7,18 +7,12 @@ namespace fgo::single_out // inline struct Hive { - // - // このクラスは他のクラスから通知を受け取ります。 - // - struct Commander { - virtual BOOL onExportImage(BOOL hasAlpha, BOOL itemOnly) = 0; - } *commander = 0; - inline static const LPCWSTR Name = L"SingleOut"; inline static const LPCWSTR DisplayName = L"画像のエクスポート"; HINSTANCE instance = 0; HWND mainWindow = 0; + int quality = 90; } hive; } diff --git a/SingleOut/MainDialog.h b/SingleOut/MainDialog.h index 348d9ff5..eb11f06c 100644 --- a/SingleOut/MainDialog.h +++ b/SingleOut/MainDialog.h @@ -1,6 +1,7 @@ #pragma once #include "Resource.h" #include "Hive.h" +#include "Action.h" #include "Common/AviUtl/SliderPanel.h" namespace fgo::single_out @@ -10,6 +11,7 @@ namespace fgo::single_out // struct MainDialog : Tools::Dialog { + BOOL lock = FALSE; Tools::AviUtl::SliderPanel> quality; // @@ -25,7 +27,40 @@ namespace fgo::single_out // BOOL create(HWND parent) { - return __super::create(hive.instance, MAKEINTRESOURCE(IDD_MAIN_DIALOG), parent); + if (!__super::create(hive.instance, MAKEINTRESOURCE(IDD_MAIN_DIALOG), parent)) + return FALSE; + +// setComboBox(IDC_CONFIRM_OVERWRITE, paint.mode, _T("確認する"), _T("確認しない")); + + return TRUE; + } + + // + // コントロールの値を更新します。 + // + BOOL updateControls() + { + if (lock) return FALSE; + + lock = TRUE; + + quality.setValue(hive.quality); + + lock = FALSE; + + return TRUE; + } + + // + // コンフィグの値を更新します。 + // + BOOL updateConfig() + { + if (lock) return FALSE; + + hive.quality = quality.getValue(); + + return TRUE; } // @@ -114,10 +149,10 @@ namespace fgo::single_out { case IDOK: case IDCANCEL: return 0; - case IDC_EXPORT_FRAME_RGB: hive.commander->onExportImage(FALSE, FALSE); break; - case IDC_EXPORT_FRAME_RGBA: hive.commander->onExportImage(TRUE, FALSE); break; - case IDC_EXPORT_ITEM_RGB: hive.commander->onExportImage(FALSE, TRUE); break; - case IDC_EXPORT_ITEM_RGBA: hive.commander->onExportImage(TRUE, TRUE); break; + case IDC_EXPORT_FRAME_RGB: action.onExportImage(FALSE, FALSE); break; + case IDC_EXPORT_FRAME_RGBA: action.onExportImage(TRUE, FALSE); break; + case IDC_EXPORT_ITEM_RGB: action.onExportImage(FALSE, TRUE); break; + case IDC_EXPORT_ITEM_RGBA: action.onExportImage(TRUE, TRUE); break; case IDC_QUALITY: if (code == EN_CHANGE) hive.quality = quality.onChangeText(); break; } diff --git a/SingleOut/MainWindow.h b/SingleOut/MainWindow.h index 860f7d66..505fc239 100644 --- a/SingleOut/MainWindow.h +++ b/SingleOut/MainWindow.h @@ -7,15 +7,18 @@ namespace fgo::single_out // このクラスはメインウィンドウです。 // このウィンドウはプラグインウィンドウのように振る舞います。 // - struct MainWindow : Tools::AviUtl::PluginWindow + inline struct MainWindow : Tools::AviUtl::PluginWindow { MainDialog mainDialog; // - // ウィンドウを作成します。 + // 初期化を行います。 // - BOOL create() + BOOL init() { + MY_TRACE_FUNC(""); + + // プラグインウィンドウのようなウィンドウを作成します。 return createAsPlugin( hive.instance, magi.auin.GetAviUtlWindow(), @@ -26,6 +29,16 @@ namespace fgo::single_out 100, 100, 300, 300); } + // + // 後始末を行います。 + // + BOOL exit() + { + MY_TRACE_FUNC(""); + + return destroy(); + } + // // ウィンドウプロシージャです。 // @@ -53,5 +66,5 @@ namespace fgo::single_out return __super::onWndProc(hwnd, message, wParam, lParam); } - }; + } mainWindow; } diff --git a/SingleOut/Servant.h b/SingleOut/Servant.h index 8600077d..0a857ea1 100644 --- a/SingleOut/Servant.h +++ b/SingleOut/Servant.h @@ -1,4 +1,6 @@ #pragma once +#include "Hive.h" +#include "Config.h" #include "MainWindow.h" namespace fgo::single_out @@ -6,10 +8,8 @@ namespace fgo::single_out // // このクラスはフレームまたはアイテムの画像をエクスポートします。 // - inline struct SingleOut : Servant, Magi::CommandID::Plugin, Hive::Commander + inline struct SingleOut : Servant, Magi::CommandID::Plugin { - MainWindow mainWindow; - // // この仮想関数は、このサーヴァントの識別名が必要なときに呼ばれます。 // @@ -34,7 +34,6 @@ namespace fgo::single_out MY_TRACE_FUNC("0x%08X", instance); hive.instance = instance; - hive.commander = this; return TRUE; } @@ -73,8 +72,8 @@ namespace fgo::single_out Hive::DisplayName, MB_OK | MB_ICONWARNING); } - if (!load()) return FALSE; - if (!mainWindow.create()) return FALSE; + if (!mainWindow.init()) return FALSE; + if (!config.init()) return FALSE; hive.mainWindow = mainWindow; @@ -91,8 +90,8 @@ namespace fgo::single_out // BOOL on_window_exit(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, AviUtl::EditHandle* editp, AviUtl::FilterPlugin* fp) override { - save(); - mainWindow.destroy(); + config.exit(); + mainWindow.exit(); return FALSE; } @@ -106,8 +105,8 @@ namespace fgo::single_out { case ID_ADDIN: { - if (mainWindow) - Tools::AviUtl::PluginWindowExtension::show(mainWindow); + if (::IsWindow(mainWindow)) + mainWindow.show(); break; } @@ -115,325 +114,5 @@ namespace fgo::single_out return FALSE; } - - // - // コンフィグファイルのフルパスを返します。 - // - inline static std::wstring getConfigFileName() - { - return magi.getConfigFileName(L"SingleOut.ini"); - } - - // - // コンフィグファイル名を取得し、設定を読み込みます。 - // - BOOL load() - { - return load(getConfigFileName().c_str()); - } - - // - // 指定されたファイルから設定を読み込みます。 - // - BOOL load(LPCWSTR path) - { - getPrivateProfileInt(path, L"Config", L"quality", hive.quality); - getPrivateProfileWindow(path, L"MainWindow", mainWindow); - - return TRUE; - } - - // - // コンフィグファイル名を取得し、設定を保存します。 - // - BOOL save() - { - return save(getConfigFileName().c_str()); - } - - // - // 指定されたファイルに設定を保存します。 - // - BOOL save(LPCWSTR path) - { - setPrivateProfileInt(path, L"Config", L"quality", hive.quality); - setPrivateProfileWindow(path, L"MainWindow", mainWindow); - - return TRUE; - } - -#pragma pack(push) -#pragma pack(1) - struct PixelARGB { uint8_t b, g, r, a; }; -#pragma pack(pop) - - template - struct Bits - { - int32_t width, height, stride; - std::unique_ptr bits; - - Bits(int32_t width, int32_t height, int32_t stride) - : width(width), height(height), stride(stride) - , bits(std::make_unique(height * stride)) - { - } - - T* get() - { - return reinterpret_cast(bits.get()); - } - - T* get_line(int32_t y) - { - return reinterpret_cast(bits.get() + y * stride); - } - }; - - inline static decltype(AviUtl::FilterPlugin::func_proc) true_exedit_func_proc = 0; - static BOOL hook_exedit_func_proc(AviUtl::FilterPlugin* fp, AviUtl::FilterProcInfo* fpip) - { - MY_TRACE(_T("hook_exedit_func_proc() begin\n")); - - const AviUtl::PixelYC white = { 4096, 0, 0 }; - AviUtl::PixelYC* ycp_edit = (AviUtl::PixelYC*)fpip->ycp_edit; - - for (int y = 0; y < fpip->h; y++) - { - int lineBegin = y * fpip->max_w; - - for (int x = 0; x < fpip->w; x++) - { - ycp_edit[lineBegin + x] = white; - } - } - - BOOL result = true_exedit_func_proc(fp, fpip); - - MY_TRACE(_T("hook_exedit_func_proc() end\n")); - - return result; - } - - static int GetEncoderClsid(const WCHAR* format, CLSID* pClsid) - { - UINT num = 0; // number of image encoders - UINT size = 0; // size of the image encoder array in bytes - - ImageCodecInfo* pImageCodecInfo = NULL; - - GetImageEncodersSize(&num, &size); - if(size == 0) - return -1; // Failure - - pImageCodecInfo = (ImageCodecInfo*)(malloc(size)); - if(pImageCodecInfo == NULL) - return -1; // Failure - - GetImageEncoders(num, size, pImageCodecInfo); - - for(UINT j = 0; j < num; ++j) - { - if( wcscmp(pImageCodecInfo[j].MimeType, format) == 0 ) - { - *pClsid = pImageCodecInfo[j].Clsid; - free(pImageCodecInfo); - return j; // Success - } - } - - free(pImageCodecInfo); - return -1; // Failure - } - - // - // 画像をエクスポートします。 - // - BOOL onExportImage(BOOL hasAlpha, BOOL itemOnly) override - { - MY_TRACE_FUNC("%d, %d", hasAlpha, itemOnly); - - auto fp = magi.fp; - auto editp = magi.auin.GetEditp(); - if (!fp || !editp) return FALSE; - if (!fp->exfunc->is_editing(editp)) return FALSE; - - auto exedit = magi.auin.GetFilter(fp, "拡張編集"); - if (!exedit) return FALSE; - - char fileName[MAX_PATH] = {}; - if (!fp->exfunc->dlg_get_save_name(fileName, "PNG / BMP / JPG / GIF / TIFF File\0*.png;*.bmp;*.jpg;*.gif;*.tiff\0All File (*.*)\0*.*\0", 0)) - return FALSE; - - LPCSTR extension = ::PathFindExtensionA(fileName); - MY_TRACE_STR(extension); - - ULONG quality = hive.quality; - EncoderParameters encoderParameters = {}; - encoderParameters.Count = 1; - encoderParameters.Parameter[0].Guid = EncoderQuality; - encoderParameters.Parameter[0].Type = EncoderParameterValueTypeLong; - encoderParameters.Parameter[0].NumberOfValues = 1; - encoderParameters.Parameter[0].Value = &quality; - - CLSID encoder = {}; - int result = -1; - if (::lstrcmpiA(extension, ".bmp") == 0) result = GetEncoderClsid(L"image/bmp", &encoder); - else if (::lstrcmpiA(extension, ".jpg") == 0) result = GetEncoderClsid(L"image/jpeg", &encoder); - else if (::lstrcmpiA(extension, ".gif") == 0) result = GetEncoderClsid(L"image/gif", &encoder); - else if (::lstrcmpiA(extension, ".tif") == 0) result = GetEncoderClsid(L"image/tiff", &encoder); - else if (::lstrcmpiA(extension, ".png") == 0) result = GetEncoderClsid(L"image/png", &encoder); - - if (result == -1) - { - ::MessageBoxW(hive.mainWindow, L"拡張子が無効です", Hive::DisplayName, MB_OK); - - return FALSE; - } - - // フレームの映像サイズを取得します。 - int32_t frame = fp->exfunc->get_frame(editp); - int32_t width = 0, height = 0; - fp->exfunc->get_pixel_filtered(editp, frame, 0, &width, &height); - int32_t stride = width * 3 + width % 4; - - // 出力バッファを確保します。 - Bits output(width, height, width * 4); - - // 選択オブジェクトを囲う点線を消すために func_save_start を呼ぶ - if (exedit) exedit->func_save_start(exedit, frame, frame, editp); - - // 入力バッファを確保します。 - Bits input(width, height, stride); - fp->exfunc->get_pixel_filtered(editp, frame, input.get(), 0, 0); - - if (exedit && hasAlpha) - { - // func_proc をすり替え - true_exedit_func_proc = exedit->func_proc; - exedit->func_proc = hook_exedit_func_proc; - - // アルファ算出用のサブ入力バッファを確保します。 - Bits sub_input(width, height, stride); - fp->exfunc->get_pixel_filtered(editp, frame, sub_input.get(), 0, 0); - - // func_proc を元に戻す - exedit->func_proc = true_exedit_func_proc; - - for (int y = 0; y < height; y++) - { - auto output_line = output.get_line(height - y - 1); - auto input_line = input.get_line(y); - auto sub_input_line = sub_input.get_line(y); - - for (int x = 0; x < width; x++) - { - BYTE ra = (BYTE)(255 - sub_input_line[x].r + input_line[x].r); - BYTE ga = (BYTE)(255 - sub_input_line[x].g + input_line[x].g); - BYTE ba = (BYTE)(255 - sub_input_line[x].b + input_line[x].b); - output_line[x].a = (BYTE)((ra+ga+ba)/3); - output_line[x].r = ra ? (BYTE)(input_line[x].r * 255 / ra) : input_line[x].r; - output_line[x].g = ga ? (BYTE)(input_line[x].g * 255 / ga) : input_line[x].g; - output_line[x].b = ba ? (BYTE)(input_line[x].b * 255 / ba) : input_line[x].b; - } - } - } - else - { - for (int y = 0; y < height; y++) - { - auto output_line = output.get_line(height - y - 1); - auto input_line = input.get_line(y); - - for (int x = 0; x < width; x++) - { - output_line[x].a = 255; - output_line[x].r = input_line[x].r; - output_line[x].g = input_line[x].g; - output_line[x].b = input_line[x].b; - } - } - } - - if (exedit) exedit->func_save_end(exedit, editp); - - if (itemOnly) - { - // アイテムの位置を取得します。 - AviUtlInternal::SelectItem si = {}; - int32_t objectIndex = magi.auin.GetCurrentObjectIndex(); - size_t c = magi.auin.GetSelectItemCount(); - MY_TRACE_INT(c); - for (size_t i = 0; i < c; i++) - { - AviUtlInternal::SelectItem* si2 = magi.auin.GetSelectItem(i); - - MY_TRACE(_T("%d => 0x%08X, %d, %d, %d, %d, %d\n"), - i, si2->flags, si2->objectIndex, si2->x, si2->y, si2->w, si2->h); - - if (si2->flags & 0x04 && si2->objectIndex == objectIndex) - { - si = *si2; - - break; - } - } - - // アイテムの位置を正規化します。 - if (si.x < 0) si.w += si.x, si.x = 0; - if (si.y < 0) si.h += si.y, si.y = 0; - si.w = std::min(si.w, width - si.x); - si.h = std::min(si.h, height - si.y); - - if (si.x < 0 || si.w <= 0 || (si.x + si.w) > width) - { - ::MessageBoxW(hive.mainWindow, L"アイテムの位置情報が無効です", Hive::DisplayName, MB_OK); - - return FALSE; - } - - if (si.y < 0 || si.h <= 0 || (si.y + si.h) > height) - { - ::MessageBoxW(hive.mainWindow, L"アイテムの位置情報が無効です", Hive::DisplayName, MB_OK); - - return FALSE; - } - - PixelARGB* dstHead = output.get(); - PixelARGB* srcHead = output.get() + si.y * width + si.x; - - for (int y = 0; y < si.h; y++) - { - PixelARGB* dstLine = dstHead + y * si.w; - PixelARGB* srcLine = srcHead + y * width; - - for (int x = 0; x < si.w; x++) - { - dstLine[x] = srcLine[x]; - } - } - - width = si.w; - height = si.h; - } - - Bitmap bitmap(width, height, width * 4, PixelFormat32bppARGB, (BYTE*)output.get()); - - Status status; - if (::lstrcmpiA(extension, ".jpg") == 0) - status = bitmap.Save((_bstr_t)fileName, &encoder, &encoderParameters); - else - status = bitmap.Save((_bstr_t)fileName, &encoder); - MY_TRACE_COM_ERROR(status); - - if (status != S_OK) - { - ::MessageBoxW(hive.mainWindow, L"ファイルの保存に失敗しました", Hive::DisplayName, MB_OK); - - return FALSE; - } - - return TRUE; - } } servant; } diff --git a/SingleOut/SingleOut.rc b/SingleOut/SingleOut.rc index 6f82a8d0..c53bb9dc 100644 --- a/SingleOut/SingleOut.rc +++ b/SingleOut/SingleOut.rc @@ -50,18 +50,22 @@ END // Dialog // -IDD_MAIN_DIALOG DIALOGEX 0, 0, 144, 134 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_SYSMENU +IDD_MAIN_DIALOG DIALOGEX 0, 0, 334, 206 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_CLIPSIBLINGS | WS_SYSMENU EXSTYLE WS_EX_NOPARENTNOTIFY | WS_EX_CONTROLPARENT FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - LTEXT "JPEGi : ",IDC_QUALITY_LABEL,0,0,40,16,SS_CENTERIMAGE,WS_EX_RIGHT - CONTROL "",IDC_QUALITY_SLIDER,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,40,0,64,16 - EDITTEXT IDC_QUALITY,104,0,40,16,ES_RIGHT | ES_AUTOHSCROLL | ES_WANTRETURN | NOT WS_BORDER - PUSHBUTTON "݃t[ۑ",IDC_EXPORT_FRAME_RGB,0,16,144,16 - PUSHBUTTON "݃t[At@tŕۑ",IDC_EXPORT_FRAME_RGBA,0,32,144,16 - PUSHBUTTON "IACeۑ",IDC_EXPORT_ITEM_RGB,0,48,144,16 - PUSHBUTTON "IACeAt@tŕۑ",IDC_EXPORT_ITEM_RGBA,0,64,144,16 + PUSHBUTTON "݃t[ۑ",IDC_EXPORT_FRAME_RGB,0,0,144,16 + PUSHBUTTON "݃t[At@tŕۑ",IDC_EXPORT_FRAME_RGBA,0,16,144,16 + PUSHBUTTON "IACeۑ",IDC_EXPORT_ITEM_RGB,0,32,144,16 + PUSHBUTTON "IACeAt@tŕۑ",IDC_EXPORT_ITEM_RGBA,0,48,144,16 + RTEXT "ۑt@C ",IDC_TARGET_MODE_LABEL,0,64,96,16,SS_CENTERIMAGE,WS_EX_RIGHT + COMBOBOX IDC_TARGET_MODE,96,64,48,104,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + EDITTEXT IDC_TARGET,0,80,128,16,ES_AUTOHSCROLL | ES_WANTRETURN | NOT WS_BORDER + PUSHBUTTON "...",IDC_TARGET_DIR,128,80,16,16 + RTEXT "JPEGi ",IDC_QUALITY_LABEL,0,96,40,16,SS_CENTERIMAGE,WS_EX_RIGHT + CONTROL "",IDC_QUALITY_SLIDER,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,40,96,64,16 + EDITTEXT IDC_QUALITY,104,96,40,16,ES_RIGHT | ES_AUTOHSCROLL | ES_WANTRETURN | NOT WS_BORDER END @@ -76,9 +80,9 @@ BEGIN IDD_MAIN_DIALOG, DIALOG BEGIN LEFTMARGIN, 7 - RIGHTMARGIN, 137 + RIGHTMARGIN, 327 TOPMARGIN, 7 - BOTTOMMARGIN, 127 + BOTTOMMARGIN, 199 END END #endif // APSTUDIO_INVOKED diff --git a/SingleOut/SingleOut.vcxproj b/SingleOut/SingleOut.vcxproj index ed3427f4..6b4901ac 100644 --- a/SingleOut/SingleOut.vcxproj +++ b/SingleOut/SingleOut.vcxproj @@ -163,6 +163,8 @@ + + diff --git a/SingleOut/SingleOut.vcxproj.filters b/SingleOut/SingleOut.vcxproj.filters index 79e401a9..4ae29410 100644 --- a/SingleOut/SingleOut.vcxproj.filters +++ b/SingleOut/SingleOut.vcxproj.filters @@ -20,6 +20,8 @@ Resource + + diff --git a/SingleOut/resource.h b/SingleOut/resource.h index fafee3b4..adcb4f16 100644 --- a/SingleOut/resource.h +++ b/SingleOut/resource.h @@ -6,10 +6,15 @@ #define IDC_QUALITY_LABEL 1000 #define IDC_QUALITY_SLIDER 1001 #define IDC_QUALITY 1002 +#define IDC_TARGET 1003 +#define IDC_TARGET_MODE_LABEL 1004 #define IDC_EXPORT_FRAME_RGB 1100 #define IDC_EXPORT_FRAME_RGBA 1101 #define IDC_EXPORT_ITEM_RGB 1102 #define IDC_EXPORT_ITEM_RGBA 1103 +#define IDC_TARGET_REF 1104 +#define IDC_TARGET_DIR 1104 +#define IDC_TARGET_MODE 1201 // Next default values for new objects // @@ -17,7 +22,7 @@ #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 104 #define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1200 +#define _APS_NEXT_CONTROL_VALUE 1202 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif