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  * カラーパレットデータ
22  ***************************/
23 /*
24  * 内容が変更されたときは ColorPalette::exit_save を TRUE にして、
25  * 終了時に保存されるようにする。
26  */
27 
28 #include <string.h>
29 #include <stdio.h>
30 
31 #include "mDef.h"
32 #include "mStr.h"
33 #include "mGui.h"
34 #include "mUtilStdio.h"
35 
36 #include "defMacros.h"
37 
38 #include "ColorPalette.h"
39 
40 
41 //--------------------
42 
43 static ColorPalette g_colpal_body;
44 
45 ColorPalette *g_colorpalette = &g_colpal_body;
46 
47 #define _BODY  g_colpal_body
48 
49 //--------------------
50 
51 
52 
53 //==================================
54 // sub
55 //==================================
56 
57 
58 /** 設定ファイル開く */
59 
_open_configfile(const char * fname,mBool write)60 static FILE *_open_configfile(const char *fname,mBool write)
61 {
62 	mStr str = MSTR_INIT;
63 	FILE *fp;
64 
65 	mAppGetConfigPath(&str, fname);
66 
67 	fp = mFILEopenUTF8(str.buf, (write)? "wb": "rb");
68 
69 	mStrFree(&str);
70 
71 	return fp;
72 }
73 
74 /** 設定ファイルから読み込み */
75 
_load_configfile()76 static void _load_configfile()
77 {
78 	FILE *fp;
79 	ColorPaletteDat *ppal;
80 	uint8_t ver,tabnum;
81 	uint16_t num;
82 	int i;
83 
84 	//開く
85 
86 	fp = _open_configfile(CONFIG_FILENAME_COLPALETTE, FALSE);
87 	if(!fp) return;
88 
89 	//ヘッダ
90 
91 	if(!mFILEreadCompareStr(fp, "AZPLPLD")
92 		|| !mFILEreadByte(fp, &ver)
93 		|| ver != 1
94 		|| !mFILEreadByte(fp, &tabnum))
95 	{
96 		fclose(fp);
97 		return;
98 	}
99 
100 	if(tabnum > COLORPALETTE_NUM)
101 		tabnum = COLORPALETTE_NUM;
102 
103 	//パレットデータ
104 
105 	ppal = _BODY.pal;
106 
107 	for(i = 0; i < tabnum; i++, ppal++)
108 	{
109 		//個数 (データなし、または 0 で終端)
110 
111 		if(!mFILEread16LE(fp, &num) || num == 0 || num > COLORPALETTEDAT_MAXNUM)
112 			break;
113 
114 		//確保
115 
116 		if(!ColorPaletteDat_alloc(ppal, num)) break;
117 
118 		//データ
119 
120 		if(fread(ppal->buf, 1, num * 3, fp) != num * 3)
121 			break;
122 	}
123 
124 	fclose(fp);
125 }
126 
127 
128 //===============================
129 // ColorPalette (メインデータ)
130 //===============================
131 
132 
133 /** 初期化 */
134 
ColorPalette_init()135 void ColorPalette_init()
136 {
137 	memset(g_colorpalette, 0, sizeof(ColorPalette));
138 }
139 
140 /** 解放 */
141 
ColorPalette_free()142 void ColorPalette_free()
143 {
144 	int i;
145 
146 	for(i = 0; i < COLORPALETTE_NUM; i++)
147 		ColorPaletteDat_free(_BODY.pal + i);
148 }
149 
150 /** 設定ファイル読み込み */
151 
ColorPalette_load()152 void ColorPalette_load()
153 {
154 	ColorPaletteDat *p;
155 	int i;
156 
157 	//ファイル読み込み
158 
159 	_load_configfile();
160 
161 	//確保されていないパレットを作成
162 
163 	p = _BODY.pal;
164 
165 	for(i = 0; i < COLORPALETTE_NUM; i++, p++)
166 	{
167 		if(!p->buf)
168 		{
169 			if(ColorPaletteDat_alloc(p, (i == 0)? 128: 64))
170 				ColorPaletteDat_fillWhite(p);
171 		}
172 	}
173 }
174 
175 /** 設定ファイル書き込み */
176 
ColorPalette_savefile()177 void ColorPalette_savefile()
178 {
179 	FILE *fp;
180 	ColorPaletteDat *ppal;
181 	int i;
182 
183 	//データが変更された時のみ
184 
185 	if(!_BODY.exit_save) return;
186 
187 	//開く
188 
189 	fp = _open_configfile(CONFIG_FILENAME_COLPALETTE, TRUE);
190 	if(!fp) return;
191 
192 	//ヘッダ
193 
194 	fputs("AZPLPLD", fp);
195 
196 	mFILEwriteByte(fp, 1);
197 	mFILEwriteByte(fp, COLORPALETTE_NUM);
198 
199 	//パレットデータ
200 
201 	ppal = _BODY.pal;
202 
203 	for(i = 0; i < COLORPALETTE_NUM; i++, ppal++)
204 	{
205 		//個数
206 
207 		mFILEwrite16LE(fp, ppal->num);
208 
209 		//データ
210 
211 		fwrite(ppal->buf, 1, ppal->num * 3, fp);
212 	}
213 
214 	fclose(fp);
215 }
216 
217 /** ver.1 の設定データを変換 */
218 
ColorPalette_convert_from_ver1()219 void ColorPalette_convert_from_ver1()
220 {
221 	FILE *fpin,*fpout;
222 	uint8_t ver,tabnum,*buf,*ps,*pd,r,g,b;
223 	uint16_t num;
224 	int i,j,size;
225 
226 	//読み込み
227 
228 	fpin = _open_configfile("palette.dat", FALSE);
229 	if(!fpin) return;
230 
231 	if(!mFILEreadCompareStr(fpin, "AZPLPLD")
232 		|| !mFILEreadByte(fpin, &ver)
233 		|| ver != 0
234 		|| !mFILEreadByte(fpin, &tabnum))
235 	{
236 		fclose(fpin);
237 		return;
238 	}
239 
240 	if(tabnum > COLORPALETTE_NUM)
241 		tabnum = COLORPALETTE_NUM;
242 
243 	//書き込み
244 
245 	fpout = _open_configfile(CONFIG_FILENAME_COLPALETTE, TRUE);
246 	if(!fpout)
247 	{
248 		fclose(fpin);
249 		return;
250 	}
251 
252 	fputs("AZPLPLD", fpout);
253 	mFILEwriteByte(fpout, 1);
254 	mFILEwriteByte(fpout, tabnum);
255 
256 	//パレットデータ
257 
258 	for(i = 0; i < tabnum; i++)
259 	{
260 		//個数 (データなし、または 0 で終端)
261 
262 		if(!mFILEread16LE(fpin, &num) || num == 0 || num > COLORPALETTEDAT_MAXNUM)
263 			break;
264 
265 		//データ読み込み
266 
267 		size = num << 2;
268 
269 		buf = (uint8_t *)mMalloc(size, FALSE);
270 		if(!buf) break;
271 
272 		if(fread(buf, 1, size, fpin) != size)
273 		{
274 			mFree(buf);
275 			break;
276 		}
277 
278 		//ver.2 のデータに変換 (BGRA -> RGB)
279 
280 		ps = pd = buf;
281 
282 		for(j = num; j; j--, ps += 4, pd += 3)
283 		{
284 			r = ps[2], g = ps[1], b = ps[0];
285 			pd[0] = r, pd[1] = g, pd[2] = b;
286 		}
287 
288 		//書き込み
289 
290 		fwrite(&num, 1, 2, fpout);
291 		fwrite(buf, 1, num * 3, fpout);
292 
293 		mFree(buf);
294 	}
295 
296 	fclose(fpin);
297 	fclose(fpout);
298 }
299 
300 
301 
302 //===============================
303 // ColorPaletteDat (各データ)
304 //===============================
305 
306 
307 
308 /** バッファサイズ変更 */
309 
_resize_pal(ColorPaletteDat * p,int num)310 static mBool _resize_pal(ColorPaletteDat *p,int num)
311 {
312 	uint8_t *pbuf;
313 
314 	pbuf = mRealloc(p->buf, num * 3);
315 	if(!pbuf) return FALSE;
316 
317 	p->buf = pbuf;
318 	p->num = num;
319 
320 	return TRUE;
321 }
322 
323 
324 
325 /** 解放 */
326 
ColorPaletteDat_free(ColorPaletteDat * p)327 void ColorPaletteDat_free(ColorPaletteDat *p)
328 {
329 	if(p->buf)
330 	{
331 		mFree(p->buf);
332 		p->buf = NULL;
333 		p->num = 0;
334 	}
335 }
336 
337 /** バッファ確保 */
338 
ColorPaletteDat_alloc(ColorPaletteDat * p,int num)339 mBool ColorPaletteDat_alloc(ColorPaletteDat *p,int num)
340 {
341 	ColorPaletteDat_free(p);
342 
343 	if(num < 1)
344 		num = 1;
345 	else if(num > COLORPALETTEDAT_MAXNUM)
346 		num = COLORPALETTEDAT_MAXNUM;
347 
348 	p->buf = (uint8_t *)mMalloc(num * 3, FALSE);
349 	if(!p->buf) return FALSE;
350 
351 	p->num = num;
352 
353 	return TRUE;
354 }
355 
356 /** サイズ変更 */
357 
ColorPaletteDat_resize(ColorPaletteDat * p,int num)358 mBool ColorPaletteDat_resize(ColorPaletteDat *p,int num)
359 {
360 	int num_src;
361 
362 	num_src = p->num;
363 
364 	//リサイズ
365 
366 	if(!_resize_pal(p, num))
367 		return FALSE;
368 
369 	//増えた分をクリア
370 
371 	if(num > num_src)
372 		memset(p->buf + num_src * 3, 255, (num - num_src) * 3);
373 
374 	_BODY.exit_save = TRUE;
375 
376 	return TRUE;
377 }
378 
379 /** 白で埋める */
380 
ColorPaletteDat_fillWhite(ColorPaletteDat * p)381 void ColorPaletteDat_fillWhite(ColorPaletteDat *p)
382 {
383 	memset(p->buf, 255, p->num * 3);
384 }
385 
386 /** RGB 値を取得 */
387 
ColorPaletteDat_getColor(ColorPaletteDat * p,int no)388 uint32_t ColorPaletteDat_getColor(ColorPaletteDat *p,int no)
389 {
390 	uint8_t *buf;
391 
392 	buf = p->buf + no * 3;
393 
394 	return M_RGB(buf[0], buf[1], buf[2]);
395 }
396 
397 /** RGB 値をセット */
398 
ColorPaletteDat_setColor(ColorPaletteDat * p,int no,uint32_t col)399 void ColorPaletteDat_setColor(ColorPaletteDat *p,int no,uint32_t col)
400 {
401 	uint8_t *buf = p->buf + no * 3;
402 
403 	buf[0] = M_GET_R(col);
404 	buf[1] = M_GET_G(col);
405 	buf[2] = M_GET_B(col);
406 
407 	_BODY.exit_save = TRUE;
408 }
409 
410 /** 指定間をグラデーション */
411 
ColorPaletteDat_gradation(ColorPaletteDat * p,int no1,int no2)412 void ColorPaletteDat_gradation(ColorPaletteDat *p,int no1,int no2)
413 {
414 	int i,j,len;
415 	uint8_t *p1,*p2,*pd;
416 	double d;
417 
418 	if(no1 > no2)
419 		i = no1, no1 = no2, no2 = i;
420 
421 	len = no2 - no1;
422 	if(len < 2) return;
423 
424 	//
425 
426 	p1 = p->buf + no1 * 3;
427 	p2 = p->buf + no2 * 3;
428 	pd = p1 + 3;
429 
430 	for(i = 1; i < len; i++, pd += 3)
431 	{
432 		d = (double)i / len;
433 
434 		for(j = 0; j < 3; j++)
435 			pd[j] = (int)((p2[j] - p1[j]) * d + p1[j] + 0.5);
436 	}
437 
438 	_BODY.exit_save = TRUE;
439 }
440 
441 /** 24bit 画像からパレット作成 */
442 
ColorPaletteDat_createFromImage(ColorPaletteDat * p,uint8_t * buf,int w,int h)443 void ColorPaletteDat_createFromImage(ColorPaletteDat *p,uint8_t *buf,int w,int h)
444 {
445 	uint32_t *palbuf,*pp,col;
446 	int num,ix,iy,i;
447 
448 	//作業用に最大数分を確保
449 
450 	palbuf = (uint32_t *)mMalloc(COLORPALETTEDAT_MAXNUM * 4, FALSE);
451 	if(!palbuf) return;
452 
453 	//取得
454 
455 	num = 0;
456 
457 	for(iy = h; iy; iy--)
458 	{
459 		for(ix = w; ix; ix--, buf += 3)
460 		{
461 			col = M_RGB(buf[0], buf[1], buf[2]);
462 
463 			//パレットにあるか
464 
465 			for(i = num, pp = palbuf; i; i--, pp++)
466 			{
467 				if(*pp == col) break;
468 			}
469 
470 			//追加
471 
472 			if(i == 0)
473 			{
474 				if(num == COLORPALETTEDAT_MAXNUM) goto END;
475 
476 				palbuf[num++] = col;
477 			}
478 		}
479 	}
480 
481 END:
482 	//パレットセット
483 
484 	if(ColorPaletteDat_alloc(p, num))
485 	{
486 		buf = p->buf;
487 		pp = palbuf;
488 
489 		for(i = num; i > 0; i--, buf += 3)
490 		{
491 			col = *(pp++);
492 
493 			buf[0] = M_GET_R(col);
494 			buf[1] = M_GET_G(col);
495 			buf[2] = M_GET_B(col);
496 		}
497 
498 		_BODY.exit_save = TRUE;
499 	}
500 
501 	mFree(palbuf);
502 }
503 
504 
505 //===============================
506 // パレットファイル読み込み
507 //===============================
508 
509 
510 /** APL 読み込み (LE) */
511 
_loadpal_apl(ColorPaletteDat * p,const char * filename)512 static mBool _loadpal_apl(ColorPaletteDat *p,const char *filename)
513 {
514 	FILE *fp;
515 	uint8_t ver,c[4],*pd;
516 	uint16_t num;
517 	int i;
518 	mBool ret = FALSE;
519 
520 	fp = mFILEopenUTF8(filename, "rb");
521 	if(!fp) return FALSE;
522 
523 	//ヘッダ
524 
525 	if(!mFILEreadCompareStr(fp, "AZPPAL")
526 		|| !mFILEreadByte(fp, &ver)
527 		|| ver != 0)
528 		goto END;
529 
530 	//個数
531 
532 	if(!mFILEread16LE(fp, &num) || num == 0)
533 		goto END;
534 
535 	//確保
536 
537 	if(!ColorPaletteDat_alloc(p, num))
538 		goto END;
539 
540 	//データ
541 
542 	pd = p->buf;
543 
544 	for(i = p->num; i > 0; i--, pd += 3)
545 	{
546 		if(fread(c, 1, 4, fp) != 4) break;
547 
548 		pd[0] = c[2];
549 		pd[1] = c[1];
550 		pd[2] = c[0];
551 	}
552 
553 	ret = TRUE;
554 END:
555 	fclose(fp);
556 
557 	return ret;
558 }
559 
560 /** ACO 読み込み (BE) */
561 
_loadpal_aco(ColorPaletteDat * p,const char * filename)562 static mBool _loadpal_aco(ColorPaletteDat *p,const char *filename)
563 {
564 	FILE *fp;
565 	uint16_t ver,num,len;
566 	uint8_t dat[10],*pd;
567 	mBool ret = FALSE;
568 	int i;
569 
570 	fp = mFILEopenUTF8(filename, "rb");
571 	if(!fp) return FALSE;
572 
573 	//バージョン
574 
575 	if(!mFILEread16BE(fp, &ver)
576 		|| (ver != 1 && ver != 2))
577 		goto END;
578 
579 	//個数
580 
581 	if(!mFILEread16BE(fp, &num) || num == 0)
582 		goto END;
583 
584 	//確保
585 
586 	if(!ColorPaletteDat_alloc(p, num))
587 		goto END;
588 
589 	//データ
590 
591 	pd = p->buf;
592 
593 	for(i = p->num; i > 0; i--, pd += 3)
594 	{
595 		/* [2byte] color space (0:RGB)
596 		 * [2byte x 4] R,G,B,Z */
597 
598 		if(fread(dat, 1, 10, fp) != 10) break;
599 
600 		//ver2 時、色名をスキップ
601 
602 		if(ver == 2)
603 		{
604 			fseek(fp, 2, SEEK_CUR);
605 
606 			if(!mFILEread16BE(fp, &len)) break;
607 			fseek(fp, len << 1, SEEK_CUR);
608 		}
609 
610 		//RGB (上位バイトのみ)
611 
612 		pd[0] = dat[2];
613 		pd[1] = dat[4];
614 		pd[2] = dat[6];
615 	}
616 
617 	ret = TRUE;
618 END:
619 	fclose(fp);
620 
621 	return ret;
622 }
623 
624 /** パレットファイル読み込み (APL,ACO) */
625 
ColorPaletteDat_loadFile(ColorPaletteDat * p,const char * filename)626 mBool ColorPaletteDat_loadFile(ColorPaletteDat *p,const char *filename)
627 {
628 	mStr ext = MSTR_INIT;
629 	mBool ret;
630 
631 	//拡張子から判定
632 
633 	mStrPathGetExt(&ext, filename);
634 
635 	if(mStrCompareCaseEq(&ext, "apl"))
636 		ret = _loadpal_apl(p, filename);
637 	else if(mStrCompareCaseEq(&ext, "aco"))
638 		ret = _loadpal_aco(p, filename);
639 	else
640 		ret = FALSE;
641 
642 	mStrFree(&ext);
643 
644 	if(ret) _BODY.exit_save = TRUE;
645 
646 	return ret;
647 }
648 
649 
650 //===============================
651 // パレットファイル保存
652 //===============================
653 
654 
655 /** APL ファイルに保存 */
656 
ColorPaletteDat_saveFile_apl(ColorPaletteDat * p,const char * filename)657 mBool ColorPaletteDat_saveFile_apl(ColorPaletteDat *p,const char *filename)
658 {
659 	FILE *fp;
660 	int i;
661 	uint8_t d[4],*ps;
662 
663 	fp = mFILEopenUTF8(filename, "wb");
664 	if(!fp) return FALSE;
665 
666 	fputs("AZPPAL", fp);
667 	mFILEwriteByte(fp, 0);
668 
669 	mFILEwrite16LE(fp, p->num);
670 
671 	ps = p->buf;
672 	d[3] = 0;
673 
674 	for(i = p->num; i > 0; i--, ps += 3)
675 	{
676 		d[0] = ps[2];
677 		d[1] = ps[1];
678 		d[2] = ps[0];
679 
680 		fwrite(d, 1, 4, fp);
681 	}
682 
683 	fclose(fp);
684 
685 	return TRUE;
686 }
687 
688 /** ACO ファイルに保存 */
689 
ColorPaletteDat_saveFile_aco(ColorPaletteDat * p,const char * filename)690 mBool ColorPaletteDat_saveFile_aco(ColorPaletteDat *p,const char *filename)
691 {
692 	FILE *fp;
693 	int i;
694 	uint8_t d[10],*ps;
695 
696 	fp = mFILEopenUTF8(filename, "wb");
697 	if(!fp) return FALSE;
698 
699 	mFILEwrite16BE(fp, 1);
700 	mFILEwrite16BE(fp, p->num);
701 
702 	ps = p->buf;
703 	memset(d, 0, 10);
704 
705 	for(i = p->num; i > 0; i--, ps += 3)
706 	{
707 		d[2] = ps[0];
708 		d[4] = ps[1];
709 		d[6] = ps[2];
710 
711 		fwrite(d, 1, 10, fp);
712 	}
713 
714 	fclose(fp);
715 
716 	return TRUE;
717 }
718 
719