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