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