1 #define _XOPEN_SOURCE 600
2
3 #ifdef HAVE_CONFIG_H
4 # include <config.h>
5 #endif
6
7 #include <stdlib.h>
8 #include <stdio.h>
9 #include <string.h>
10 #include <errno.h>
11
12 #include <math.h>
13 #include <sys/types.h>
14 #include <sys/stat.h>
15 #include <unistd.h>
16 #include <fcntl.h>
17
18 #ifdef HAVE_NETINET_IN_H
19 # include <netinet/in.h>
20 #endif
21
22 #include "evas_common_private.h"
23 #include "evas_private.h"
24
25 typedef struct _PSD_Header PSD_Header;
26
27 typedef enum _PSD_Mode
28 {
29 PSD_GREYSCALE = 1,
30 PSD_INDEXED = 2,
31 PSD_RGB = 3,
32 PSD_CMYK = 4
33 } PSD_Mode;
34
35 struct _PSD_Header
36 {
37 unsigned char signature[4];
38 unsigned short version;
39 unsigned char reserved[9];
40 unsigned short channels;
41 unsigned int height;
42 unsigned int width;
43 unsigned short depth;
44
45 unsigned short channel_num;
46
47 PSD_Mode mode;
48 };
49
50 enum {
51 READ_COMPRESSED_SUCCESS,
52 READ_COMPRESSED_ERROR_FILE_CORRUPT,
53 READ_COMPRESSED_ERROR_FILE_READ_ERROR
54 };
55
56 static Eina_Bool get_compressed_channels_length(PSD_Header *Head,
57 const unsigned char *map, size_t length, size_t *position,
58 unsigned short *rle_table,
59 unsigned int *chanlen);
60
61 static int
read_ushort(const unsigned char * map,size_t length,size_t * position,unsigned short * ret)62 read_ushort(const unsigned char *map, size_t length, size_t *position, unsigned short *ret)
63 {
64 if (((*position) + 2) > length) return 0;
65 // FIXME: need to check order
66 *ret = (map[(*position) + 0] << 8) | map[(*position) + 1];
67 *position += 2;
68 return 1;
69 }
70
71 static int
read_uint(const unsigned char * map,size_t length,size_t * position,unsigned int * ret)72 read_uint(const unsigned char *map, size_t length, size_t *position, unsigned int *ret)
73 {
74 if (((*position) + 4) > length) return 0;
75 // FIXME: need to check order
76 *ret = ARGB_JOIN(map[(*position) + 0], map[(*position) + 1], map[(*position) + 2], map[(*position) + 3]);
77 *position += 4;
78 return 1;
79 }
80
81 static int
read_block(const unsigned char * map,size_t length,size_t * position,void * target,size_t size)82 read_block(const unsigned char *map, size_t length, size_t *position, void *target, size_t size)
83 {
84 if (((*position) + size) > length) return 0;
85 memcpy(target, map + *position, size);
86 *position += size;
87 return 1;
88 }
89
90 // Internal function used to get the Psd header from the current file.
91 static Eina_Bool
psd_get_header(PSD_Header * header,const unsigned char * map,size_t length,size_t * position)92 psd_get_header(PSD_Header *header, const unsigned char *map, size_t length, size_t *position)
93 {
94 unsigned short tmp;
95
96 #define CHECK_RET(Call) \
97 if (!Call) return EINA_FALSE;
98
99 CHECK_RET(read_block(map, length, position, header->signature, 4));
100 CHECK_RET(read_ushort(map, length, position, &header->version));
101 CHECK_RET(read_block(map, length, position, header->reserved, 6));
102 CHECK_RET(read_ushort(map, length, position, &header->channels));
103 CHECK_RET(read_uint(map, length, position, &header->height));
104 CHECK_RET(read_uint(map, length, position, &header->width));
105 CHECK_RET(read_ushort(map, length, position, &header->depth));
106
107 CHECK_RET(read_ushort(map, length, position, &tmp));
108 header->mode = tmp;
109
110 #undef CHECK_RET
111
112 return EINA_TRUE;
113 }
114
115
116 // Internal function used to check if the HEADER is a valid Psd header.
117 static Eina_Bool
is_psd(PSD_Header * header)118 is_psd(PSD_Header *header)
119 {
120 if (strncmp((char*)header->signature, "8BPS", 4))
121 return EINA_FALSE;
122 if (header->version != 1)
123 return EINA_FALSE;
124 if (header->channels < 1 || header->channels > 24)
125 return EINA_FALSE;
126 if (header->height < 1 || header->width < 1)
127 return EINA_FALSE;
128 if (header->depth != 1 && header->depth != 8 && header->depth != 16)
129 return EINA_FALSE;
130
131 return EINA_TRUE;
132 }
133
134 static void *
evas_image_load_file_open_psd(Eina_File * f,Eina_Stringshare * key EINA_UNUSED,Evas_Image_Load_Opts * opts EINA_UNUSED,Evas_Image_Animated * animated EINA_UNUSED,int * error EINA_UNUSED)135 evas_image_load_file_open_psd(Eina_File *f, Eina_Stringshare *key EINA_UNUSED,
136 Evas_Image_Load_Opts *opts EINA_UNUSED,
137 Evas_Image_Animated *animated EINA_UNUSED,
138 int *error EINA_UNUSED)
139 {
140 return f;
141 }
142
143 static void
evas_image_load_file_close_psd(void * loader_data EINA_UNUSED)144 evas_image_load_file_close_psd(void *loader_data EINA_UNUSED)
145 {
146 }
147
148 static Eina_Bool
evas_image_load_file_head_psd(void * loader_data,Emile_Image_Property * prop,int * error)149 evas_image_load_file_head_psd(void *loader_data,
150 Emile_Image_Property *prop,
151 int *error)
152 {
153 Eina_File *f = loader_data;
154 void *map;
155 size_t length;
156 size_t position;
157 PSD_Header header;
158 Eina_Bool correct;
159 Eina_Bool r = EINA_FALSE;
160
161 *error = EVAS_LOAD_ERROR_NONE;
162
163 map = eina_file_map_all(f, EINA_FILE_RANDOM);
164 length = eina_file_size_get(f);
165 position = 0;
166 if (!map || length < 1)
167 {
168 *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
169 goto on_error;
170 }
171
172 correct = psd_get_header(&header, map, length, &position);
173 if (!correct || !is_psd(&header))
174 {
175 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
176 goto on_error;
177 }
178
179 prop->w = header.width;
180 prop->h = header.height;
181 if (header.channels != 3)
182 prop->alpha = 1;
183
184 r = EINA_TRUE;
185
186 on_error:
187 eina_file_map_free(f, map);
188 return r;
189 }
190
191 static unsigned int
read_compressed_channel(const unsigned char * map,size_t length,size_t * position,const unsigned int channel_length EINA_UNUSED,unsigned int size,unsigned char * channel)192 read_compressed_channel(const unsigned char *map, size_t length, size_t *position,
193 const unsigned int channel_length EINA_UNUSED,
194 unsigned int size,
195 unsigned char* channel)
196 {
197 // FIXME: what does channel_length means, and why is it not used
198 unsigned int i;
199 signed char headbyte;
200 unsigned char c;
201
202 #define CHECK_RET(Call) \
203 if (!Call) return READ_COMPRESSED_ERROR_FILE_READ_ERROR; \
204
205 for (i = 0; i < size; )
206 {
207 CHECK_RET(read_block(map, length, position, &headbyte, 1));
208
209 if (headbyte >= 0)
210 {
211 if (i + headbyte > size)
212 return READ_COMPRESSED_ERROR_FILE_CORRUPT;
213 CHECK_RET(read_block(map, length, position, channel + i, headbyte + 1));
214
215 i += headbyte + 1;
216 }
217 else if (headbyte >= -127)
218 {
219 int run;
220
221 CHECK_RET(read_block(map, length, position, &c, 1));
222
223 run = c;
224 /* if (run == -1) */
225 /* return READ_COMPRESSED_ERROR_FILE_READ_ERROR; */
226
227 if (i + (-headbyte + 1) > size)
228 return READ_COMPRESSED_ERROR_FILE_CORRUPT;
229
230 memset(channel + i, run, -headbyte + 1);
231 i += -headbyte + 1;
232 }
233 }
234
235 #undef CHECK_RET
236
237 return READ_COMPRESSED_SUCCESS;
238 }
239
240
241 static Eina_Bool
psd_get_data(PSD_Header * head,const unsigned char * map,size_t length,size_t * position,unsigned char * buffer,Eina_Bool compressed,int * error)242 psd_get_data(PSD_Header *head,
243 const unsigned char *map, size_t length, size_t *position,
244 unsigned char *buffer, Eina_Bool compressed,
245 int *error)
246 {
247 unsigned int c, x, y, numchan, bps, bpc, bpp;
248 unsigned int pixels_count;
249 unsigned char *channel = NULL;
250 unsigned char *data = NULL;
251
252 // Added 01-07-2009: This is needed to correctly load greyscale and
253 // paletted images.
254 switch (head->mode)
255 {
256 case PSD_GREYSCALE:
257 case PSD_INDEXED:
258 numchan = 1;
259 break;
260 default:
261 numchan = 3;
262 }
263
264 bpp = head->channels;
265 bpc = head->depth / 8;
266 pixels_count = head->width * head->height;
267
268 data = malloc(sizeof (unsigned char) * pixels_count * bpp);
269 if (!data) return EINA_FALSE;
270
271 channel = malloc(sizeof (unsigned char) * pixels_count * bpc);
272 if (!channel)
273 {
274 free(data);
275 return EINA_FALSE;
276 }
277
278 bps = head->width * head->channels * bpc;
279 // @TODO: Add support for this in, though I have yet to run across a .psd
280 // file that uses this.
281 if (compressed && bpc == 2)
282 {
283 free(data);
284 free(channel);
285 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
286 return EINA_FALSE;
287 }
288
289 #define CHECK_RET(Call) \
290 if (!Call) \
291 { \
292 free(data); \
293 free(channel); \
294 return EINA_FALSE; \
295 }
296
297 if (!compressed)
298 {
299 if (bpc == 1)
300 {
301 for (c = 0; c < numchan; c++)
302 {
303 unsigned char *tmp = channel;
304
305 CHECK_RET(read_block(map, length, position, tmp, pixels_count));
306
307 for (y = 0; y < head->height * bps; y += bps)
308 {
309 for (x = 0; x < bps; x += bpp, tmp++)
310 {
311 data[y + x + c] = *tmp;
312 }
313 }
314 }
315
316 // Accumulate any remaining channels into a single alpha channel
317 //@TODO: This needs to be changed for greyscale images.
318 for (; c < head->channels; c++)
319 {
320 unsigned char *tmp = channel;
321
322 CHECK_RET(read_block(map, length, position, channel, pixels_count));
323
324 for (y = 0; y < head->height * bps; y += bps)
325 {
326 for (x = 0; x < bps; x += bpp, tmp++)
327 {
328 unsigned short newval;
329
330 // previous formula was : (old / 255 * new / 255) * 255
331 newval = (*tmp) * data[y + x + 3];
332
333 data[y + x + 3] = newval >> 8;
334 }
335 }
336 }
337 }
338 else
339 {
340 int bps2;
341
342 bps2 = bps / 2;
343
344 // iCurImage->Bpc == 2
345 for (c = 0; c < numchan; c++)
346 {
347 unsigned short *shortptr = (unsigned short*) channel;
348
349 CHECK_RET(read_block(map, length, position, channel, pixels_count * 2));
350
351 for (y = 0; y < head->height * bps2; y += bps2)
352 {
353 for (x = 0; x < (unsigned int)bps2; x += bpp, shortptr++)
354 {
355 ((unsigned short*)data)[y + x + c] = *shortptr;
356 }
357 }
358 }
359
360 // Accumulate any remaining channels into a single alpha channel
361 //@TODO: This needs to be changed for greyscale images.
362 for (; c < head->channels; c++)
363 {
364 unsigned short *shortptr = (unsigned short*) channel;
365
366 CHECK_RET(read_block(map, length, position, channel, pixels_count * 2));
367
368 for (y = 0; y < head->height * bps2; y += bps2)
369 {
370 for (x = 0; x < (unsigned int)bps2; x += bpp, shortptr++)
371 {
372 unsigned int newval;
373
374 newval = *shortptr * ((unsigned short*)data)[y + x + 3];
375
376 ((unsigned short*)data)[y + x + 3] = newval >> 16;
377 }
378 }
379 }
380 }
381 }
382 else
383 {
384 unsigned short *rle_table;
385 unsigned int *chanlen;
386
387 rle_table = alloca(head->height * head->channel_num * sizeof (unsigned short));
388 chanlen = alloca(head->channel_num * sizeof (unsigned int));
389 if (!get_compressed_channels_length(head, map, length, position, rle_table, chanlen))
390 goto file_read_error;
391
392 for (c = 0; c < numchan; c++)
393 {
394 unsigned char *tmp = channel;
395 int err;
396
397 err = read_compressed_channel(map, length, position,
398 chanlen[c],
399 pixels_count,
400 channel);
401 if (err == READ_COMPRESSED_ERROR_FILE_CORRUPT)
402 goto file_corrupt;
403 else if (err == READ_COMPRESSED_ERROR_FILE_READ_ERROR)
404 goto file_read_error;
405
406 for (y = 0; y < head->height * bps; y += bps)
407 {
408 for (x = 0; x < bps; x += bpp, tmp++)
409 {
410 data[y + x + c] = *tmp;
411 }
412 }
413 }
414
415 // Initialize the alpha channel to solid
416 //@TODO: This needs to be changed for greyscale images.
417 if (head->channels >= 4)
418 {
419 for (y = 0; y < head->height * bps; y += bps)
420 {
421 for (x = 0; x < bps; x += bpp)
422 {
423 data[y + x + 3] = 255;
424 }
425 }
426
427 for (; c < head->channels; c++)
428 {
429 unsigned char *tmp = channel;
430 int err;
431
432 err = read_compressed_channel(map, length, position,
433 chanlen[c],
434 pixels_count,
435 channel);
436 if (err == READ_COMPRESSED_ERROR_FILE_CORRUPT)
437 goto file_corrupt;
438 else if (err == READ_COMPRESSED_ERROR_FILE_READ_ERROR)
439 goto file_read_error;
440
441 for (y = 0; y < head->height * bps; y += bps)
442 {
443 for (x = 0; x < bps; x += bpp, tmp++)
444 {
445 unsigned short newval;
446
447 newval = *tmp * data[y + x + 3];
448
449 data[y + x + 3] = newval >> 8;
450 }
451 }
452 }
453 }
454 }
455
456 if (bpp == 3)
457 {
458 for (x = 0; x < pixels_count; x++)
459 {
460 buffer[x * 4 + 0] = data[x * 3 + 2];
461 buffer[x * 4 + 1] = data[x * 3 + 1];
462 buffer[x * 4 + 2] = data[x * 3 + 0];
463 buffer[x * 4 + 3] = 255;
464 }
465 }
466 else
467 {
468 // BRGA to RGBA
469 for (x= 0; x < pixels_count; x++)
470 {
471 buffer[x * 4 + 0] = data[x * 4 + 2];
472 buffer[x * 4 + 1] = data[x * 4 + 1];
473 buffer[x * 4 + 2] = data[x * 4 + 0];
474 buffer[x * 4 + 3] = data[x * 4 + 3];
475 }
476 }
477
478 free(channel);
479 free(data);
480 return EINA_TRUE;
481
482 #undef CHECK_RET
483
484 file_corrupt:
485 *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
486
487 file_read_error:
488 free(channel);
489 free(data);
490
491 return EINA_FALSE;
492 }
493
494
495 static Eina_Bool
get_single_channel(PSD_Header * head,const unsigned char * map,size_t length,size_t * position,unsigned char * buffer,Eina_Bool compressed)496 get_single_channel(PSD_Header *head,
497 const unsigned char *map, size_t length, size_t *position,
498 unsigned char *buffer,
499 Eina_Bool compressed)
500 {
501 unsigned int i, bpc;
502 signed char headbyte;
503 int c;
504 int pixels_count;
505
506 bpc = (head->depth / 8);
507 pixels_count = head->width * head->height;
508
509 #define CHECK_RET(Call) \
510 if (!Call) return EINA_FALSE;
511
512 if (!compressed)
513 {
514 if (bpc == 1)
515 {
516 CHECK_RET(read_block(map, length, position, buffer, pixels_count));
517 }
518 else
519 { // Bpc == 2
520 CHECK_RET(read_block(map, length, position, buffer, pixels_count * 2));
521 }
522 }
523 else
524 {
525 for (i = 0; i < (unsigned int)pixels_count; )
526 {
527 CHECK_RET(read_block(map, length, position, &headbyte, 1));
528
529 if (headbyte >= 0)
530 { // && HeadByte <= 127
531 CHECK_RET(read_block(map, length, position, buffer + i, headbyte + 1));
532
533 i += headbyte + 1;
534 }
535 if (headbyte >= -127 && headbyte <= -1)
536 {
537 int run;
538
539 CHECK_RET(read_block(map, length, position, &c, 1));
540
541 run = c;
542 if (run == -1) return EINA_FALSE;
543
544 memset(buffer + i, run, -headbyte + 1);
545 i += -headbyte + 1;
546 }
547 }
548 }
549
550 #undef CHECK_RET
551
552 return EINA_TRUE;
553 }
554
555 static Eina_Bool
read_psd_grey(void * pixels,PSD_Header * head,const unsigned char * map,size_t length,size_t * position,int * error)556 read_psd_grey(void *pixels, PSD_Header *head, const unsigned char *map, size_t length, size_t *position, int *error)
557 {
558 unsigned int color_mode, resource_size, misc_info;
559 unsigned short compressed;
560
561 *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
562
563 #define CHECK_RET(Call) \
564 if (!Call) return EINA_FALSE;
565
566 CHECK_RET(read_uint(map, length, position, &color_mode));
567 // Skip over the 'color mode data section'
568 *position += color_mode;
569 if ((*position) >= length) return EINA_FALSE;
570
571 CHECK_RET(read_uint(map, length, position, &resource_size));
572 // Read the 'image resources section'
573 *position += resource_size;
574 if ((*position) >= length) return EINA_FALSE;
575
576 CHECK_RET(read_uint(map, length, position, &misc_info));
577 *position += misc_info;
578 if ((*position) >= length) return EINA_FALSE;
579
580 CHECK_RET(read_ushort(map, length, position, &compressed));
581 if (compressed != 0) compressed = EINA_TRUE;
582
583 head->channel_num = head->channels;
584 // Temporary to read only one channel...some greyscale .psd files have 2.
585 head->channels = 1;
586
587 switch (head->depth)
588 {
589 case 8:
590 case 16:
591 break;
592 default:
593 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
594 return EINA_FALSE;
595 }
596
597 if (!psd_get_data(head, map, length, position, pixels, compressed, error))
598 goto cleanup_error;
599
600 return EINA_TRUE;
601
602 #undef CHECK_RET
603
604 cleanup_error:
605 return EINA_FALSE;
606 }
607
608
609 static Eina_Bool
read_psd_indexed(void * pixels,PSD_Header * head,const unsigned char * map,size_t length,size_t * position,int * error)610 read_psd_indexed(void *pixels, PSD_Header *head, const unsigned char *map, size_t length, size_t *position, int *error)
611 {
612 unsigned int color_mode, resource_size, misc_info;
613 unsigned short compressed;
614
615 *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
616
617 #define CHECK_RET(Call) \
618 if (!(Call)) return EINA_FALSE;
619
620 CHECK_RET(read_uint(map, length, position, &color_mode));
621 CHECK_RET(!(color_mode % 3));
622 /*
623 Palette = (unsigned char*)malloc(Colormode);
624 if (Palette == NULL)
625 return EINA_FALSE;
626 if (fread(&Palette, 1, Colormode, file) != Colormode)
627 goto cleanup_error;
628 */
629 // Skip over the 'color mode data section'
630 *position += color_mode;
631 if ((*position) >= length) return EINA_FALSE;
632
633 // Read the 'image resources section'
634 CHECK_RET(read_uint(map, length, position, &resource_size));
635 *position += resource_size;
636 if ((*position) >= length) return EINA_FALSE;
637
638 CHECK_RET(read_uint(map, length, position, &misc_info));
639 *position += misc_info;
640 if ((*position) >= length) return EINA_FALSE;
641
642 CHECK_RET(read_ushort(map, length, position, &compressed));
643 if (compressed != 0) compressed = EINA_TRUE;
644
645 if (head->channels != 1 || head->depth != 8)
646 {
647 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
648 return EINA_FALSE;
649 }
650 head->channel_num = head->channels;
651
652 if (!psd_get_data(head, map, length, position, pixels, compressed, error))
653 return EINA_FALSE;
654 return EINA_TRUE;
655
656 #undef CHECK_RET
657 }
658
659 static Eina_Bool
read_psd_rgb(void * pixels,PSD_Header * head,const unsigned char * map,size_t length,size_t * position,int * error)660 read_psd_rgb(void *pixels, PSD_Header *head, const unsigned char *map, size_t length, size_t *position, int *error)
661 {
662 unsigned int color_mode, resource_size, misc_info;
663 unsigned short compressed;
664
665 #define CHECK_RET(Call) \
666 if (!Call) return EINA_FALSE;
667
668 CHECK_RET(read_uint(map, length, position, &color_mode));
669 // Skip over the 'color mode data section'
670 *position += color_mode;
671 if ((*position) >= length) return EINA_FALSE;
672
673 // Read the 'image resources section'
674 CHECK_RET(read_uint(map, length, position, &resource_size));
675 *position += resource_size;
676 if ((*position) >= length) return EINA_FALSE;
677
678 CHECK_RET(read_uint(map, length, position, &misc_info));
679 *position += misc_info;
680 if ((*position) >= length) return EINA_FALSE;
681
682 CHECK_RET(read_ushort(map, length, position, &compressed));
683 if (compressed != 0) compressed = EINA_TRUE;
684
685 head->channel_num = head->channels;
686
687 switch (head->depth)
688 {
689 case 8:
690 case 16:
691 break;
692 default:
693 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
694 return EINA_FALSE;
695 }
696
697 if (!psd_get_data(head, map, length, position, pixels, compressed, error))
698 return EINA_FALSE;
699
700 return EINA_TRUE;
701
702 #undef CHECK_RET
703 }
704
705 static Eina_Bool
read_psd_cmyk(Emile_Image_Property * prop,void * pixels,PSD_Header * head,const unsigned char * map,size_t length,size_t * position,int * error)706 read_psd_cmyk(Emile_Image_Property *prop, void *pixels, PSD_Header *head, const unsigned char *map, size_t length, size_t *position, int *error)
707 {
708 unsigned int color_mode, resource_size, misc_info, size, j, data_size;
709 unsigned short compressed;
710 unsigned int format, type;
711 unsigned char *kchannel = NULL;
712 Eina_Bool r = EINA_FALSE;
713
714 *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
715
716 #define CHECK_RET(Call) \
717 if (!Call) return EINA_FALSE;
718
719 CHECK_RET(read_uint(map, length, position, &color_mode));
720 // Skip over the 'color mode data section'
721 *position += color_mode;
722 if ((*position) >= length) return EINA_FALSE;
723
724 CHECK_RET(read_uint(map, length, position, &resource_size));
725 // Read the 'image resources section'
726 *position += resource_size;
727 if ((*position) >= length) return EINA_FALSE;
728
729 CHECK_RET(read_uint(map, length, position, &misc_info));
730 *position += misc_info;
731 if ((*position) >= length) return EINA_FALSE;
732
733 CHECK_RET(read_ushort(map, length, position, &compressed));
734 if (compressed != 0) compressed = EINA_TRUE;
735
736 switch (head->channels)
737 {
738 case 4:
739 format = 0x1907;
740 head->channel_num = 4;
741 head->channels = 3;
742 break;
743 case 5:
744 format = 0x1908;
745 head->channel_num = 5;
746 head->channels = 4;
747 break;
748 default:
749 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
750 return EINA_FALSE;
751 }
752
753 switch (head->depth)
754 {
755 case 8:
756 type = 1;
757 break;
758 case 16:
759 type = 2;
760 break;
761 default:
762 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
763 return EINA_FALSE;
764 }
765
766 if (!psd_get_data(head, map, length, position, pixels, compressed, error))
767 goto cleanup_error;
768
769 size = type * prop->w * prop->h;
770 kchannel = malloc(size);
771 if (kchannel == NULL)
772 goto cleanup_error;
773 if (!get_single_channel(head, map, length, position, kchannel, compressed))
774 goto cleanup_error;
775
776 data_size = head->channels * type * prop->w * prop->h;
777 if (format == 0x1907)
778 {
779 unsigned char *tmp = pixels;
780 const unsigned char *limit = tmp + data_size;
781
782 for (j = 0; tmp < limit; tmp++, j++)
783 {
784 int k;
785
786 for (k = 0; k < 3; k++)
787 *tmp = (*tmp * kchannel[j]) >> 8;
788
789 // FIXME: tmp[i+3] = 255;
790 }
791 }
792 else
793 { // RGBA
794 unsigned char *tmp = pixels;
795 const unsigned char *limit = tmp + data_size;
796
797 // The KChannel array really holds the alpha channel on this one.
798 for (j = 0; tmp < limit; tmp += 4, j++)
799 {
800 tmp[0] = (tmp[0] * tmp[3]) >> 8;
801 tmp[1] = (tmp[1] * tmp[3]) >> 8;
802 tmp[2] = (tmp[2] * tmp[3]) >> 8;
803 tmp[3] = kchannel[j]; // Swap 'K' with alpha channel.
804 }
805 }
806
807 r = EINA_TRUE;
808
809 cleanup_error:
810 free(kchannel);
811 return r;
812 }
813
814 static Eina_Bool
evas_image_load_file_data_psd(void * loader_data,Emile_Image_Property * prop,void * pixels,int * error)815 evas_image_load_file_data_psd(void *loader_data,
816 Emile_Image_Property *prop,
817 void *pixels,
818 int *error)
819 {
820 Eina_File *f = loader_data;
821
822 void *map;
823 size_t length;
824 size_t position;
825 PSD_Header header;
826 Eina_Bool bpsd = EINA_FALSE;
827
828 map = eina_file_map_all(f, EINA_FILE_SEQUENTIAL);
829 length = eina_file_size_get(f);
830 position = 0;
831 *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
832 if (!map || length < 1)
833 goto on_error;
834
835 *error = EVAS_LOAD_ERROR_GENERIC;
836 if (!psd_get_header(&header, map, length, &position) || !is_psd(&header))
837 goto on_error;
838
839 if (header.width != prop->w ||
840 header.height != prop->h)
841 goto on_error;
842
843 *error = EVAS_LOAD_ERROR_NONE;
844
845 switch (header.mode)
846 {
847 case PSD_GREYSCALE: // Greyscale
848 bpsd = read_psd_grey(pixels, &header, map, length, &position, error);
849 break;
850 case PSD_INDEXED: // Indexed
851 bpsd = read_psd_indexed(pixels, &header, map, length, &position, error);
852 break;
853 case PSD_RGB: // RGB
854 bpsd = read_psd_rgb(pixels, &header, map, length, &position, error);
855 prop->premul = EINA_TRUE;
856 break;
857 case PSD_CMYK: // CMYK
858 bpsd = read_psd_cmyk(prop, pixels, &header, map, length, &position, error);
859 prop->premul = EINA_TRUE;
860 break;
861 default :
862 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
863 bpsd = EINA_FALSE;
864 }
865
866 on_error:
867 if (map) eina_file_map_free(f, map);
868
869 return bpsd;
870 }
871
872 static Eina_Bool
get_compressed_channels_length(PSD_Header * head,const unsigned char * map,size_t length,size_t * position,unsigned short * rle_table,unsigned int * chanlen)873 get_compressed_channels_length(PSD_Header *head,
874 const unsigned char *map, size_t length, size_t *position,
875 unsigned short *rle_table,
876 unsigned int *chanlen)
877 {
878 unsigned int j;
879 unsigned int c;
880
881 if (!read_block(map, length, position, rle_table,
882 sizeof (unsigned short) * head->height * head->channel_num))
883 return EINA_FALSE;
884
885 memset(chanlen, 0, head->channel_num * sizeof(unsigned int));
886 for (c = 0; c < head->channel_num; c++)
887 {
888 unsigned int i;
889
890 j = c * head->height;
891 for (i = 0; i < head->height; i++)
892 {
893 chanlen[c] += rle_table[i + j];
894 }
895 }
896
897 return EINA_TRUE;
898 }
899
900 static const Evas_Image_Load_Func evas_image_load_psd_func = {
901 EVAS_IMAGE_LOAD_VERSION,
902 evas_image_load_file_open_psd,
903 evas_image_load_file_close_psd,
904 (void*) evas_image_load_file_head_psd,
905 NULL,
906 (void*) evas_image_load_file_data_psd,
907 NULL,
908 EINA_TRUE,
909 EINA_FALSE
910 };
911
912 static int
module_open(Evas_Module * em)913 module_open(Evas_Module *em)
914 {
915 if (!em) return 0;
916 em->functions = (void *)(&evas_image_load_psd_func);
917 return 1;
918 }
919
920 static void
module_close(Evas_Module * em EINA_UNUSED)921 module_close(Evas_Module *em EINA_UNUSED)
922 {
923 }
924
925 static Evas_Module_Api evas_modapi =
926 {
927 EVAS_MODULE_API_VERSION,
928 "psd",
929 "none",
930 {
931 module_open,
932 module_close
933 }
934 };
935
936 EVAS_MODULE_DEFINE(EVAS_MODULE_TYPE_IMAGE_LOADER, image_loader, psd);
937
938
939 #ifndef EVAS_STATIC_BUILD_PSD
940 EVAS_EINA_MODULE_DEFINE(image_loader, psd);
941 #endif
942