1 /*$
2  Copyright (C) 2013-2020 Azel.
3 
4  This file is part of AzPainter.
5 
6  AzPainter is free software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  AzPainter is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 $*/
19 
20 /*****************************************
21  * MainWindow
22  *
23  * ファイル関連コマンド
24  *****************************************/
25 
26 #include <string.h>
27 
28 #include "mDef.h"
29 #include "mStr.h"
30 #include "mUtilFile.h"
31 #include "mMenu.h"
32 #include "mIconButtons.h"
33 #include "mMessageBox.h"
34 #include "mSysDialog.h"
35 #include "mTrans.h"
36 
37 #include "defMacros.h"
38 #include "defDraw.h"
39 #include "defConfig.h"
40 #include "defMainWindow.h"
41 #include "defFileFormat.h"
42 #include "AppErr.h"
43 
44 #define LOADERR_DEFINE
45 #include "defLoadErr.h"
46 
47 #include "defMainWindow.h"
48 #include "MainWindow.h"
49 #include "MainWindow_pv.h"
50 #include "FileDialog.h"
51 #include "PopupThread.h"
52 #include "Undo.h"
53 
54 #include "draw_main.h"
55 #include "draw_file.h"
56 
57 #include "trgroup.h"
58 #include "trid_mainmenu.h"
59 #include "trid_message.h"
60 
61 
62 //----------------------
63 
64 mBool NewImageDialog_run(mWindow *owner,mSize *size,int *dpi,int *layertype);
65 mBool SaveOptionDlg_run(mWindow *owner,int format);
66 
67 //----------------------
68 
69 
70 
71 //============================
72 // FileFormat
73 //============================
74 
75 
76 /** ファイルのヘッダからフォーマット取得 */
77 
FileFormat_getbyFileHeader(const char * filename)78 uint32_t FileFormat_getbyFileHeader(const char *filename)
79 {
80 	uint8_t d[8],png[8] = {0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a};
81 
82 	if(mReadFileHead(filename, d, 8))
83 	{
84 		if(memcmp(d, "AZPDATA", 7) == 0)
85 		{
86 			//APD
87 
88 			if(d[7] < 2)
89 				return FILEFORMAT_APD | FILEFORMAT_APD_v1v2;
90 			else if(d[7] == 2)
91 				return FILEFORMAT_APD | FILEFORMAT_APD_v3;
92 			else
93 				return FILEFORMAT_UNKNOWN;
94 		}
95 		else if(memcmp(d, "AZDWDAT", 7) == 0)
96 			return FILEFORMAT_ADW;
97 
98 		else if(memcmp(d, "8BPS", 4) == 0)
99 			return FILEFORMAT_PSD;
100 
101 		else if(memcmp(d, png, 8) == 0)
102 			return FILEFORMAT_PNG;
103 
104 		else if(d[0] == 0xff && d[1] == 0xd8)
105 			return FILEFORMAT_JPEG;
106 
107 		else if(d[0] == 'G' && d[1] == 'I' && d[2] == 'F')
108 			return FILEFORMAT_GIF;
109 
110 		else if(d[0] == 'B' && d[1] == 'M')
111 			return FILEFORMAT_BMP;
112 	}
113 
114 	return FILEFORMAT_UNKNOWN;
115 }
116 
117 
118 //============================
119 // sub
120 //============================
121 
122 
123 /** 最近使ったファイルに追加 */
124 
_add_recent_file(MainWindow * p,const char * filename)125 static void _add_recent_file(MainWindow *p,const char *filename)
126 {
127 	mStrArrayAddRecent(APP_CONF->strRecentFile, CONFIG_RECENTFILE_NUM, filename, TRUE);
128 
129 	//メニュー
130 
131 	MainWindow_setRecentFileMenu(p);
132 }
133 
134 /** ファイル履歴のメニューをセット */
135 
MainWindow_setRecentFileMenu(MainWindow * p)136 void MainWindow_setRecentFileMenu(MainWindow *p)
137 {
138 	mMenu *menu = p->menu_recentfile;
139 
140 	//削除
141 
142 	mMenuDeleteAll(menu);
143 
144 	//ファイル
145 
146 	mMenuSetStrArray(menu, MAINWINDOW_CMDID_RECENTFILE,
147 		APP_CONF->strRecentFile, CONFIG_RECENTFILE_NUM);
148 
149 	//消去
150 
151 	if(!mStrIsEmpty(APP_CONF->strRecentFile))
152 	{
153 		mMenuAddSep(menu);
154 
155 		mMenuAddText_static(menu, TRMENU_FILE_RECENTFILE_CLEAR,
156 			M_TR_T2(TRGROUP_MAINMENU, TRMENU_FILE_RECENTFILE_CLEAR));
157 	}
158 }
159 
160 /** ツールバーの開く/保存ドロップメニュー
161  *
162  * @return 選択された履歴の番号。-1 でキャンセル */
163 
MainWindow_runMenu_toolbarDrop_opensave(MainWindow * p,mBool save)164 int MainWindow_runMenu_toolbarDrop_opensave(MainWindow *p,mBool save)
165 {
166 	mMenu *menu;
167 	mMenuItemInfo *mi;
168 	mStr *str_array;
169 	mBox box;
170 	int no;
171 
172 	str_array = (save)? APP_CONF->strRecentSaveDir: APP_CONF->strRecentOpenDir;
173 
174 	//履歴が一つもない (先頭が空)
175 
176 	if(mStrIsEmpty(str_array)) return -1;
177 
178 	//メニュー
179 
180 	menu = mMenuNew();
181 
182 	mMenuSetStrArray(menu, 0, str_array, CONFIG_RECENTDIR_NUM);
183 
184 	mIconButtonsGetItemBox(M_ICONBUTTONS(p->toolbar),
185 		(save)? TRMENU_FILE_SAVE_AS: TRMENU_FILE_OPEN, &box, TRUE);
186 
187 	mi = mMenuPopup(menu, NULL, box.x, box.y + box.h, 0);
188 	no = (mi)? mi->id: -1;
189 
190 	mMenuDestroy(menu);
191 
192 	return no;
193 }
194 
195 /** 複製保存のドロップメニュー
196  *
197  * @return 選択された履歴の番号。-1 でキャンセル */
198 
MainWindow_runMenu_toolbarDrop_savedup(MainWindow * p)199 int MainWindow_runMenu_toolbarDrop_savedup(MainWindow *p)
200 {
201 	mMenu *menu,*sub;
202 	mMenuItemInfo *mi;
203 	mBox box;
204 	int no,i;
205 	static const char *format_str[] = {
206 		"APD (AzPainter)", "PSD (PhotoShop)", "PNG", "JPEG", "BMP"
207 	};
208 
209 	M_TR_G(TRGROUP_DROPMENU_SAVEDUP);
210 
211 	//保存形式サブメニュー
212 
213 	sub = mMenuNew();
214 
215 	mMenuAddNormal(sub, 1000, M_TR_T(1), 0, MMENUITEM_F_RADIO);
216 
217 	for(i = 0; i < 5; i++)
218 		mMenuAddNormal(sub, 1001 + i, format_str[i], 0, MMENUITEM_F_RADIO);
219 
220 	mMenuSetCheck(sub, 1000 + APP_CONF->savedup_type, 1);
221 
222 	//main
223 
224 	menu = mMenuNew();
225 
226 	mMenuAddSubmenu(menu, 100, M_TR_T(0), sub);
227 	mMenuAddSep(menu);
228 	mMenuAddStrArray(menu, 0, APP_CONF->strRecentSaveDir, CONFIG_RECENTDIR_NUM);
229 
230 	//
231 
232 	mIconButtonsGetItemBox(M_ICONBUTTONS(p->toolbar),
233 		TRMENU_FILE_SAVE_DUP, &box, TRUE);
234 
235 	mi = mMenuPopup(menu, NULL, box.x, box.y + box.h, 0);
236 	no = (mi)? mi->id: -1;
237 
238 	mMenuDestroy(menu);
239 
240 	//保存形式変更
241 
242 	if(no >= 1000)
243 	{
244 		APP_CONF->savedup_type = no - 1000;
245 		return -1;
246 	}
247 
248 	return no;
249 }
250 
251 /** ツールバーのファイル履歴メニュー */
252 
MainWindow_runMenu_toolbar_recentfile(MainWindow * p)253 void MainWindow_runMenu_toolbar_recentfile(MainWindow *p)
254 {
255 	mBox box;
256 
257 	//履歴が一つもない (先頭が空)
258 
259 	if(mStrIsEmpty(APP_CONF->strRecentFile)) return;
260 
261 	//メニュー (COMMAND イベントを送る)
262 
263 	mIconButtonsGetItemBox(M_ICONBUTTONS(p->toolbar),
264 		TRMENU_FILE_RECENTFILE, &box, TRUE);
265 
266 	mMenuPopup(p->menu_recentfile, M_WIDGET(p), box.x, box.y + box.h, 0);
267 }
268 
269 
270 //============================
271 // 新規作成
272 //============================
273 
274 
275 /** 新規作成 */
276 
MainWindow_newImage(MainWindow * p)277 void MainWindow_newImage(MainWindow *p)
278 {
279 	mSize size;
280 	int dpi,type;
281 
282 	//ダイアログ
283 
284 	if(!NewImageDialog_run(M_WINDOW(p), &size, &dpi, &type))
285 		return;
286 
287 	//保存確認
288 
289 	if(!MainWindow_confirmSave(p)) return;
290 
291 	//新規
292 
293 	if(!drawImage_new(APP_DRAW, size.w, size.h, dpi, type))
294 	{
295 		MainWindow_apperr(APPERR_ALLOC, NULL);
296 
297 		drawImage_new(APP_DRAW, 300, 300, dpi, type);
298 	}
299 
300 	//更新
301 
302 	MainWindow_updateNewCanvas(p, "");
303 }
304 
305 
306 //============================
307 // ファイルを開く
308 //============================
309 
310 
311 typedef struct
312 {
313 	const char *filename;
314 	char *errmes;	//確保されたエラー文字列
315 	int loaderr,	//LOADERR_*
316 		loadopt;	//開くダイアログ時のオプション
317 	uint32_t format;
318 }_thread_openfileinfo;
319 
320 
321 /** 読み込みスレッド処理 */
322 /*
323  * 戻り値が APPERR_OK で成功。それ以外の場合エラー。
324  * loaderr に LOADERR_OK 以外をセットすると、定義されたエラー文字列表示。
325  */
326 
_thread_load(mPopupProgress * prog,void * data)327 static int _thread_load(mPopupProgress *prog,void *data)
328 {
329 	_thread_openfileinfo *p = (_thread_openfileinfo *)data;
330 	uint32_t format;
331 	int ret = APPERR_LOAD,loaderr = -100;
332 
333 	format = p->format;
334 
335 	if(format & FILEFORMAT_APD)
336 	{
337 		//APD
338 
339 		if(format & FILEFORMAT_APD_v3)
340 		{
341 			//ver 3
342 			if(drawFile_load_apd_v3(APP_DRAW, p->filename, prog))
343 				ret = APPERR_OK;
344 		}
345 		else
346 			//ver 1,2
347 			loaderr = drawFile_load_apd_v1v2(p->filename, prog);
348 	}
349 	else if(format & FILEFORMAT_ADW)
350 		//ADW
351 		loaderr = drawFile_load_adw(p->filename, prog);
352 	else if(format & FILEFORMAT_PSD)
353 	{
354 		//PSD
355 
356 		if(drawFile_load_psd(APP_DRAW, p->filename, prog, &p->errmes))
357 			ret= APPERR_OK;
358 	}
359 	else
360 	{
361 		//画像ファイル
362 
363 		ret = drawImage_loadFile(APP_DRAW, p->filename, p->format,
364 			FILEDIALOG_LAYERIMAGE_IS_IGNORE_ALPHA(p->loadopt),
365 			prog, &p->errmes);
366 	}
367 
368 	//loaderr に戻り値がある場合、
369 	//関数の戻り値と loaderr セット
370 
371 	if(loaderr != -100)
372 	{
373 		if(loaderr == LOADERR_OK)
374 			ret = APPERR_OK;
375 		else
376 		{
377 			p->loaderr = loaderr;
378 			ret = APPERR_LOAD;
379 		}
380 	}
381 
382 	return ret;
383 }
384 
385 /** ファイルを開く (ダイアログ)
386  *
387  * @param recentno  ディレクトリ履歴番号 (0 で最新の履歴) */
388 
MainWindow_openFile(MainWindow * p,int recentno)389 void MainWindow_openFile(MainWindow *p,int recentno)
390 {
391 	mStr str = MSTR_INIT;
392 	int ret;
393 
394 	//ファイル名
395 
396 	ret = FileDialog_openLayerImage(M_WINDOW(p),
397 		"Image Files (ADW/APD/PSD/BMP/PNG/JPEG/GIF)\t*.adw;*.apd;*.psd;*.bmp;*.png;*.jpg;*.jpeg;*.gif\t"
398 		"AzPainter File (*.apd)\t*.apd\t"
399 		"All Files\t*",
400 		APP_CONF->strRecentOpenDir[recentno].buf, &str);
401 
402 	if(ret == -1) return;
403 
404 	//保存確認後、読み込み
405 
406 	if(MainWindow_confirmSave(p))
407 		MainWindow_loadImage(p, str.buf, ret);
408 
409 	mStrFree(&str);
410 }
411 
412 /** 画像読み込み処理
413  *
414  * @param loadopt 開くダイアログからのオプション (0 でデフォルト) */
415 
MainWindow_loadImage(MainWindow * p,const char * filename,int loadopt)416 mBool MainWindow_loadImage(MainWindow *p,const char *filename,int loadopt)
417 {
418 	_thread_openfileinfo dat;
419 	int err;
420 	uint32_t format;
421 
422 	//ヘッダからフォーマット取得
423 
424 	format = FileFormat_getbyFileHeader(filename);
425 
426 	if(format == FILEFORMAT_UNKNOWN)
427 	{
428 		MainWindow_apperr(APPERR_UNSUPPORTED_FORMAT, NULL);
429 		return FALSE;
430 	}
431 
432 	//読み込み
433 
434 	dat.filename = filename;
435 	dat.format = format;
436 	dat.errmes = NULL;
437 	dat.loaderr = LOADERR_OK;
438 	dat.loadopt = loadopt;
439 
440 	err = PopupThread_run(&dat, _thread_load);
441 	if(err == -1) return FALSE;
442 
443 	//結果
444 
445 	if(err == APPERR_OK)
446 	{
447 		//---- 成功
448 
449 		mStr str = MSTR_INIT;
450 
451 		//フォーマット
452 
453 		p->fileformat = format;
454 
455 		//ファイル履歴追加
456 		/* filename が履歴内の文字列の場合があるので、以降
457 		 * ファイル名を参照する場合は、ファイル履歴の先頭を参照すること。 */
458 
459 		_add_recent_file(p, filename);
460 
461 		//ディレクトリ履歴
462 
463 		mStrPathGetDir(&str, APP_CONF->strRecentFile[0].buf);
464 
465 		mStrArrayAddRecent(APP_CONF->strRecentOpenDir, CONFIG_RECENTDIR_NUM, str.buf, TRUE);
466 
467 		mStrFree(&str);
468 
469 		//更新
470 
471 		MainWindow_updateNewCanvas(p, APP_CONF->strRecentFile[0].buf);
472 
473 		return TRUE;
474 	}
475 	else
476 	{
477 		//---- 失敗
478 
479 		//エラーメッセージ
480 
481 		if(dat.errmes)
482 		{
483 			MainWindow_apperr(err, dat.errmes);
484 			mFree(dat.errmes);
485 		}
486 		else if(dat.loaderr != LOADERR_OK)
487 			MainWindow_apperr(err, g_loaderr_str[dat.loaderr]);
488 
489 		/* レイヤが一つもなければ新規作成。
490 		 * カレントレイヤが指定されていなければ途中まで読み込まれた */
491 
492 		if(drawImage_onLoadError(APP_DRAW))
493 			MainWindow_updateNewCanvas(p, filename);
494 
495 		return FALSE;
496 	}
497 }
498 
499 
500 //============================
501 // ファイル保存 sub
502 //============================
503 
504 
505 enum
506 {
507 	FILETYPE_APD,
508 	FILETYPE_PSD,
509 	FILETYPE_PNG,
510 	FILETYPE_JPEG,
511 	FILETYPE_BMP
512 };
513 
514 
515 /** フォーマットフラグからファイル名に拡張子セット */
516 
_save_set_ext(mStr * str,uint32_t format)517 static void _save_set_ext(mStr *str,uint32_t format)
518 {
519 	uint32_t flag[] = {
520 		FILEFORMAT_APD, FILEFORMAT_PSD, FILEFORMAT_PNG,
521 		FILEFORMAT_JPEG, FILEFORMAT_BMP, 0
522 	};
523 	const char *ext[] = {
524 		"apd", "psd", "png", "jpg", "bmp"
525 	};
526 	int i;
527 
528 	for(i = 0; flag[i]; i++)
529 	{
530 		if(format & flag[i])
531 		{
532 			mStrPathSetExt(str, ext[i]);
533 			break;
534 		}
535 	}
536 }
537 
538 /** フォーマットフラグからファイルタイプ取得 */
539 
_save_format_to_type(uint32_t format)540 static int _save_format_to_type(uint32_t format)
541 {
542 	uint32_t flag[] = {
543 		FILEFORMAT_APD, FILEFORMAT_PSD, FILEFORMAT_PNG,
544 		FILEFORMAT_JPEG, FILEFORMAT_BMP, 0
545 	};
546 	int i;
547 
548 	for(i = 0; flag[i]; i++)
549 	{
550 		if(format & flag[i])
551 			return i;
552 	}
553 
554 	return FILETYPE_APD;
555 }
556 
557 /** 上書き保存時のメッセージ
558  *
559  * @return [0]キャンセル [1]上書き保存 [2]別名保存 */
560 
_save_message(MainWindow * p)561 static int _save_message(MainWindow *p)
562 {
563 	uint32_t ret;
564 
565 	//ADW/GIF 形式での上書き保存は不可 => 別名保存
566 
567 	if(p->fileformat & (FILEFORMAT_ADW | FILEFORMAT_GIF))
568 		return 2;
569 
570 	//APD 以外の場合、確認
571 
572 	if(!(p->fileformat & FILEFORMAT_APD)
573 		&& (APP_CONF->optflags & CONFIG_OPTF_MES_SAVE_APD))
574 	{
575 		ret = mMessageBox(M_WINDOW(p), NULL, M_TR_T2(TRGROUP_MESSAGE, TRID_MES_SAVE_APD),
576 			MMESBOX_YES | MMESBOX_CANCEL | MMESBOX_NOTSHOW, MMESBOX_CANCEL);
577 
578 		//メッセージ表示しない
579 
580 		if(ret & MMESBOX_NOTSHOW)
581 			APP_CONF->optflags ^= CONFIG_OPTF_MES_SAVE_APD;
582 
583 		return (ret & MMESBOX_YES)? 1: 0;
584 	}
585 
586 	//上書き保存メッセージ
587 
588 	if(APP_CONF->optflags & CONFIG_OPTF_MES_SAVE_OVERWRITE)
589 	{
590 		mStr str = MSTR_INIT;
591 
592 		mStrPathGetFileName(&str, p->strFilename.buf);
593 		mStrAppendText(&str, "\n\n");
594 		mStrAppendText(&str, M_TR_T2(TRGROUP_MESSAGE, TRID_MES_SAVE_OVERWRITE));
595 
596 		ret = mMessageBox(M_WINDOW(p), NULL, str.buf,
597 			MMESBOX_SAVE | MMESBOX_CANCEL | MMESBOX_NOTSHOW, MMESBOX_SAVE);
598 
599 		mStrFree(&str);
600 
601 		//メッセージ表示しない
602 
603 		if(ret & MMESBOX_NOTSHOW)
604 			APP_CONF->optflags ^= CONFIG_OPTF_MES_SAVE_OVERWRITE;
605 
606 		//キャンセル
607 
608 		if(!(ret & MMESBOX_SAVE))
609 			return 0;
610 	}
611 
612 	return 1;
613 }
614 
615 /** ファイル名とフォーマットを取得
616  *
617  * @return 保存フォーマット。-1 でキャンセル、-2 で上書き保存 */
618 
_save_get_path_and_format(MainWindow * p,mStr * strpath,int savetype,int recentno)619 static int _save_get_path_and_format(MainWindow *p,
620 	mStr *strpath,int savetype,int recentno)
621 {
622 	int ret,type,format;
623 	int type_to_format[] = {
624 		FILEFORMAT_APD, FILEFORMAT_PSD, FILEFORMAT_PNG,
625 		FILEFORMAT_JPEG, FILEFORMAT_BMP
626 	};
627 
628 	//-------- 上書き保存
629 	/* 新規状態、または上書きできない場合は別名保存へ */
630 
631 	if(savetype == MAINWINDOW_SAVEFILE_OVERWRITE && !mStrIsEmpty(&p->strFilename))
632 	{
633 		ret = _save_message(p);
634 
635 		if(ret == 0)
636 			//キャンセル
637 			return -1;
638 		else if(ret == 1)
639 		{
640 			//上書き保存
641 
642 			mStrCopy(strpath, &p->strFilename);
643 			return -2;
644 		}
645 	}
646 
647 	//------- 別名保存、複製保存
648 
649 	//初期ファイル名
650 
651 	if(!mStrIsEmpty(&p->strFilename))
652 		mStrPathGetFileNameNoExt(strpath, p->strFilename.buf);
653 
654 	//種類の初期選択
655 
656 	type = FILETYPE_APD;
657 
658 	if(savetype == MAINWINDOW_SAVEFILE_DUP)
659 	{
660 		//複製時は指定フォーマット
661 
662 		if(APP_CONF->savedup_type == 0)
663 		{
664 			//現在のファイルと同じ
665 
666 			if(!mStrIsEmpty(&p->strFilename))
667 				type = _save_format_to_type(p->fileformat);
668 		}
669 		else
670 			type = APP_CONF->savedup_type - 1;
671 	}
672 
673 	//ダイアログ
674 
675 	ret = mSysDlgSaveFile(M_WINDOW(p),
676 		"AzPainter (*.apd)\t*.apd\t"
677 		"PhotoShop (*.psd)\t*.psd\t"
678 		"PNG (*.png)\t*.png\t"
679 		"JPEG (*.jpg)\t*.jpg\t"
680 		"BMP (*.bmp)\t*.bmp\t",
681 		type, APP_CONF->strRecentSaveDir[recentno].buf, 0, strpath, &type);
682 
683 	if(!ret) return -1;
684 
685 	//フォーマット取得
686 
687 	format = type_to_format[type];
688 
689 	//拡張子セット
690 
691 	_save_set_ext(strpath, format);
692 
693 	return format;
694 }
695 
696 
697 //============================
698 // ファイル保存 main
699 //============================
700 
701 
702 typedef struct
703 {
704 	const char *filename;
705 	uint32_t format;
706 }_thdata_save;
707 
708 
709 /** 保存スレッド処理 */
710 
_thread_save(mPopupProgress * prog,void * data)711 static int _thread_save(mPopupProgress *prog,void *data)
712 {
713 	_thdata_save *p = (_thdata_save *)data;
714 	int ret;
715 	uint32_t format;
716 
717 	format = p->format;
718 
719 	//PNG + ALPHA
720 
721 	if((format & FILEFORMAT_PNG)
722 		&& (APP_CONF->save.flags & CONFIG_SAVEOPTION_F_PNG_ALPHA_CHANNEL))
723 		format |= FILEFORMAT_ALPHA_CHANNEL;
724 
725 	//
726 
727 	if(format & FILEFORMAT_APD)
728 	{
729 		//----- APD v3
730 
731 		ret = drawFile_save_apd_v3(APP_DRAW, p->filename, prog);
732 	}
733 	else if(format & FILEFORMAT_PSD)
734 	{
735 		//----- PSD
736 
737 		if(!drawImage_blendImage_RGB8(APP_DRAW))
738 			return FALSE;
739 
740 		if(APP_CONF->save.psd_type == 0)
741 			//レイヤ維持
742 			ret = drawFile_save_psd_layer(APP_DRAW, p->filename, prog);
743 		else
744 		{
745 			//1枚絵
746 			ret = drawFile_save_psd_image(APP_DRAW, APP_CONF->save.psd_type,
747 				p->filename, prog);
748 		}
749 
750 		drawUpdate_blendImage_full(APP_DRAW);
751 	}
752 	else
753 	{
754 		//----- PNG/JPEG/BMP
755 
756 		if(format & FILEFORMAT_ALPHA_CHANNEL)
757 			//RGBA8
758 			drawImage_blendImage_RGBA8(APP_DRAW);
759 		else
760 		{
761 			//RGB8
762 
763 			if(!drawImage_blendImage_RGB8(APP_DRAW))
764 				return FALSE;
765 		}
766 
767 		ret = drawFile_save_image(APP_DRAW, p->filename, format, prog);
768 
769 		drawUpdate_blendImage_full(APP_DRAW);
770 	}
771 
772 	return ret;
773 }
774 
775 /** ファイル保存
776  *
777  * @param savetype [0]上書き保存 [1]別名保存 [2]複製保存
778  * @param recentno ディレクトリ履歴番号
779  * @param FALSE でキャンセルされた */
780 
MainWindow_saveFile(MainWindow * p,int savetype,int recentno)781 mBool MainWindow_saveFile(MainWindow *p,int savetype,int recentno)
782 {
783 	mStr str = MSTR_INIT,strdir = MSTR_INIT;
784 	uint32_t format;
785 	int ret;
786 	_thdata_save dat;
787 
788 	//パスとフォーマット取得
789 
790 	ret = _save_get_path_and_format(p, &str, savetype, recentno);
791 	if(ret == -1)
792 	{
793 		mStrFree(&str);
794 		return FALSE;
795 	}
796 
797 	format = (ret == -2)? p->fileformat: ret;
798 
799 	//保存設定 (PNG/JPEG/PSD)
800 	/* 上書き保存で、開いた後一度保存されている場合を除いて保存設定を行う。 */
801 
802 	if(!(ret == -2 && p->saved)
803 		&& (format & (FILEFORMAT_PNG | FILEFORMAT_JPEG | FILEFORMAT_PSD)))
804 	{
805 		if(!SaveOptionDlg_run(M_WINDOW(p), format))
806 		{
807 			mStrFree(&str);
808 			return FALSE;
809 		}
810 	}
811 
812 	//スレッド
813 
814 	dat.filename = str.buf;
815 	dat.format = format;
816 
817 	ret = PopupThread_run(&dat, _thread_save);
818 
819 	//失敗
820 
821 	if(ret != 1)
822 	{
823 		MainWindow_apperr(APPERR_FAILED, NULL);
824 
825 		mStrFree(&str);
826 		return TRUE;
827 	}
828 
829 	//----- 成功
830 
831 	//編集ファイル情報
832 
833 	if(savetype != MAINWINDOW_SAVEFILE_DUP)
834 	{
835 		mStrCopy(&p->strFilename, &str);
836 
837 		p->fileformat = format;
838 		p->saved = TRUE;
839 
840 		//タイトル
841 
842 		MainWindow_setTitle(p);
843 
844 		//undo データ変更フラグ OFF
845 
846 		Undo_clearUpdateFlag();
847 	}
848 
849 	//ファイル履歴
850 
851 	_add_recent_file(p, str.buf);
852 
853 	//ディレクトリ履歴
854 
855 	mStrPathGetDir(&strdir, str.buf);
856 
857 	mStrArrayAddRecent(APP_CONF->strRecentSaveDir, CONFIG_RECENTDIR_NUM, strdir.buf, TRUE);
858 
859 	//
860 
861 	mStrFree(&str);
862 	mStrFree(&strdir);
863 
864 	return TRUE;
865 }
866