summaryrefslogtreecommitdiff
path: root/legacy
diff options
context:
space:
mode:
authorCedric BAIL <cedric.bail@free.fr>2011-04-24 19:45:43 +0000
committerCedric BAIL <cedric.bail@free.fr>2011-04-24 19:45:43 +0000
commit0cef5e41fefbd7975f5c4d9477041502d8049c7a (patch)
tree93cd9998cbf01582ddf006346d46206aca3dce2c /legacy
parentbd1337f4cdb57c7838bea704ccbed9f1e5f631c9 (diff)
evas: add psd file format support.
Patch from Thierry el Borgi with some rework of myself. NOTE: I don't have much file to test, so if some don't contact us with those file and we will fix the loader if needed. SVN revision: 58873
Diffstat (limited to '')
-rw-r--r--legacy/evas/AUTHORS1
-rw-r--r--legacy/evas/ChangeLog5
-rw-r--r--legacy/evas/configure.ac5
-rw-r--r--legacy/evas/m4/evas_check_loader.m420
-rw-r--r--legacy/evas/src/lib/Makefile.am5
-rw-r--r--legacy/evas/src/lib/engines/common/evas_image_load.c5
-rw-r--r--legacy/evas/src/lib/file/evas_module.c4
-rw-r--r--legacy/evas/src/modules/loaders/Makefile.am6
-rw-r--r--legacy/evas/src/modules/loaders/psd/evas_image_load_psd.c947
9 files changed, 996 insertions, 2 deletions
diff --git a/legacy/evas/AUTHORS b/legacy/evas/AUTHORS
index cb75a4a773..3a59230dbe 100644
--- a/legacy/evas/AUTHORS
+++ b/legacy/evas/AUTHORS
@@ -23,3 +23,4 @@ Samsung SAIT <tbd>
23Sung W. Park <sungwoo@gmail.com> 23Sung W. Park <sungwoo@gmail.com>
24Jiyoun Park <jy0703.park@samsung.com> 24Jiyoun Park <jy0703.park@samsung.com>
25Myoungwoon Roy Kim(roy_kim) <myoungwoon.kim@samsung.com> <myoungwoon@gmail.com> 25Myoungwoon Roy Kim(roy_kim) <myoungwoon.kim@samsung.com> <myoungwoon@gmail.com>
26Thierry el Borgi <tbd>
diff --git a/legacy/evas/ChangeLog b/legacy/evas/ChangeLog
index 251589995d..884274731b 100644
--- a/legacy/evas/ChangeLog
+++ b/legacy/evas/ChangeLog
@@ -262,3 +262,8 @@
262 Supports a filter object or filter under (the area where the object 262 Supports a filter object or filter under (the area where the object
263 is filtered). Various parameters to tweak, and potential for 263 is filtered). Various parameters to tweak, and potential for
264 additional filters (but you get to write the shader ;-) 264 additional filters (but you get to write the shader ;-)
265
2662011-04-24 Thierry el Borgi
267
268 * Add PSD file format support.
269
diff --git a/legacy/evas/configure.ac b/legacy/evas/configure.ac
index 72f50898b9..2d22dc9606 100644
--- a/legacy/evas/configure.ac
+++ b/legacy/evas/configure.ac
@@ -122,6 +122,7 @@ want_evas_image_loader_bmp="yes"
122want_evas_image_loader_tga="yes" 122want_evas_image_loader_tga="yes"
123want_evas_image_loader_wbmp="yes" 123want_evas_image_loader_wbmp="yes"
124want_evas_image_loader_ico="yes" 124want_evas_image_loader_ico="yes"
125want_evas_image_loader_psd="yes"
125 126
126want_evas_font_loader_eet="yes" 127want_evas_font_loader_eet="yes"
127 128
@@ -835,6 +836,8 @@ EVAS_CHECK_IMAGE_LOADER([WBMP], [${want_evas_image_loader_wbmp}])
835 836
836EVAS_CHECK_IMAGE_LOADER([ICO], [${want_evas_image_loader_ico}]) 837EVAS_CHECK_IMAGE_LOADER([ICO], [${want_evas_image_loader_ico}])
837 838
839EVAS_CHECK_IMAGE_LOADER([PSD], [${want_evas_image_loader_psd}])
840
838##################################################################### 841#####################################################################
839## Cpu based optimizations 842## Cpu based optimizations
840 843
@@ -1607,6 +1610,7 @@ src/modules/loaders/tga/Makefile
1607src/modules/loaders/svg/Makefile 1610src/modules/loaders/svg/Makefile
1608src/modules/loaders/pmaps/Makefile 1611src/modules/loaders/pmaps/Makefile
1609src/modules/loaders/wbmp/Makefile 1612src/modules/loaders/wbmp/Makefile
1613src/modules/loaders/psd/Makefile
1610src/modules/savers/Makefile 1614src/modules/savers/Makefile
1611src/modules/savers/edb/Makefile 1615src/modules/savers/edb/Makefile
1612src/modules/savers/eet/Makefile 1616src/modules/savers/eet/Makefile
@@ -1698,6 +1702,7 @@ echo " TGA.....................: $have_evas_image_loader_tga"
1698echo " TIFF....................: $have_evas_image_loader_tiff" 1702echo " TIFF....................: $have_evas_image_loader_tiff"
1699echo " WBMP....................: $have_evas_image_loader_wbmp" 1703echo " WBMP....................: $have_evas_image_loader_wbmp"
1700echo " XPM.....................: $have_evas_image_loader_xpm" 1704echo " XPM.....................: $have_evas_image_loader_xpm"
1705echo " PSD.....................: $have_evas_image_loader_psd"
1701echo 1706echo
1702echo "Font Sourcing Systems:" 1707echo "Font Sourcing Systems:"
1703echo " EET.....................: $have_evas_font_loader_eet" 1708echo " EET.....................: $have_evas_font_loader_eet"
diff --git a/legacy/evas/m4/evas_check_loader.m4 b/legacy/evas/m4/evas_check_loader.m4
index d03ce091f0..2bff191559 100644
--- a/legacy/evas/m4/evas_check_loader.m4
+++ b/legacy/evas/m4/evas_check_loader.m4
@@ -390,6 +390,26 @@ fi
390 390
391]) 391])
392 392
393dnl use: EVAS_CHECK_LOADER_DEP_PSD(loader, want_static[, ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
394
395AC_DEFUN([EVAS_CHECK_LOADER_DEP_PSD],
396[
397
398have_dep="yes"
399evas_image_loader_[]$1[]_cflags=""
400evas_image_loader_[]$1[]_libs=""
401
402AC_SUBST([evas_image_loader_$1_cflags])
403AC_SUBST([evas_image_loader_$1_libs])
404
405if test "x${have_dep}" = "xyes" ; then
406 m4_default([$3], [:])
407else
408 m4_default([$4], [:])
409fi
410
411])
412
393dnl use: EVAS_CHECK_IMAGE_LOADER(loader, want_loader, macro) 413dnl use: EVAS_CHECK_IMAGE_LOADER(loader, want_loader, macro)
394 414
395 415
diff --git a/legacy/evas/src/lib/Makefile.am b/legacy/evas/src/lib/Makefile.am
index 6e44840190..e901a9b24d 100644
--- a/legacy/evas/src/lib/Makefile.am
+++ b/legacy/evas/src/lib/Makefile.am
@@ -164,6 +164,11 @@ SUBDIRS += ../modules/loaders/xpm
164EVAS_STATIC_MODULE += ../modules/loaders/xpm/libevas_loader_xpm.la 164EVAS_STATIC_MODULE += ../modules/loaders/xpm/libevas_loader_xpm.la
165EVAS_STATIC_LIBADD += @evas_image_loader_xpm_libs@ 165EVAS_STATIC_LIBADD += @evas_image_loader_xpm_libs@
166endif 166endif
167if EVAS_STATIC_BUILD_PSD
168SUBDIRS += ../modules/loaders/psd
169EVAS_STATIC_MODULE += ../modules/loaders/psd/libevas_loader_psd.la
170EVAS_STATIC_LIBADD += @evas_image_loader_psd_libs@
171endif
167 172
168AM_CPPFLAGS = \ 173AM_CPPFLAGS = \
169-I. \ 174-I. \
diff --git a/legacy/evas/src/lib/engines/common/evas_image_load.c b/legacy/evas/src/lib/engines/common/evas_image_load.c
index ba6b38df78..2ddbd1bcab 100644
--- a/legacy/evas/src/lib/engines/common/evas_image_load.c
+++ b/legacy/evas/src/lib/engines/common/evas_image_load.c
@@ -32,12 +32,13 @@ static const struct ext_loader_s loaders[] =
32 { "tga", "tga" }, 32 { "tga", "tga" },
33 { "wbmp", "wbmp" }, 33 { "wbmp", "wbmp" },
34 { "ico", "ico" }, 34 { "ico", "ico" },
35 { "cur", "ico" } 35 { "cur", "ico" },
36 { "psd", "psd" }
36}; 37};
37 38
38static const char *loaders_name[] = 39static const char *loaders_name[] =
39{ 40{
40 "png", "jpeg", "eet", "xpm", "tiff", "gif", "svg", "pmaps", "edb", "bmp", "tga", "wbmp", "ico" 41 "png", "jpeg", "eet", "xpm", "tiff", "gif", "svg", "pmaps", "edb", "bmp", "tga", "wbmp", "ico", "psd"
41}; 42};
42 43
43struct evas_image_foreach_loader_data 44struct evas_image_foreach_loader_data
diff --git a/legacy/evas/src/lib/file/evas_module.c b/legacy/evas/src/lib/file/evas_module.c
index 0c5969f764..1098822b6e 100644
--- a/legacy/evas/src/lib/file/evas_module.c
+++ b/legacy/evas/src/lib/file/evas_module.c
@@ -121,6 +121,7 @@ EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, edb);
121EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, tga); 121EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, tga);
122EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, wbmp); 122EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, wbmp);
123EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, ico); 123EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, ico);
124EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, psd);
124EVAS_EINA_STATIC_MODULE_DEFINE(image_saver, edb); 125EVAS_EINA_STATIC_MODULE_DEFINE(image_saver, edb);
125EVAS_EINA_STATIC_MODULE_DEFINE(image_saver, eet); 126EVAS_EINA_STATIC_MODULE_DEFINE(image_saver, eet);
126EVAS_EINA_STATIC_MODULE_DEFINE(image_saver, jpeg); 127EVAS_EINA_STATIC_MODULE_DEFINE(image_saver, jpeg);
@@ -239,6 +240,9 @@ static const struct {
239#ifdef EVAS_STATIC_BUILD_TIFF 240#ifdef EVAS_STATIC_BUILD_TIFF
240 EVAS_EINA_STATIC_MODULE_USE(image_saver, tiff), 241 EVAS_EINA_STATIC_MODULE_USE(image_saver, tiff),
241#endif 242#endif
243#ifdef EVAS_STATIC_BUILD_PSD
244 EVAS_EINA_STATIC_MODULE_USE(image_saver, psd),
245#endif
242 { NULL, NULL } 246 { NULL, NULL }
243}; 247};
244 248
diff --git a/legacy/evas/src/modules/loaders/Makefile.am b/legacy/evas/src/modules/loaders/Makefile.am
index 222bef1e12..f90cfd21a4 100644
--- a/legacy/evas/src/modules/loaders/Makefile.am
+++ b/legacy/evas/src/modules/loaders/Makefile.am
@@ -80,3 +80,9 @@ SUBDIRS += xpm
80endif 80endif
81endif 81endif
82 82
83if BUILD_LOADER_PSD
84if !EVAS_STATIC_BUILD_PSD
85SUBDIRS += psd
86endif
87endif
88
diff --git a/legacy/evas/src/modules/loaders/psd/evas_image_load_psd.c b/legacy/evas/src/modules/loaders/psd/evas_image_load_psd.c
new file mode 100644
index 0000000000..f7c3e2428e
--- /dev/null
+++ b/legacy/evas/src/modules/loaders/psd/evas_image_load_psd.c
@@ -0,0 +1,947 @@
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 <netinet/in.h>
14#include <sys/types.h>
15#include <sys/stat.h>
16#include <unistd.h>
17#include <fcntl.h>
18#include <sys/mman.h>
19
20#ifdef HAVE_EVIL
21# include <Evil.h>
22#endif
23
24#include "evas_common.h"
25#include "evas_private.h"
26
27typedef struct _PSD_Header PSD_Header;
28
29typedef enum _PSD_Mode
30 {
31 PSD_GREYSCALE = 1,
32 PSD_INDEXED = 2,
33 PSD_RGB = 3,
34 PSD_CMYK = 4
35 } PSD_Mode;
36
37struct _PSD_Header
38{
39 unsigned char signature[4];
40 unsigned short version;
41 unsigned char reserved[9];
42 unsigned short channels;
43 unsigned int height;
44 unsigned int width;
45 unsigned short depth;
46
47 unsigned short channel_num;
48
49 PSD_Mode mode;
50};
51
52enum {
53 READ_COMPRESSED_SUCCESS,
54 READ_COMPRESSED_ERROR_FILE_CORRUPT,
55 READ_COMPRESSED_ERROR_FILE_READ_ERROR
56};
57
58static Eina_Bool get_compressed_channels_length(PSD_Header *Head,
59 FILE *file,
60 unsigned short *rle_table,
61 unsigned int *chanlen);
62
63static int
64read_ushort(FILE *file, unsigned short *ret)
65{
66 unsigned char b[2];
67 if (fread(b, sizeof(unsigned char), 2, file) != 2) return 0;
68 // FIXME: need to check order
69 *ret = (b[0] << 8) | b[1];
70 return 1;
71}
72
73static int
74read_uint(FILE *file, unsigned int *ret)
75{
76 unsigned char b[4];
77 if (fread(b, sizeof(unsigned char), 4, file) != 4) return 0;
78 // FIXME: need to check order
79 *ret = ARGB_JOIN(b[0], b[1], b[2], b[3]);
80 return 1;
81}
82
83// Internal function used to get the Psd header from the current file.
84Eina_Bool
85psd_get_header(PSD_Header *header, FILE * file)
86{
87 unsigned short tmp;
88
89#define CHECK_RET(Call, Value) \
90 if (Call != Value) return EINA_FALSE;
91
92 CHECK_RET(fread(header->signature, sizeof (unsigned char), 4, file), 4);
93 CHECK_RET(read_ushort(file, &header->version), 1);
94 CHECK_RET(fread(header->reserved, sizeof (unsigned char), 6, file), 6);
95 CHECK_RET(read_ushort(file, &header->channels), 1);
96 CHECK_RET(read_uint(file, &header->height), 1);
97 CHECK_RET(read_uint(file, &header->width), 1);
98 CHECK_RET(read_ushort(file, &header->depth), 1);
99
100 CHECK_RET(read_ushort(file, &tmp), 1);
101 header->mode = tmp;
102
103#undef CHECK_RET
104
105 /* fprintf(stderr, "<<<<<<<<<<<\nsignature : %c%c%c%c\n", */
106 /* header->signature[0], */
107 /* header->signature[1], */
108 /* header->signature[2], */
109 /* header->signature[3]); */
110 /* fprintf(stderr, "version : %i\n", header->version); */
111 /* fprintf(stderr, "channels : %i\n", header->channels); */
112 /* fprintf(stderr, "width x height : %dx%d\n", header->width, header->height); */
113 /* fprintf(stderr, "depth : %i\n", header->depth); */
114 /* fprintf(stderr, "mode : %i\n>>>>>>>>>>>>\n", header->mode); */
115
116 return EINA_TRUE;
117}
118
119
120// Internal function used to check if the HEADER is a valid Psd header.
121Eina_Bool
122is_psd(PSD_Header *header)
123{
124 if (strncmp((char*)header->signature, "8BPS", 4))
125 return EINA_FALSE;
126 if (header->version != 1)
127 return EINA_FALSE;
128 if (header->channels < 1 || header->channels > 24)
129 return EINA_FALSE;
130 if (header->height < 1 || header->width < 1)
131 return EINA_FALSE;
132 if (header->depth != 1 && header->depth != 8 && header->depth != 16)
133 return EINA_FALSE;
134
135 return EINA_TRUE;
136}
137
138static Eina_Bool
139evas_image_load_file_head_psd(Image_Entry *ie, const char *FileName, const char *key, int *error)
140{
141 FILE *f;
142 PSD_Header header;
143
144 *error = EVAS_LOAD_ERROR_NONE;
145
146 f = fopen(FileName, "rb");
147 if (f == NULL)
148 {
149 *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
150 return EINA_FALSE;
151 }
152 psd_get_header(&header, f);
153 fclose(f);
154
155 if (!is_psd(&header))
156 {
157 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
158 return EINA_FALSE;
159 }
160
161 ie->w = header.width;
162 ie->h = header.height;
163 if (header.channels == 3) ie->flags.alpha = 0;
164 else ie->flags.alpha = 1;
165
166 return EINA_TRUE;
167}
168
169static unsigned int
170read_compressed_channel(FILE* file,
171 const unsigned int channel_length, unsigned int size,
172 unsigned char* channel)
173{
174 // FIXME: what does channel_length means, and why is it not used
175 unsigned int i;
176 char headbyte, c;
177
178#define CHECK_RET(Call, Value) \
179 if (Call != Value) return READ_COMPRESSED_ERROR_FILE_READ_ERROR;
180
181 for (i = 0; i < size; )
182 {
183 CHECK_RET(fread(&headbyte, 1, 1, file), 1);
184
185 if (headbyte >= 0)
186 {
187 if (i + headbyte > size)
188 return READ_COMPRESSED_ERROR_FILE_CORRUPT;
189
190 CHECK_RET(fread(channel + i, headbyte + 1, 1, file), 1);
191
192 i += headbyte + 1;
193 }
194 else if (headbyte >= -127 && headbyte <= -1)
195 {
196 int run;
197
198 CHECK_RET(fread(&c, 1, 1, file), 1);
199
200 run = c;
201 /* if (run == -1) */
202 /* return READ_COMPRESSED_ERROR_FILE_READ_ERROR; */
203
204 if (i + (-headbyte + 1) > size)
205 return READ_COMPRESSED_ERROR_FILE_CORRUPT;
206
207 memset(channel + i, run, -headbyte + 1);
208 i += -headbyte + 1;
209 }
210 }
211
212#undef CHECK_RET
213
214 return READ_COMPRESSED_SUCCESS;
215}
216
217
218Eina_Bool
219psd_get_data(Image_Entry *ie,
220 PSD_Header *head,
221 FILE *f,
222 unsigned char *buffer, Eina_Bool compressed,
223 int *error)
224{
225 unsigned int c, x, y, numchan, bps, bpc, bpp;
226 unsigned int pixels_count;
227 unsigned char *channel = NULL;
228 unsigned char *data = NULL;
229
230 // Added 01-07-2009: This is needed to correctly load greyscale and
231 // paletted images.
232 switch (head->mode)
233 {
234 case PSD_GREYSCALE:
235 case PSD_INDEXED:
236 numchan = 1;
237 break;
238 default:
239 numchan = 3;
240 }
241
242 bpp = head->channels;
243 bpc = head->depth / 8;
244 pixels_count = head->width * head->height;
245
246 data = malloc(sizeof (unsigned char) * pixels_count * bpp);
247 if (!data) return EINA_FALSE;
248
249 channel = malloc(sizeof (unsigned char) * pixels_count * bpc);
250 if (!channel)
251 {
252 free(data);
253 return EINA_FALSE;
254 }
255
256 bps = head->width * head->channels * bpc;
257 // @TODO: Add support for this in, though I have yet to run across a .psd
258 // file that uses this.
259 if (compressed && bpc == 2)
260 {
261 free(data);
262 free(channel);
263 fprintf(stderr, "unsupported file format.\n");
264 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
265 return EINA_FALSE;
266 }
267
268#define CHECK_RET(Call, Value) \
269 if (Call != Value) \
270 { \
271 free(data); \
272 free(channel); \
273 return EINA_FALSE; \
274 }
275
276 if (!compressed)
277 {
278 if (bpc == 1)
279 {
280 for (c = 0; c < numchan; c++)
281 {
282 unsigned char *tmp = channel;
283
284 CHECK_RET(fread(tmp, pixels_count, 1, f), 1);
285
286 for (y = 0; y < head->height * bps; y += bps)
287 {
288 for (x = 0; x < bps; x += bpp, tmp++)
289 {
290 data[y + x + c] = *tmp;
291 }
292 }
293 }
294
295 // Accumulate any remaining channels into a single alpha channel
296 //@TODO: This needs to be changed for greyscale images.
297 for (; c < head->channels; c++)
298 {
299 unsigned char *tmp = channel;
300
301 CHECK_RET(fread(channel, pixels_count, 1, f), 1);
302
303 for (y = 0; y < head->height * bps; y += bps)
304 {
305 for (x = 0; x < bps; x += bpp, tmp++)
306 {
307 unsigned short newval;
308
309 // previous formula was : (old / 255 * new / 255) * 255
310 newval = (*tmp) * data[y + x + 3];
311
312 data[y + x + 3] = newval >> 8;
313 }
314 }
315 }
316 }
317 else
318 {
319 int bps2;
320
321 bps2 = bps / 2;
322
323 // iCurImage->Bpc == 2
324 for (c = 0; c < numchan; c++)
325 {
326 unsigned short *shortptr = (unsigned short*) channel;
327
328 CHECK_RET(fread(channel, pixels_count * 2, 1, f), 1);
329
330 for (y = 0; y < head->height * bps2; y += bps2)
331 {
332 for (x = 0; x < bps2; x += bpp, shortptr++)
333 {
334 ((unsigned short*)data)[y + x + c] = *shortptr;
335 }
336 }
337 }
338
339 // Accumulate any remaining channels into a single alpha channel
340 //@TODO: This needs to be changed for greyscale images.
341 for (; c < head->channels; c++)
342 {
343 unsigned short *shortptr = (unsigned short*) channel;
344
345 CHECK_RET(fread(channel, pixels_count * 2, 1, f), 1);
346
347 for (y = 0; y < head->height * bps2; y += bps2)
348 {
349 for (x = 0; x < bps2; x += bpp, shortptr)
350 {
351 unsigned int newval;
352
353 newval = *shortptr * ((unsigned short*)data)[y + x + 3];
354
355 ((unsigned short*)data)[y + x + 3] = newval >> 16;
356 }
357 }
358 }
359 }
360 }
361 else
362 {
363 unsigned short *rle_table;
364 unsigned int *chanlen;
365
366 rle_table = alloca(head->height * head->channel_num * sizeof (unsigned short));
367 chanlen = alloca(head->channel_num * sizeof (unsigned int));
368 if (!get_compressed_channels_length(head, f, rle_table, chanlen))
369 goto file_read_error;
370
371 for (c = 0; c < numchan; c++)
372 {
373 unsigned char *tmp = channel;
374 int err;
375
376 err = read_compressed_channel(f,
377 chanlen[c],
378 pixels_count,
379 channel);
380 if (err == READ_COMPRESSED_ERROR_FILE_CORRUPT)
381 goto file_corrupt;
382 else if (err == READ_COMPRESSED_ERROR_FILE_READ_ERROR)
383 goto file_read_error;
384
385 for (y = 0; y < head->height * bps; y += bps)
386 {
387 for (x = 0; x < bps; x += bpp, tmp++)
388 {
389 data[y + x + c] = *tmp;
390 }
391 }
392 }
393
394 // Initialize the alpha channel to solid
395 //@TODO: This needs to be changed for greyscale images.
396 if (head->channels >= 4)
397 {
398 for (y = 0; y < head->height * bps; y += bps)
399 {
400 for (x = 0; x < bps; x += bpp)
401 {
402 data[y + x + 3] = 255;
403 }
404 }
405
406 for (; c < head->channels; c++)
407 {
408 unsigned char *tmp = channel;
409 int err;
410
411 err = read_compressed_channel(f,
412 chanlen[c],
413 pixels_count,
414 channel);
415 if (err == READ_COMPRESSED_ERROR_FILE_CORRUPT)
416 goto file_corrupt;
417 else if (err == READ_COMPRESSED_ERROR_FILE_READ_ERROR)
418 goto file_read_error;
419
420 for (y = 0; y < head->height * bps; y += bps)
421 {
422 for (x = 0; x < bps; x += bpp, tmp++)
423 {
424 unsigned short newval;
425
426 newval = *tmp * data[y + x + 3];
427
428 data[y + x + 3] = newval >> 8;
429 }
430 }
431 }
432 }
433 }
434
435 if (bpp == 3)
436 {
437 for (x = 0; x < pixels_count; x++)
438 {
439 buffer[x * 4 + 0] = data[x * 3 + 2];
440 buffer[x * 4 + 1] = data[x * 3 + 1];
441 buffer[x * 4 + 2] = data[x * 3 + 0];
442 buffer[x * 4 + 3] = 255;
443 }
444 }
445 else
446 {
447 // BRGA to RGBA
448 for (x= 0; x < pixels_count; x++)
449 {
450 buffer[x * 4 + 0] = data[x * 4 + 2];
451 buffer[x * 4 + 1] = data[x * 4 + 1];
452 buffer[x * 4 + 2] = data[x * 4 + 0];
453 buffer[x * 4 + 3] = data[x * 4 + 3];
454 }
455 }
456
457 free(channel);
458 free(data);
459 return EINA_TRUE;
460
461#undef CHECK_RET
462
463 file_corrupt:
464 *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
465
466 file_read_error:
467 free(channel);
468 free(data);
469
470 return EINA_FALSE;
471}
472
473
474Eina_Bool
475get_single_channel(Image_Entry *ie,
476 PSD_Header *head,
477 FILE *f,
478 unsigned char *buffer,
479 Eina_Bool compressed)
480{
481 unsigned int i, bpc;
482 unsigned short *tmp;
483 char headbyte;
484 int c;
485 int pixels_count;
486
487 tmp = (unsigned short*)buffer;
488 bpc = (head->depth / 8);
489 pixels_count = head->width * head->height;
490
491#define CHECK_RET(Call, Value) \
492 if (Call != Value) return EINA_FALSE;
493
494 if (!compressed)
495 {
496 if (bpc == 1)
497 {
498 CHECK_RET(fread(buffer, pixels_count, 1, f), 1);
499 }
500 else
501 { // Bpc == 2
502 CHECK_RET(fread(buffer, pixels_count * 2, 1, f), 1);
503 }
504 }
505 else
506 {
507 for (i = 0; i < pixels_count; )
508 {
509 CHECK_RET(fread(&headbyte, 1, 1, f), 1);
510
511 if (headbyte >= 0)
512 { // && HeadByte <= 127
513 CHECK_RET(fread(buffer + i, headbyte + 1, 1, f), 1);
514
515 i += headbyte + 1;
516 }
517 if (headbyte >= -127 && headbyte <= -1)
518 {
519 int run;
520
521 CHECK_RET(fread(&c, 1, 1, f), 1);
522
523 run = c;
524 if (run == -1) return EINA_FALSE;
525
526 memset(buffer + i, run, -headbyte + 1);
527 i += -headbyte + 1;
528 }
529 }
530 }
531
532#undef CHECK_RET
533
534 return EINA_TRUE;
535}
536
537Eina_Bool
538read_psd_grey(Image_Entry *ie, PSD_Header *head, FILE * f, int *error)
539{
540 unsigned int color_mode, resource_size, misc_info;
541 unsigned short compressed;
542 unsigned int type;
543 void *surface = NULL;
544
545 *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
546
547#define CHECK_RET(Call, Value) \
548 if (Call != Value) return EINA_FALSE;
549
550 CHECK_RET(read_uint(f, &color_mode), 1);
551 // Skip over the 'color mode data section'
552 CHECK_RET(fseek(f, color_mode, SEEK_CUR), 0);
553
554 CHECK_RET(read_uint(f, &resource_size), 1);
555 // Read the 'image resources section'
556
557 CHECK_RET(fseek(f, resource_size, SEEK_CUR), 0);
558
559 CHECK_RET(read_uint(f, &misc_info), 1);
560 CHECK_RET(fseek(f, misc_info, SEEK_CUR), 0);
561
562 CHECK_RET(read_ushort(f, &compressed), 1);
563
564 ie->w = head->width;
565 ie->h = head->height;
566 if (head->channels == 3) ie->flags.alpha = 0;
567 else ie->flags.alpha = 1;
568
569 head->channel_num = head->channels;
570 // Temporary to read only one channel...some greyscale .psd files have 2.
571 head->channels = 1;
572
573 switch (head->depth)
574 {
575 case 8:
576 type = 1;
577 break;
578 case 16:
579 type = 2;
580 break;
581 default:
582 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
583 return EINA_FALSE;
584 }
585
586 evas_cache_image_surface_alloc(ie, ie->w, ie->h);
587 surface = evas_cache_image_pixels(ie);
588
589 if (!psd_get_data(ie, head, f, surface, compressed, error))
590 goto cleanup_error;
591
592 return EINA_TRUE;
593
594#undef CHECK_RET
595
596 cleanup_error:
597 return EINA_FALSE;
598}
599
600
601Eina_Bool
602read_psd_indexed(Image_Entry *ie, PSD_Header *head, FILE * f, int *error)
603{
604 unsigned int color_mode, resource_size, misc_info;
605 unsigned short compressed;
606 void *surface;
607
608 *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
609
610#define CHECK_RET(Call, Value) \
611 if (Call != Value) return EINA_FALSE;
612
613 CHECK_RET(read_uint(f, &color_mode), 1);
614 CHECK_RET((color_mode % 3), 0);
615 /*
616 Palette = (unsigned char*)malloc(Colormode);
617 if (Palette == NULL)
618 return EINA_FALSE;
619 if (fread(&Palette, 1, Colormode, file) != Colormode)
620 goto cleanup_error;
621 */
622 // Skip over the 'color mode data section'
623 CHECK_RET(fseek(f, color_mode, SEEK_CUR), 0);
624
625 // Read the 'image resources section'
626 CHECK_RET(read_uint(f, &resource_size), 1);
627 CHECK_RET(fseek(f, resource_size, SEEK_CUR), 0);
628
629 CHECK_RET(read_uint(f, &misc_info), 1);
630 CHECK_RET(fseek(f, misc_info, SEEK_CUR), 0);
631
632 CHECK_RET(read_ushort(f, &compressed), 1);
633
634 if (head->channels != 1 || head->depth != 8)
635 {
636 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
637 return EINA_FALSE;
638 }
639 head->channel_num = head->channels;
640
641 ie->w = head->width;
642 ie->h = head->height;
643 if (head->channels == 3) ie->flags.alpha = 0;
644 else ie->flags.alpha = 1;
645
646 evas_cache_image_surface_alloc(ie, ie->w, ie->h);
647 surface = evas_cache_image_pixels(ie);
648
649 if (!psd_get_data(ie, head, f, surface, compressed, error))
650 return EINA_FALSE;
651 return EINA_TRUE;
652
653#undef CHECK_RET
654}
655
656Eina_Bool
657read_psd_rgb(Image_Entry *ie, PSD_Header *head, FILE *f, int *error)
658{
659 unsigned int color_mode, resource_size, misc_info;
660 unsigned short compressed;
661 unsigned int format, type;
662 void *surface;
663
664#define CHECK_RET(Call, Value) \
665 if (Call != Value) return EINA_FALSE;
666
667 CHECK_RET(read_uint(f, &color_mode), 1);
668 // Skip over the 'color mode data section'
669 CHECK_RET(fseek(f, color_mode, SEEK_CUR), 0);
670
671 // Read the 'image resources section'
672 CHECK_RET(read_uint(f, &resource_size), 1);
673 CHECK_RET(fseek(f, resource_size, SEEK_CUR), 0);
674
675 CHECK_RET(read_uint(f, &misc_info), 1);
676 CHECK_RET(fseek(f, misc_info, SEEK_CUR), 0);
677
678 CHECK_RET(read_ushort(f, &compressed), 1);
679
680 head->channel_num = head->channels;
681
682 switch (head->depth)
683 {
684 case 8:
685 type = 1;
686 break;
687 case 16:
688 type = 2;
689 break;
690 default:
691 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
692 return EINA_FALSE;
693 }
694 ie->w = head->width;
695 ie->h = head->height;
696 if (head->channels == 3) ie->flags.alpha = 0;
697 else ie->flags.alpha = 1;
698
699 evas_cache_image_surface_alloc(ie, ie->w, ie->h);
700 surface = evas_cache_image_pixels(ie);
701
702 if (!psd_get_data(ie, head, f, surface, compressed, error))
703 goto cleanup_error;
704
705 evas_common_image_premul(ie);
706 return EINA_TRUE;
707
708#undef CHECK_RET
709
710 cleanup_error:
711 return EINA_FALSE;
712}
713
714Eina_Bool
715read_psd_cmyk(Image_Entry *ie, PSD_Header *head, FILE *f, int *error)
716{
717 unsigned int color_mode, resource_size, misc_info, size, i, j, data_size;
718 unsigned short compressed;
719 unsigned int format, type;
720 unsigned char *kchannel = NULL;
721 void *surface;
722
723 *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
724
725#define CHECK_RET(Call, Value) \
726 if (Call != Value) return EINA_FALSE;
727
728 CHECK_RET(read_uint(f, &color_mode), 1);
729 // Skip over the 'color mode data section'
730 CHECK_RET(fseek(f, color_mode, SEEK_CUR), 0);
731
732 CHECK_RET(read_uint(f, &resource_size), 1);
733 // Read the 'image resources section'
734 CHECK_RET(fseek(f, resource_size, SEEK_CUR), 0);
735
736 CHECK_RET(read_uint(f, &misc_info), 1);
737 CHECK_RET(fseek(f, misc_info, SEEK_CUR), 0);
738
739 CHECK_RET(read_ushort(f, &compressed), 1);
740
741 switch (head->channels)
742 {
743 case 4:
744 format = 0x1907;
745 head->channel_num = 4;
746 head->channels = 3;
747 break;
748 case 5:
749 format = 0x1908;
750 head->channel_num = 5;
751 head->channels = 4;
752 break;
753 default:
754 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
755 return EINA_FALSE;
756 }
757
758 switch (head->depth)
759 {
760 case 8:
761 type = 1;
762 break;
763 case 16:
764 type = 2;
765 break;
766 default:
767 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
768 return EINA_FALSE;
769 }
770
771 ie->w = head->width;
772 ie->h = head->height;
773 if (head->channels == 3) ie->flags.alpha = 0;
774 else ie->flags.alpha = 1;
775
776 evas_cache_image_surface_alloc(ie, ie->w, ie->h);
777 surface = evas_cache_image_pixels(ie);
778
779 if (!psd_get_data(ie, head, f, surface, compressed, error))
780 goto cleanup_error;
781
782 size = type * ie->w * ie->h;
783 kchannel = malloc(size);
784 if (kchannel == NULL)
785 goto cleanup_error;
786 if (!get_single_channel(ie, head, f, kchannel, compressed))
787 goto cleanup_error;
788
789 data_size = head->channels * type * ie->w * ie->h;
790 if (format == 0x1907)
791 {
792 unsigned char *tmp = surface;
793 const unsigned char *limit = tmp + data_size;
794
795 for (i = 0, j = 0; tmp < limit; tmp++, j++)
796 {
797 int k;
798
799 for (k = 0; k < 3; k++)
800 *tmp = (*tmp * kchannel[j]) >> 8;
801
802 // FIXME: tmp[i+3] = 255;
803 }
804 }
805 else
806 { // RGBA
807 unsigned char *tmp = surface;
808 const unsigned char *limit = tmp + data_size;
809
810 // The KChannel array really holds the alpha channel on this one.
811 for (i = 0, j = 0; tmp < limit; tmp += 4, j++)
812 {
813 tmp[0] = (tmp[0] * tmp[3]) >> 8;
814 tmp[1] = (tmp[1] * tmp[3]) >> 8;
815 tmp[2] = (tmp[2] * tmp[3]) >> 8;
816 tmp[3] = kchannel[j]; // Swap 'K' with alpha channel.
817 }
818 }
819
820 free(kchannel);
821
822 evas_common_image_premul(ie);
823 return EINA_TRUE;
824
825 cleanup_error:
826 free(kchannel);
827 return EINA_FALSE;
828}
829
830static Eina_Bool
831evas_image_load_file_data_psd(Image_Entry *ie,
832 const char *file,
833 const char *key,
834 int *error)
835{
836 FILE *f;
837 PSD_Header header;
838 Eina_Bool bpsd = EINA_FALSE;
839
840 f = fopen(file, "rb");
841 if (f == NULL)
842 {
843 *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
844 return bpsd;
845 }
846
847 psd_get_header(&header, f);
848 if (!is_psd(&header))
849 {
850 *error = EVAS_LOAD_ERROR_GENERIC;
851 return EINA_FALSE;
852 }
853
854 ie->w = header.width;
855 ie->h = header.height;
856
857 *error = EVAS_LOAD_ERROR_NONE;
858
859 switch (header.mode)
860 {
861 case PSD_GREYSCALE: // Greyscale
862 bpsd = read_psd_grey(ie, &header, f, error);
863 break;
864 case PSD_INDEXED: // Indexed
865 bpsd = read_psd_indexed(ie, &header, f, error);
866 break;
867 case PSD_RGB: // RGB
868 bpsd = read_psd_rgb(ie, &header, f, error);
869 break;
870 case PSD_CMYK: // CMYK
871 bpsd = read_psd_cmyk(ie, &header, f, error);
872 break;
873 default :
874 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
875 bpsd = EINA_FALSE;
876 }
877 fclose(f);
878
879 return bpsd;
880}
881
882static Eina_Bool
883get_compressed_channels_length(PSD_Header *head,
884 FILE * file,
885 unsigned short *rle_table,
886 unsigned int *chanlen)
887{
888 unsigned int j;
889 unsigned int c;
890
891 if (fread(rle_table,
892 sizeof(unsigned short),
893 head->height * head->channel_num,
894 file) != head->height * head->channel_num)
895 return EINA_FALSE;
896
897 memset(chanlen, 0, head->channel_num * sizeof(unsigned int));
898 for (c = 0; c < head->channel_num; c++)
899 {
900 unsigned int i;
901
902 j = c * head->height;
903 for (i = 0; i < head->height; i++)
904 {
905 chanlen[c] += rle_table[i + j];
906 }
907 }
908
909 return EINA_TRUE;
910}
911
912static const Evas_Image_Load_Func evas_image_load_psd_func = {
913 EINA_TRUE,
914 evas_image_load_file_head_psd,
915 evas_image_load_file_data_psd
916};
917
918static int
919module_open(Evas_Module *em)
920{
921 if (!em) return 0;
922 em->functions = (void *)(&evas_image_load_psd_func);
923 return 1;
924}
925
926static void
927module_close(Evas_Module *em __UNUSED__)
928{
929}
930
931static Evas_Module_Api evas_modapi =
932 {
933 EVAS_MODULE_API_VERSION,
934 "psd",
935 "none",
936 {
937 module_open,
938 module_close
939 }
940 };
941
942EVAS_MODULE_DEFINE(EVAS_MODULE_TYPE_IMAGE_LOADER, image_loader, psd);
943
944
945#ifndef EVAS_STATIC_BUILD_PSD
946EVAS_EINA_MODULE_DEFINE(image_loader, psd);
947#endif