summaryrefslogtreecommitdiff
path: root/src/generic
diff options
context:
space:
mode:
authorCedric BAIL <cedric@osg.samsung.com>2016-06-01 16:59:02 -0700
committerTom Hacohen <tom@stosb.com>2016-06-02 11:35:05 +0100
commit6b5ed1b7118cd99b99a8d133b3e466952885f945 (patch)
treee800e00e4d7239499198598151f50e055d11de4e /src/generic
parent36f15d761a2d39fc81c38a9db7b13d1d571ef453 (diff)
evas: integrate evas generic loaders into our single tree build system.
Diffstat (limited to 'src/generic')
-rw-r--r--src/generic/.gitignore5
-rw-r--r--src/generic/evas/common/shmfile.c87
-rw-r--r--src/generic/evas/common/shmfile.h20
-rw-r--r--src/generic/evas/common/timeout.c16
-rw-r--r--src/generic/evas/common/timeout.h14
-rwxr-xr-xsrc/generic/evas/pdf/evas_generic_pdf_loader.libreoffice8
-rw-r--r--src/generic/evas/pdf/main.cpp353
-rw-r--r--src/generic/evas/ps/main.c289
-rw-r--r--src/generic/evas/raw/main.c242
-rw-r--r--src/generic/evas/svg/main.c230
-rw-r--r--src/generic/evas/xcf/common.h51
-rw-r--r--src/generic/evas/xcf/main.c1731
-rw-r--r--src/generic/evas/xcf/pixelfuncs.c759
13 files changed, 3805 insertions, 0 deletions
diff --git a/src/generic/.gitignore b/src/generic/.gitignore
new file mode 100644
index 0000000..f901c12
--- /dev/null
+++ b/src/generic/.gitignore
@@ -0,0 +1,5 @@
1/emotion/vlc/vlc
2/evas/pdf/evas_image_loader.pdf
3/evas/ps/evas_image_loader.ps
4/evas/raw/evas_image_loader.raw
5/evas/xcf/evas_image_loader.xcf
diff --git a/src/generic/evas/common/shmfile.c b/src/generic/evas/common/shmfile.c
new file mode 100644
index 0000000..538a314
--- /dev/null
+++ b/src/generic/evas/common/shmfile.c
@@ -0,0 +1,87 @@
1#ifdef HAVE_CONFIG_H
2# include <config.h>
3#endif
4
5#include <stdio.h>
6#include <stdlib.h>
7#include <sys/types.h>
8#include <unistd.h>
9#include <math.h>
10#include <netinet/in.h>
11#include <time.h>
12#include <sys/mman.h>
13#include <sys/stat.h>
14#include <fcntl.h>
15#include <string.h>
16#include <zlib.h>
17
18#ifdef __cplusplus
19extern "C" {
20#endif
21
22int shm_fd = -1;
23static int shm_size = 0;
24void *shm_addr = NULL;
25char *shmfile = NULL;
26
27void
28shm_alloc(unsigned long dsize)
29{
30#ifdef HAVE_SHM_OPEN
31 if (!shmfile) shmfile = malloc(1024);
32 if (!shmfile) goto failed;
33 shmfile[0] = 0;
34 srand(time(NULL));
35 do
36 {
37 snprintf(shmfile, 1024, "/evas-loader.%i.%i",
38 (int)getpid(), (int)rand());
39 shm_fd = shm_open(shmfile, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
40 }
41 while (shm_fd < 0);
42
43 if (ftruncate(shm_fd, dsize) < 0)
44 {
45 close(shm_fd);
46 shm_unlink(shmfile);
47 shm_fd = -1;
48 goto failed;
49 }
50 shm_addr = mmap(NULL, dsize, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
51 if (shm_addr == MAP_FAILED)
52 {
53 close(shm_fd);
54 shm_unlink(shmfile);
55 shm_fd = -1;
56 goto failed;
57 }
58 shm_size = dsize;
59 return;
60failed:
61#endif
62 shm_addr = malloc(dsize);
63}
64
65void
66shm_free(void)
67{
68#ifdef HAVE_SHM_OPEN
69 if (shm_fd >= 0)
70 {
71 munmap(shm_addr, shm_size);
72 close(shm_fd);
73 shm_fd = -1;
74 shm_addr = NULL;
75 if (shmfile) free(shmfile);
76 shmfile = NULL;
77 return;
78 }
79#endif
80 free(shm_addr);
81 shm_addr = NULL;
82 shm_fd = -1;
83}
84
85#ifdef __cplusplus
86}
87#endif
diff --git a/src/generic/evas/common/shmfile.h b/src/generic/evas/common/shmfile.h
new file mode 100644
index 0000000..f70a8fd
--- /dev/null
+++ b/src/generic/evas/common/shmfile.h
@@ -0,0 +1,20 @@
1#ifndef SHMFILE_H
2#define SHMFILE_H 1
3
4#ifdef __cplusplus
5extern "C" {
6#endif
7
8extern int shm_fd;
9extern int shm_size;
10extern void *shm_addr;
11extern char *shmfile;
12
13void shm_alloc (unsigned long dsize);
14void shm_free (void);
15
16#ifdef __cplusplus
17}
18#endif
19
20#endif
diff --git a/src/generic/evas/common/timeout.c b/src/generic/evas/common/timeout.c
new file mode 100644
index 0000000..6d52aa9
--- /dev/null
+++ b/src/generic/evas/common/timeout.c
@@ -0,0 +1,16 @@
1#include <unistd.h>
2#include <signal.h>
3
4static void
5_timeout(int val)
6{
7 _exit(-1);
8 if (val) return;
9}
10
11void
12timeout_init(int seconds)
13{
14 signal(SIGALRM, _timeout);
15 alarm(seconds);
16}
diff --git a/src/generic/evas/common/timeout.h b/src/generic/evas/common/timeout.h
new file mode 100644
index 0000000..8725627
--- /dev/null
+++ b/src/generic/evas/common/timeout.h
@@ -0,0 +1,14 @@
1#ifndef TIMEOUT_H
2#define TIMEOUT_H 1
3
4#ifdef __cplusplus
5extern "C" {
6#endif
7
8void timeout_init(int seconds);
9
10#ifdef __cplusplus
11}
12#endif
13
14#endif
diff --git a/src/generic/evas/pdf/evas_generic_pdf_loader.libreoffice b/src/generic/evas/pdf/evas_generic_pdf_loader.libreoffice
new file mode 100755
index 0000000..b36e11e
--- /dev/null
+++ b/src/generic/evas/pdf/evas_generic_pdf_loader.libreoffice
@@ -0,0 +1,8 @@
1#!/bin/sh
2LOBIN=soffice
3if [ -x /usr/lib/libreoffice/program/soffice.bin ]; then
4 LOBIN=/usr/lib/libreoffice/program/soffice.bin
5elif [ -x /usr/lib64/libreoffice/program/soffice.bin ]; then
6 LOBIN=/usr/lib64/libreoffice/program/soffice.bin
7fi
8$LOBIN --headless --convert-to pdf --outdir "$2" "$1"
diff --git a/src/generic/evas/pdf/main.cpp b/src/generic/evas/pdf/main.cpp
new file mode 100644
index 0000000..6b1de13
--- /dev/null
+++ b/src/generic/evas/pdf/main.cpp
@@ -0,0 +1,353 @@
1#ifdef HAVE_CONFIG_H
2# include <config.h>
3#endif
4
5#include <sys/mman.h>
6#include <fcntl.h>
7#include <stdio.h>
8#include <unistd.h>
9#include <libgen.h>
10
11#include <GlobalParams.h>
12#include <PDFDoc.h>
13#include <ErrorCodes.h>
14#include <Page.h>
15#include <SplashOutputDev.h>
16#include <splash/SplashBitmap.h>
17
18#include <Eina.h>
19
20#include "shmfile.h"
21#include "timeout.h"
22
23#define DATA32 unsigned int
24
25//#define PDF_DBG
26
27#ifdef PDF_DBG
28#define D(fmt, args...) fprintf(stderr, fmt, ## args)
29#else
30#define D(fmt, args...)
31#endif
32
33
34PDFDoc *pdfdoc;
35bool locked = false;
36
37::Page *page;
38int width = 0, height = 0;
39int crop_width = 0, crop_height = 0;
40void *data = NULL;
41double dpi = -1.0;
42
43#define DEF_DPI 72.0
44
45Eina_Bool poppler_init(const char *file, int page_nbr, int size_w, int size_h)
46{
47 Object obj;
48 double w, h, cw, ch;
49 int rot;
50
51 if (!file || !*file)
52 return EINA_FALSE;
53
54 if (page_nbr < 0)
55 return EINA_FALSE;
56
57 if (!(globalParams = new GlobalParams()))
58 return EINA_FALSE;
59
60 if (!eina_init())
61 goto del_global_param;
62
63#ifndef HAVE_POPPLER_031
64 if (globalParams->getAntialias())
65 globalParams->setAntialias((char *)"yes");
66 if (globalParams->getVectorAntialias())
67 globalParams->setVectorAntialias((char *)"yes");
68#endif
69
70 pdfdoc = new PDFDoc(new GooString(file), NULL);
71 if (!pdfdoc)
72 goto del_global_param;
73
74 if (!pdfdoc->isOk() || (pdfdoc->getErrorCode() == errEncrypted))
75 goto del_pdfdoc;
76
77 if (page_nbr >= pdfdoc->getNumPages())
78 goto del_pdfdoc;
79
80 /* load the page */
81
82 page = pdfdoc->getCatalog()->getPage(page_nbr + 1);
83 if (!page || !page->isOk())
84 goto del_pdfdoc;
85
86 w = page->getMediaWidth();
87 h = page->getMediaHeight();
88 cw = page->getCropWidth();
89 ch = page->getCropHeight();
90 rot = page->getRotate();
91 if (cw > w) cw = w;
92 if (ch > h) ch = h;
93 if ((rot == 90) || (rot == 270))
94 {
95 double t;
96 // swap width & height
97 t = w; w = h; h = t;
98 // swap crop width & height
99 t = cw; cw = ch; ch = t;
100 }
101
102 if ((size_w > 0) || (size_h > 0))
103 {
104 double w2 = cw, h2 = ch;
105
106 w2 = size_w;
107 h2 = (size_w * ch) / cw;
108 if (h2 > size_h)
109 {
110 h2 = size_h;
111 w2 = (size_h * cw) / ch;
112 }
113 D("XXXXXXXXXXXXXXXXXXXXx %3.3fx%3.3f\n", w2, h2);
114 if (w2 > h2) dpi = (w2 * DEF_DPI) / cw;
115 else dpi = (h2 * DEF_DPI) / ch;
116 }
117
118 if (dpi > 0.0)
119 {
120 cw = (cw * dpi) / DEF_DPI;
121 ch = (ch * dpi) / DEF_DPI;
122 w = (w * dpi) / DEF_DPI;
123 h = (h * dpi) / DEF_DPI;
124 }
125 width = w;
126 height = h;
127 crop_width = cw;
128 crop_height = ch;
129
130 return EINA_TRUE;
131
132 del_pdfdoc:
133 delete pdfdoc;
134 del_global_param:
135 delete globalParams;
136
137 return EINA_FALSE;
138}
139
140void poppler_shutdown()
141{
142 delete pdfdoc;
143 eina_shutdown();
144 delete globalParams;
145}
146
147void poppler_load_image(int size_w EINA_UNUSED, int size_h EINA_UNUSED)
148{
149 SplashOutputDev *output_dev;
150 SplashColor white;
151 SplashColorPtr color_ptr;
152 DATA32 *src, *dst;
153 int y;
154
155 white[0] = 255;
156 white[1] = 255;
157 white[2] = 255;
158 white[3] = 255;
159
160 output_dev = new SplashOutputDev(splashModeXBGR8, 4, gFalse, white);
161 if (!output_dev)
162 return;
163
164#if defined(HAVE_POPPLER_020) || defined(HAVE_POPPLER_031)
165 output_dev->startDoc(pdfdoc);
166#else
167 output_dev->startDoc(pdfdoc->getXRef());
168#endif
169
170 if (dpi <= 0.0) dpi = DEF_DPI;
171
172#ifdef HAVE_POPPLER_031
173 output_dev->setFontAntialias(EINA_TRUE);
174 output_dev->setVectorAntialias(EINA_TRUE);
175#endif
176
177#if defined(HAVE_POPPLER_020) || defined(HAVE_POPPLER_031)
178 page->displaySlice(output_dev, dpi, dpi,
179 0, false, false,
180 0, 0, width, height,
181 false, NULL, NULL);
182#else
183 page->displaySlice(output_dev, dpi, dpi,
184 0, false, false,
185 0, 0, width, height,
186 false, pdfdoc->getCatalog());
187#endif
188 color_ptr = output_dev->getBitmap()->getDataPtr();
189
190 shm_alloc(crop_width * crop_height * sizeof(DATA32));
191 if (!shm_addr) goto del_outpput_dev;
192 data = shm_addr;
193 src = (DATA32 *)color_ptr;
194 dst = (DATA32 *)data;
195 for (y = 0; y < crop_height; y++)
196 {
197 memcpy(dst, src, crop_width * sizeof(DATA32));
198 src += width;
199 dst += crop_width;
200 }
201
202 del_outpput_dev:
203 delete output_dev;
204}
205
206int
207main(int argc, char **argv)
208{
209 Eina_Tmpstr *tmpdir = NULL;
210 Eina_Tmpstr *generated = NULL;
211 char *extension;
212 char *dir;
213 char *file;
214 int i;
215 int size_w = 0, size_h = 0;
216 int head_only = 0;
217 int page_num = 0;
218
219 if (argc < 2) return -1;
220 // file is ALWAYS first arg, other options come after
221 file = argv[1];
222 for (i = 2; i < argc; i++)
223 {
224 if (!strcmp(argv[i], "-head"))
225 // asked to only load header, not body/data
226 head_only = 1;
227 else if (!strcmp(argv[i], "-key"))
228 {
229 i++;
230 page_num = atoi(argv[i]);
231 i++;
232 }
233 else if (!strcmp(argv[i], "-opt-scale-down-by"))
234 { // not used by pdf loader
235 i++;
236 // int scale_down = atoi(argv[i]);
237 }
238 else if (!strcmp(argv[i], "-opt-dpi"))
239 {
240 i++;
241 dpi = ((double)atoi(argv[i])) / 1000.0; // dpi is an int multiplied by 1000 (so 72dpi is 72000)
242 i++;
243 }
244 else if (!strcmp(argv[i], "-opt-size"))
245 { // not used by pdf loader
246 i++;
247 size_w = atoi(argv[i]);
248 i++;
249 size_h = atoi(argv[i]);
250 }
251 }
252
253 D("dpi....: %f\n", dpi);
254 D("page...: %d\n", page_num);
255
256 // This is a funny hack to call an external tool to generate a pdf that will then be processed by poppler
257 extension = strrchr(file, '.');
258 dir = dirname(argv[0]);
259 if (extension && dir && strcmp(extension, ".pdf"))
260 {
261 if (eina_file_mkdtemp("evas_generic_pdf_loaderXXXXXX", &tmpdir))
262 {
263 Eina_Strbuf *tmp;
264 FILE *cmd;
265
266 tmp = eina_strbuf_new();
267 eina_strbuf_append_printf(tmp, "%s/evas_generic_pdf_loader.%s '%s' %s", dir, extension + 1, file, tmpdir);
268
269 cmd = popen(eina_strbuf_string_get(tmp), "r");
270 D("running preprocessing process '%s'...\n", eina_strbuf_string_get(tmp));
271 eina_strbuf_reset(tmp);
272
273 if (cmd)
274 {
275 struct stat st;
276 const char *filename;
277 char buf[1024];
278
279 while (fgets(buf, sizeof (buf), cmd))
280 ;
281 pclose(cmd);
282
283 filename = basename(file);
284 generated = eina_tmpstr_add_length(filename, strlen(filename) - strlen(extension));
285
286 eina_strbuf_append_printf(tmp, "%s/%s.pdf", tmpdir, generated);
287
288 eina_tmpstr_del(generated);
289 generated = NULL;
290
291 if (stat(eina_strbuf_string_get(tmp), &st) == 0)
292 {
293 generated = eina_tmpstr_add_length(eina_strbuf_string_get(tmp),
294 eina_strbuf_length_get(tmp));
295 file = (char*) generated;
296 }
297 }
298
299 D("generated file: '%s'\n", generated);
300 eina_strbuf_free(tmp);
301 }
302 }
303
304 // Let's force a timeout if things go wrong
305 timeout_init(10);
306
307 // Now process the pdf (or the generated pdf)
308 D("poppler_file_init\n");
309 if (!poppler_init(file, page_num, size_w, size_h))
310 return -1;
311 D("poppler_file_init done\n");
312
313 D("dpi2...: %f\n", dpi);
314 if (!head_only)
315 {
316 poppler_load_image(size_w, size_h);
317 }
318
319 D("size...: %ix%i\n", width, height);
320 D("crop...: %ix%i\n", crop_width, crop_height);
321 D("alpha..: 1\n");
322
323 printf("size %i %i\n", crop_width, crop_height);
324 printf("alpha 0\n");
325
326 if (!head_only)
327 {
328 if (shm_fd >= 0) printf("shmfile %s\n", shmfile);
329 else
330 {
331 // could also to "tmpfile %s\n" like shmfile but just
332 // a mmaped tmp file on the system
333 printf("data\n");
334 fwrite(data, crop_width * crop_height * sizeof(DATA32), 1, stdout);
335 }
336 shm_free();
337 }
338 else
339 printf("done\n");
340
341 poppler_shutdown();
342
343 if (tmpdir)
344 {
345 if (generated) unlink(generated);
346 rmdir(tmpdir);
347
348 eina_tmpstr_del(tmpdir);
349 eina_tmpstr_del(generated);
350 }
351 fflush(stdout);
352 return 0;
353}
diff --git a/src/generic/evas/ps/main.c b/src/generic/evas/ps/main.c
new file mode 100644
index 0000000..48e8a4b
--- /dev/null
+++ b/src/generic/evas/ps/main.c
@@ -0,0 +1,289 @@
1#ifdef HAVE_CONFIG_H
2# include <config.h>
3#endif
4
5#include <sys/mman.h>
6#include <fcntl.h>
7
8#include <libspectre/spectre.h>
9
10#include <Eina.h>
11
12#include "shmfile.h"
13#include "timeout.h"
14
15#define DATA32 unsigned int
16
17#define PS_DBG
18
19#ifdef PS_DBG
20#define D(fmt, args...) fprintf(stderr, fmt, ## args)
21#else
22#define D(fmt, args...)
23#endif
24
25
26static SpectreDocument *psdoc;
27static int page_count;
28
29static SpectrePage *page;
30
31static int width = 0;
32static int height = 0;
33static void *data = NULL;
34static double dpi = -1.0;
35
36#define DEF_DPI 72.0
37
38static Eina_Bool
39_spectre_init(const char *file, int page_nbr, int size_w, int size_h)
40{
41 double w, h;
42 int ww, hh;
43 SpectreOrientation rot;
44 SpectreStatus status;
45
46 if (!file || !*file)
47 return EINA_FALSE;
48
49 if (page_nbr < 0)
50 return EINA_FALSE;
51
52 if (!eina_init())
53 return EINA_FALSE;
54
55 psdoc = spectre_document_new();
56 if (!psdoc)
57 goto shutdown_eina;
58
59 spectre_document_load(psdoc, file);
60 status = spectre_document_status (psdoc);
61 if (status != SPECTRE_STATUS_SUCCESS)
62 {
63 D("[ps] %s\n", spectre_status_to_string(status));
64 goto free_psdoc;
65 }
66
67 page_count = spectre_document_get_n_pages(psdoc);
68 status = spectre_document_status(psdoc);
69 if (status != SPECTRE_STATUS_SUCCESS)
70 {
71 D("[eps] %s\n", spectre_status_to_string (status));
72 goto free_psdoc;
73 }
74
75 if (page_nbr >= page_count)
76 goto free_psdoc;
77
78 /* load the page */
79
80 page = spectre_document_get_page(psdoc, page_nbr);
81 status = spectre_document_status(psdoc);
82 if (status != SPECTRE_STATUS_SUCCESS)
83 {
84 D("[eps] %s\n", spectre_status_to_string (status));
85 goto free_page;
86 }
87
88 spectre_page_get_size(page, &ww, &hh);
89 w = ww;
90 h = hh;
91 rot = spectre_page_get_orientation(page);
92
93 if ((rot == SPECTRE_ORIENTATION_LANDSCAPE) || (rot == SPECTRE_ORIENTATION_REVERSE_LANDSCAPE))
94 {
95 double t;
96 // swap width & height
97 t = w; w = h; h = t;
98 }
99
100 if ((size_w > 0) || (size_h > 0))
101 {
102 double w2 = w, h2 = h;
103
104 w2 = size_w;
105 h2 = (size_w * h) / w;
106 if (h2 > size_h)
107 {
108 h2 = size_h;
109 w2 = (size_h * w) / h;
110 }
111 D("XXXXXXXXXXXXXXXXXXXXx %3.3fx%3.3f\n", w2, h2);
112 if (w2 > h2) dpi = (w2 * DEF_DPI) / w;
113 else dpi = (h2 * DEF_DPI) / h;
114 }
115
116 if (dpi > 0.0)
117 {
118 w = (w * dpi) / DEF_DPI;
119 h = (h * dpi) / DEF_DPI;
120 }
121 width = w;
122 height = h;
123
124 return EINA_TRUE;
125
126 free_page:
127 spectre_page_free(page);
128 free_psdoc:
129 spectre_document_free(psdoc);
130 shutdown_eina:
131 eina_shutdown();
132
133 return EINA_FALSE;
134}
135
136static void
137_spectre_shutdown()
138{
139 spectre_page_free(page);
140 spectre_document_free(psdoc);
141 eina_shutdown();
142}
143
144static void
145_pixcopy(DATA32 *dst, unsigned char *src, int size)
146{
147 DATA32 *d;
148 unsigned char *s, *e;
149
150 d = dst;
151 s = src;
152 e = s + size;
153 while (s < e)
154 {
155 d[0] =
156 0xff000000 |
157 (s[2] << 16) |
158 (s[1] << 8 ) |
159 (s[0] );
160 d++;
161 s += 4;
162 }
163}
164
165static void
166_spectre_load_image(int size_w EINA_UNUSED, int size_h EINA_UNUSED)
167{
168 SpectreRenderContext *rc;
169 unsigned char *psdata;
170 int stride;
171 unsigned char *src;
172 DATA32 *dst;
173 int yy;
174 SpectreStatus status;
175
176 rc = spectre_render_context_new();
177 if (!rc)
178 return;
179
180 spectre_page_render(page, rc, &psdata, &stride);
181 spectre_render_context_set_page_size (rc, width, height);
182 status = spectre_page_status(page);
183 if (status != SPECTRE_STATUS_SUCCESS)
184 {
185 D("[eps] %s\n", spectre_status_to_string (status));
186 return;
187 }
188
189 shm_alloc(width * height * sizeof(DATA32));
190 if (!shm_addr) return;
191 data = shm_addr;
192
193 if (stride == 4 * width)
194 _pixcopy(data, psdata, height * stride);
195 else
196 {
197 src = psdata;
198 dst = (DATA32 *)data;
199 for (yy = 0; yy < height; src += stride, dst += width, ++yy)
200 _pixcopy (dst, src, width * 4);
201 }
202
203 spectre_render_context_free(rc);
204}
205
206int
207main(int argc, char **argv)
208{
209 char *file;
210 int i;
211 int size_w = 0, size_h = 0;
212 int head_only = 0;
213 int page_nbr = 0;
214
215 if (argc < 2) return -1;
216 // file is ALWAYS first arg, other options come after
217 file = argv[1];
218 for (i = 2; i < argc; i++)
219 {
220 if (!strcmp(argv[i], "-head"))
221 // asked to only load header, not body/data
222 head_only = 1;
223 else if (!strcmp(argv[i], "-key"))
224 {
225 i++;
226 page_nbr = atoi(argv[i]);
227 i++;
228 }
229 else if (!strcmp(argv[i], "-opt-scale-down-by"))
230 { // not used by ps loader
231 i++;
232 // int scale_down = atoi(argv[i]);
233 }
234 else if (!strcmp(argv[i], "-opt-dpi"))
235 {
236 i++;
237 dpi = ((double)atoi(argv[i])) / 1000.0; // dpi is an int multiplied by 1000 (so 72dpi is 72000)
238 i++;
239 }
240 else if (!strcmp(argv[i], "-opt-size"))
241 { // not used by ps loader
242 i++;
243 size_w = atoi(argv[i]);
244 i++;
245 size_h = atoi(argv[i]);
246 }
247 }
248
249 D("_spectre_init_file\n");
250 D("dpi....: %f\n", dpi);
251 D("page...: %d\n", page_nbr);
252
253 timeout_init(10);
254
255 if (!_spectre_init(file, page_nbr, size_w, size_h))
256 return -1;
257 D("_spectre_init done\n");
258
259 D("dpi2...: %f\n", dpi);
260 if (!head_only)
261 {
262 _spectre_load_image(size_w, size_h);
263 }
264
265 D("size...: %ix%i\n", width, height);
266 D("alpha..: 0\n");
267
268 printf("size %i %i\n", width, height);
269 printf("alpha 0\n");
270
271 if (!head_only)
272 {
273 if (shm_fd >= 0) printf("shmfile %s\n", shmfile);
274 else
275 {
276 // could also to "tmpfile %s\n" like shmfile but just
277 // a mmaped tmp file on the system
278 printf("data\n");
279 fwrite(data, width * height * sizeof(DATA32), 1, stdout);
280 }
281 shm_free();
282 }
283 else
284 printf("done\n");
285
286 _spectre_shutdown();
287 fflush(stdout);
288 return 0;
289}
diff --git a/src/generic/evas/raw/main.c b/src/generic/evas/raw/main.c
new file mode 100644
index 0000000..ac9f810
--- /dev/null
+++ b/src/generic/evas/raw/main.c
@@ -0,0 +1,242 @@
1#ifdef HAVE_CONFIG_H
2#include <config.h>
3#endif
4#include <fcntl.h>
5#include <stdio.h>
6#include <sys/mman.h>
7#include <sys/stat.h>
8#include <sys/types.h>
9#include <unistd.h>
10#include <libraw.h>
11#include "shmfile.h"
12#include "timeout.h"
13
14#ifdef HAVE_NETINET_IN_H
15# include <netinet/in.h>
16#endif
17
18#ifdef HAVE_UNISTD_H
19# include <unistd.h>
20#endif
21
22#include <Eina.h>
23
24
25#define DATA32 unsigned int
26#define DATA8 unsigned char
27
28#define ARGB_JOIN(a,r,g,b) \
29 (((a) << 24) + ((r) << 16) + ((g) << 8) + (b))
30
31//#define RAW_DBG 1
32
33#ifdef RAW_DBG
34#define D(fmt, args...) fprintf(stderr, fmt, ## args)
35#else
36#define D(fmt, args...)
37#endif
38
39static int fd = -1;
40static size_t seg_size = 0;
41static unsigned char *seg = MAP_FAILED;
42static libraw_data_t *raw_data = NULL;
43static void *data = NULL;
44static int width = 0;
45static int height = 0;
46
47static int
48_raw_init(const char *file)
49{
50 struct stat ss;
51 fd = open(file, O_RDONLY);
52 if (fd < 0) return EINA_FALSE;
53
54 if (stat(file, &ss)) goto close_file;
55 seg_size = ss.st_size;
56 seg = mmap(NULL, seg_size, PROT_READ, MAP_SHARED, fd, 0);
57 if (seg == MAP_FAILED) goto close_file;
58
59 D("raw_init\n");
60 raw_data = libraw_init(0);
61 raw_data->params.half_size = 0;
62 raw_data->params.user_qual = 2;
63
64 D("raw_open_buffer\n");
65 if (libraw_open_buffer(raw_data, seg, seg_size) != LIBRAW_SUCCESS)
66 return EINA_FALSE;
67 return EINA_TRUE;
68
69close_file:
70 close(fd);
71 return EINA_FALSE;
72}
73
74static void
75_raw_shutdown()
76{
77 D("raw_shutdown\n");
78 if (raw_data)
79 libraw_close(raw_data);
80 if (seg != MAP_FAILED) munmap(seg, seg_size);
81 close(fd);
82}
83
84static int
85read_raw_header()
86{
87 int ret;
88
89 D("raw_open_buffer\n");
90 if ((ret = libraw_open_buffer(raw_data, seg, seg_size)) != LIBRAW_SUCCESS)
91 return 0;
92
93 D("raw_adjust_size\n");
94 if ((ret = libraw_adjust_sizes_info_only(raw_data)) != LIBRAW_SUCCESS)
95 {
96 if (LIBRAW_FATAL_ERROR(ret))
97 return 0;
98 }
99
100 if ((raw_data->sizes.width < 1) || (raw_data->sizes.height < 1))
101 return 0;
102
103 width = raw_data->sizes.iwidth;
104 height = raw_data->sizes.iheight;
105
106 return 1;
107
108}
109
110
111static int
112read_raw_data()
113{
114 int ret;
115 unsigned int count;
116 libraw_processed_image_t *image = NULL;
117 DATA8 *bufptr;
118 DATA32 *dataptr;
119
120
121 D("raw_open_unpack\n");
122 if ((ret = libraw_unpack(raw_data)) != LIBRAW_SUCCESS)
123 return 0;
124
125 D("raw_dcraw_process\n");
126 if ((ret = libraw_dcraw_process(raw_data)) != LIBRAW_SUCCESS)
127 {
128 if (LIBRAW_FATAL_ERROR(ret))
129 return 0;;
130 }
131
132 D("raw_make_mem_image\n");
133 image = libraw_dcraw_make_mem_image(raw_data, &ret);
134 if (image)
135 {
136 if ((image->width < 1) || (image->height < 1))
137 goto clean_image;
138 width = image->width;
139 height = image->height;
140 if (image->type != LIBRAW_IMAGE_BITMAP)
141 goto clean_image;
142 if (image->colors != 3)
143 goto clean_image;
144#define SWAP(a, b) { a ^= b; a = (b ^=a); }
145 if ((image->bits == 16) && (htons(0x55aa) != 0x55aa))
146 for (count = 0; count < image->data_size; count +=2)
147 SWAP(image->data[count], image->data[count + 1]);
148#undef SWAP
149 shm_alloc((unsigned int)(image->width * image->height) * (sizeof(DATA32)));
150 if (!shm_addr)
151 goto clean_image;
152 data = shm_addr;
153 memset(shm_addr, 0, (unsigned int)(image->width * image->height) * (sizeof(DATA32)));
154 dataptr = data;
155 bufptr = image->data;
156 for (count = (unsigned int)(image->width * image->height); count > 0; --count)
157 {
158 *dataptr = ARGB_JOIN(0xff, bufptr[0], bufptr[1], bufptr[2]);
159 dataptr++;
160 bufptr += 3;
161 }
162
163 free(image);
164 }
165 return 1;
166
167clean_image:
168 free(image);
169 return 0;
170}
171
172
173int main(int argc, char **argv)
174{
175 char *file;
176 int i;
177 int head_only = 0;
178
179 if (argc < 2) return -1;
180 file = argv[1];
181
182 for (i = 2; i < argc; ++i)
183 {
184 if (!strcmp(argv[i], "-head"))
185 head_only = 1;
186 else if (!strcmp(argv[i], "-key"))
187 { // not used by raw loader
188 i++;
189 // const char *key = argv[i];
190 }
191 else if (!strcmp(argv[i], "-opt-scale-down-by"))
192 { // not used by raw loader
193 i++;
194 // int scale_down = atoi(argv[i]);
195 }
196 else if (!strcmp(argv[i], "-opt-dpi"))
197 { // not used by raw loader
198 i++;
199 // double dpi = ((double)atoi(argv[i])) / 1000.0;
200 }
201 else if (!strcmp(argv[i], "-opt-size"))
202 { // not used by raw loader
203 i++;
204 // int size_w = atoi(argv[i]);
205 i++;
206 // int size_h = atoi(argv[i]);
207 }
208 }
209
210 timeout_init(4);
211
212 if (!_raw_init(file)) return -1;
213 if (head_only != 0)
214 {
215 if (read_raw_header())
216 {
217 printf("size %d %d\n", width, height);
218 printf("alpha 1\n");
219 }
220 printf("done\n");
221 }
222 else
223 {
224 if (read_raw_data())
225 {
226 printf("size %d %d\n", width, height);
227 printf("alpha 1\n");
228 if (shm_fd >= 0) printf("shmfile %s\n", shmfile);
229 else
230 {
231 printf("data\n");
232 fwrite(data, (unsigned int)(width * height) * sizeof(DATA32), 1, stdout);
233 }
234 shm_free();
235 }
236 }
237 _raw_shutdown();
238 fflush(stdout);
239 return 0;
240
241}
242
diff --git a/src/generic/evas/svg/main.c b/src/generic/evas/svg/main.c
new file mode 100644
index 0000000..5fc7912
--- /dev/null
+++ b/src/generic/evas/svg/main.c
@@ -0,0 +1,230 @@
1#ifdef HAVE_CONFIG_H
2#include <config.h>
3#endif
4#include <stdio.h>
5#include "shmfile.h"
6#include "timeout.h"
7
8#include <Eina.h>
9
10#include <librsvg/rsvg.h>
11#ifndef LIBRSVG_CHECK_VERSION
12# include <librsvg/librsvg-features.h>
13#endif
14#if LIBRSVG_CHECK_VERSION(2,36,2)
15#else
16# include <librsvg/rsvg-cairo.h>
17#endif
18
19#define DATA32 unsigned int
20
21static RsvgHandle *rsvg = NULL;
22static int width = 0;
23static int height = 0;
24static RsvgDimensionData dim;
25
26static inline Eina_Bool evas_image_load_file_is_svg(const char *file)
27{
28 int i, len = strlen(file);
29 Eina_Bool is_gz = EINA_FALSE;
30
31 for (i = len - 1; i > 0; i--)
32 {
33 if (file[i] == '.')
34 {
35 if (is_gz)
36 break;
37 else if (strcasecmp(file + i + 1, "gz") == 0)
38 is_gz = EINA_TRUE;
39 else
40 break;
41 }
42 }
43
44 if (i < 1) return EINA_FALSE;
45 i++;
46 if (i >= len) return EINA_FALSE;
47 if (strncasecmp(file + i, "svg", 3) != 0) return EINA_FALSE;
48 i += 3;
49 if (is_gz)
50 {
51 if (file[i] == '.') return EINA_TRUE;
52 else return EINA_FALSE;
53 }
54 else
55 {
56 if (file[i] == '\0') return EINA_TRUE;
57 else if (((file[i] == 'z') || (file[i] == 'Z')) && (!file[i + 1])) return EINA_TRUE;
58 else return EINA_FALSE;
59 }
60}
61
62static int
63_svg_init(const char *file)
64{
65#ifdef HAVE_SVG_2_36
66# if !defined(GLIB_VERSION_2_36)
67 g_type_init();
68# endif
69#else
70 rsvg_init();
71#endif
72
73 if (!evas_image_load_file_is_svg(file)) return 0;
74
75 rsvg = rsvg_handle_new_from_file(file, NULL);
76
77 return 1;
78}
79
80static void
81_svg_shutdown(void)
82{
83 if (rsvg)
84 {
85 rsvg_handle_close(rsvg, NULL);
86 g_object_unref(rsvg);
87 }
88 // Maybe it's not crashing anymore, let's try it.
89#ifndef HAVE_SVG_2_36
90 rsvg_term();
91#endif
92}
93
94static int
95read_svg_header(int scale_down, double dpi, int size_w, int size_h)
96{
97 rsvg_handle_set_dpi(rsvg, 75.0);
98 rsvg_handle_get_dimensions(rsvg, &dim);
99 width = dim.width;
100 height = dim.height;
101
102 if ((width < 1) || (height < 1)) return 0;
103
104 if (scale_down > 1)
105 {
106 width /= scale_down;
107 height /= scale_down;
108 }
109 else if (dpi > 0.0)
110 {
111 width = (width * dpi) / 75;
112 height = (height * dpi) / 75;
113 }
114 else if (size_w > 0 && size_h > 0)
115 {
116 int w, h;
117
118 w = size_w;
119 h = (size_w * height) / width;
120 if (h > size_h)
121 {
122 h = size_h;
123 w = (size_h * width) / height;
124 }
125 width = w;
126 height = h;
127 }
128 if (width < 1) width = 1;
129 if (height < 1) height = 1;
130
131 return 1;
132}
133
134static int
135read_svg_data(void)
136{
137 cairo_surface_t *surface;
138 cairo_t *cr;
139
140 shm_alloc(width * height * (sizeof(DATA32)));
141 if (!shm_addr) return 0;
142
143 memset(shm_addr, 0, width * height * sizeof (DATA32));
144 surface = cairo_image_surface_create_for_data((unsigned char *)shm_addr, CAIRO_FORMAT_ARGB32,
145 width, height, width * sizeof(DATA32));;
146 if (!surface) return 0;
147
148 cr = cairo_create(surface);
149 if (!cr) return 0;
150
151 cairo_scale(cr, (double) width / dim.em, (double) height / dim.ex);
152 rsvg_handle_render_cairo(rsvg, cr);
153 cairo_surface_destroy(surface);
154 cairo_destroy(cr);
155
156 return 1;
157}
158
159int main(int argc, char **argv)
160{
161 char *file;
162 int i;
163 int head_only = 0;
164 int scale_down = 0;
165 double dpi = 0.0;
166 int size_w = 0, size_h = 0;
167
168 if (argc < 2) return -1;
169 file = argv[1];
170
171 for (i = 2; i < argc; ++i)
172 {
173 if (!strcmp(argv[i], "-head"))
174 head_only = 1;
175 else if (!strcmp(argv[i], "-key"))
176 { // not used by svg loader
177 i++;
178 // const char *key = argv[i];
179 }
180 else if (!strcmp(argv[i], "-opt-scale-down-by"))
181 {
182 i++;
183 scale_down = atoi(argv[i]);
184 }
185 else if (!strcmp(argv[i], "-opt-dpi"))
186 {
187 i++;
188 dpi = ((double)atoi(argv[i])) / 1000.0;
189 }
190 else if (!strcmp(argv[i], "-opt-size"))
191 {
192 i++;
193 size_w = atoi(argv[i]);
194 i++;
195 size_h = atoi(argv[i]);
196 }
197 }
198
199 timeout_init(5);
200
201 if (!_svg_init(file)) return -1;
202 if (!read_svg_header(scale_down, dpi, size_w, size_h)) return -1;
203
204 if (head_only != 0)
205 {
206 printf("size %d %d\n", width, height);
207 printf("alpha 1\n");
208 printf("done\n");
209 }
210 else
211 {
212 if (read_svg_data())
213 {
214 printf("size %d %d\n", width, height);
215 printf("alpha 1\n");
216 if (shm_fd >= 0) printf("shmfile %s\n", shmfile);
217 else
218 {
219 printf("data\n");
220 fwrite(shm_addr, width * height * sizeof(DATA32), 1, stdout);
221 }
222 shm_free();
223 }
224 }
225 _svg_shutdown();
226 fflush(stdout);
227 return 0;
228
229}
230
diff --git a/src/generic/evas/xcf/common.h b/src/generic/evas/xcf/common.h
new file mode 100644
index 0000000..5abaab8
--- /dev/null
+++ b/src/generic/evas/xcf/common.h
@@ -0,0 +1,51 @@
1#ifndef __COMMON
2#define __COMMON 1
3
4#ifdef HAVE_CONFIG_H
5# include <config.h>
6#endif
7
8#include <stdio.h>
9#include <stdlib.h>
10#include <sys/types.h>
11#include <unistd.h>
12#include <math.h>
13#include <netinet/in.h>
14#include <time.h>
15#include <sys/mman.h>
16#include <sys/stat.h>
17#include <fcntl.h>
18#include <string.h>
19#include <zlib.h>
20
21#define DATABIG unsigned long long
22#define DATA64 unsigned long long
23#define DATA32 unsigned int
24#define DATA16 unsigned short
25#define DATA8 unsigned char
26
27#ifndef WORDS_BIGENDIAN
28
29#define A_VAL(p) ((DATA8 *)(p))[3]
30#define R_VAL(p) ((DATA8 *)(p))[2]
31#define G_VAL(p) ((DATA8 *)(p))[1]
32#define B_VAL(p) ((DATA8 *)(p))[0]
33
34#else
35
36#define A_VAL(p) ((DATA8 *)(p))[0]
37#define R_VAL(p) ((DATA8 *)(p))[1]
38#define G_VAL(p) ((DATA8 *)(p))[2]
39#define B_VAL(p) ((DATA8 *)(p))[3]
40
41#endif
42
43//#define XCF_DBG 1
44
45#ifdef XCF_DBG
46#define D(fmt, args...) fprintf(stderr, fmt, ## args)
47#else
48#define D(fmt, args...)
49#endif
50
51#endif
diff --git a/src/generic/evas/xcf/main.c b/src/generic/evas/xcf/main.c
new file mode 100644
index 0000000..373823b
--- /dev/null
+++ b/src/generic/evas/xcf/main.c
@@ -0,0 +1,1731 @@
1/*
2
3 -----------------------------[ XCF Loader ]-----------------------------
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2, or (at your option)
8 any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software Foundation,
17 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19 ------------------------------------------------------------------------
20
21 There's a quick overview of the XCF file structure in Gimp's source
22 tree, in docs/xcf.doc. However it's brief, so here's a more verbose
23 overview based on my understanding of XCF. All image characteristics
24 are defined in "properties". In the data stream properties are defined
25 through a 4 bit index number (see enum below), followed by a 4 byte
26 length. The property data directly follows this information. A list of
27 properties ends when PROP_END is encountered. There is a properties
28 block at the beginning of the file, as well as at the beginning of each
29 layer and channel. Layers and channels are read at offsets in the file,
30 the list of layers (resp. channels) is exhausted when the next offset
31 read in is zero.
32
33 The actual image data is stored in tiles, which are by default 64x64 in
34 size, likely with smaller ones on the right and bottom edges.
35
36 The position of the tiles on the image is left->right, row by row. The
37 actual DATA8* data is contained in a "level" which is contained in a
38 "hierarchy". I've not really understood the purpose of the hierarchy, as
39 it seems to always contain only one level anyway.
40
41 Layer masks are stored as channels (basically grayscale layers with a
42 single color definition. For the purpose of this loader I replaced the
43 concept of a channel with a layer, since it doesn't really matter.
44
45 Ok, hope this helps with understanding XCF. -- cK.
46
47*/
48#include "common.h"
49#include "shmfile.h"
50#include "timeout.h"
51
52#define FREE(X) { free(X); X = NULL; }
53
54#define TILE_WIDTH 64
55#define TILE_HEIGHT 64
56
57/* --------------------------------------------------------------------------- typedefs ------------ */
58
59typedef struct _Layer Layer;
60typedef struct _Tile Tile;
61
62/* ------------------------------------------------------------------------------ enums ------------ */
63
64
65/* These are all the properties that a layer or channel can have.
66 Only some of them are actually used. */
67typedef enum
68{
69 PROP_END = 0,
70 PROP_COLORMAP = 1,
71 PROP_ACTIVE_LAYER = 2,
72 PROP_ACTIVE_CHANNEL = 3,
73 PROP_SELECTION = 4,
74 PROP_FLOATING_SELECTION = 5,
75 PROP_OPACITY = 6,
76 PROP_MODE = 7,
77 PROP_VISIBLE = 8,
78 PROP_LINKED = 9,
79 PROP_PRESERVE_TRANSPARENCY = 10,
80 PROP_APPLY_MASK = 11,
81 PROP_EDIT_MASK = 12,
82 PROP_SHOW_MASK = 13,
83 PROP_SHOW_MASKED = 14,
84 PROP_OFFSETS = 15,
85 PROP_COLOR = 16,
86 PROP_COMPRESSION = 17,
87 PROP_GUIDES = 18,
88 PROP_RESOLUTION = 19,
89 PROP_TATTOO = 20,
90 PROP_PARASITES = 21,
91 PROP_UNIT = 22,
92 PROP_PATHS = 23,
93 PROP_USER_UNIT = 24
94}
95PropType;
96
97/* The tiles can be stored in an encrypted fashion, defined as follows: */
98typedef enum
99{
100 COMPRESS_NONE = 0,
101 COMPRESS_RLE = 1,
102 COMPRESS_ZLIB = 2,
103 COMPRESS_FRACTAL = 3 /* Unused. */
104} CompressionType;
105
106/* Layer modes (*SIGH*) */
107typedef enum
108{
109 NORMAL_MODE,
110 DISSOLVE_MODE,
111 BEHIND_MODE,
112 MULTIPLY_MODE,
113 SCREEN_MODE,
114 OVERLAY_MODE,
115 DIFFERENCE_MODE,
116 ADDITION_MODE,
117 SUBTRACT_MODE,
118 DARKEN_ONLY_MODE,
119 LIGHTEN_ONLY_MODE,
120 HUE_MODE,
121 SATURATION_MODE,
122 COLOR_MODE,
123 VALUE_MODE,
124 DIVIDE_MODE,
125 ERASE_MODE, /*< skip >*/
126 REPLACE_MODE, /*< skip >*/
127 ANTI_ERASE_MODE /*< skip >*/
128}
129LayerModeEffects;
130
131/* Base image types */
132typedef enum
133{
134 RGB,
135 GRAY,
136 INDEXED
137} GimpImageBaseType;
138
139/* Image types */
140typedef enum
141{
142 RGB_GIMAGE,
143 RGBA_GIMAGE,
144 GRAY_GIMAGE,
145 GRAYA_GIMAGE,
146 INDEXED_GIMAGE,
147 INDEXEDA_GIMAGE
148} GimpImageType;
149
150/* ---------------------------------------------------------------------------- structs ------------ */
151
152/* Ok, this is what's left of Gimp's layer abstraction. I kicked out
153 all the stuff that's unnecessary and added the necessary stuff
154 from the Gimp drawable superclass. This one also serves as a
155 Channel, e.g. for use as a layer mask.
156 --cK.
157*/
158struct _Layer
159{
160 int visible; /* controls visibility */
161 int width, height; /* size of drawable */
162 int bpp; /* depth */
163 int offset_x, offset_y; /* offset of layer in image */
164
165 int ID; /* provides a unique ID */
166 GimpImageType type; /* type of drawable */
167 char has_alpha; /* drawable has alpha */
168
169 int preserve_trans; /* preserve transparency */
170
171 Layer *mask; /* possible layer mask */
172
173 int opacity; /* layer opacity */
174 LayerModeEffects mode; /* layer combination mode */
175
176
177 /* XCF stores the actual image data as tiles. A Layer is covered with
178 tiles, the tiles on the right and bottom will (usually) be a bit
179 smaller. num_rows and num_cols gives the number of tile rows and
180 columns.
181 */
182
183 Tile* tiles; /* tiles for drawable data */
184 int num_rows;
185 int num_cols;
186
187 /* After the tiles are read in, they're serialized int an array
188 of DATA8's, that will always contain 4 bpp data. Not optimal,
189 I know, but makes life easier
190 */
191
192 DATA8* data;
193
194 /* Layers are stored as a linked list. */
195 struct _Layer* next;
196 struct _Layer* prev;
197};
198
199
200/* The tile structure:
201*/
202struct _Tile
203{
204 unsigned char bpp; /* the bytes per pixel (1, 2, 3 or 4) */
205 unsigned short ewidth; /* the effective width of the tile */
206 unsigned short eheight; /* the effective height of the tile */
207
208 /* a tile's effective width and height may be smaller
209 * (but not larger) than TILE_WIDTH and TILE_HEIGHT.
210 * This is to handle edge tiles of a drawable.
211 */
212
213 DATA8 *data;
214};
215
216
217/* This struct simply contains everything that didn't fit elsewhere,
218 based on GimpImage :)
219*/
220struct _GimpImage
221{
222 void *file;
223 char *filename;
224 long cp;
225 int compression; /* file compression mode */
226 int file_version;
227
228 int width, height; /* width and height attributes */
229 GimpImageBaseType base_type; /* base gimp_image type */
230
231 DATA32 floating_sel_offset;
232
233 DATA8* cmap; /* colormap--for indexed */
234 int num_cols; /* number of colors in map */
235
236 /* If a layer number was passed to the loader, it goes here: */
237 int single_layer_index;
238
239 /* Tadaa -- the final image data. Layers get pasted
240 onto this one, bottom-up.
241 */
242 DATA8* data;
243
244 Layer* layers;
245 Layer* last_layer;
246 Layer* floating_sel;
247}
248_image;
249
250/* ------------------------------------------------------------------------- prototypes ------------ */
251
252typedef struct _File File;
253typedef struct _Chunk Chunk;
254
255#define FBUF 1
256#define CHUNK_SIZE (32 * 1024)
257
258struct _Chunk
259{
260 int size;
261 unsigned char data[CHUNK_SIZE];
262};
263
264struct _File
265{
266 int fd;
267 gzFile fp;
268 long pos, size;
269 int chunk_num;
270 Chunk **chunk;
271};
272
273static File *
274f_open(const char *file)
275{
276 File *f;
277
278 f = calloc(1, sizeof(File));
279 if (!f) return NULL;
280 f->fd = open(file, O_RDONLY);
281 if (f->fd < 0)
282 {
283 D("open of %s failed\n", file);
284 free(f);
285 return NULL;
286 }
287 f->fp = gzdopen(f->fd, "r");
288 if (!f->fp)
289 {
290 D("gzdopen of %i failed\n", f->fd);
291 close(f->fd);
292 free(f);
293 return NULL;
294 }
295 return f;
296}
297
298static void
299f_close(File *f)
300{
301 // FIXME: free chunks
302 gzclose(f->fp);
303 free(f);
304}
305
306#ifdef FBUF
307static void
308_f_read_pos(File *f, long pos, long bytes)
309{
310 long i, cnum;
311 Chunk **cks;
312
313 if (f->size > 0) return;
314 cnum = ((pos + bytes) / CHUNK_SIZE) + 1;
315 if (f->chunk_num >= cnum) return;
316 D("FFFF: go up to %li + %li, chunks %li\n", pos, bytes, cnum);
317 cks = realloc(f->chunk, sizeof(Chunk *) * cnum);
318 if (!cks) return;
319 f->chunk = cks;
320 for (i = f->chunk_num; i < cnum; i++)
321 {
322 if (f->size != 0)
323 {
324 f->chunk[i] = NULL;
325 continue;
326 }
327 f->chunk[i] = malloc(sizeof(Chunk));
328 if (f->chunk[i])
329 {
330 f->chunk[i]->size = gzread(f->fp, f->chunk[i]->data, CHUNK_SIZE);
331 D("FFFF: go %i\n", f->chunk[i]->size);
332 if (f->chunk[i]->size < CHUNK_SIZE)
333 {
334 f->size = (i * CHUNK_SIZE) + f->chunk[i]->size;
335 }
336 }
337 }
338 f->chunk_num = cnum;
339}
340#endif
341
342static long
343f_read(File *f, unsigned char *dest, long bytes)
344{
345#ifdef FBUF
346 long done = 0, off = 0;
347 int c;
348 unsigned char *p;
349 _f_read_pos(f, f->pos, bytes);
350
351 c = f->pos / CHUNK_SIZE;
352 off = f->pos - (c * CHUNK_SIZE);
353 p = dest;
354 while ((done < bytes) && (c < f->chunk_num))
355 {
356 long amount = bytes - done;
357
358 if (!f->chunk[c]) break;
359 if (amount > (f->chunk[c]->size - off))
360 amount = (f->chunk[c]->size - off);
361 if (amount < 1) return 0;
362 memcpy(p, f->chunk[c]->data + off, amount);
363 p += amount;
364 off = 0;
365 done += amount;
366 c++;
367 }
368 f->pos += done;
369 return done;
370#else
371 long done = gzread(f->fp, dest, bytes);
372 f->pos += done;
373 return done;
374#endif
375}
376
377static void
378f_seek(File *f, long pos)
379{
380#ifdef FBUF
381 if (f->size > 0)
382 {
383 if (pos >= f->size) pos = f->size -1;
384 }
385#endif
386 if (f->pos == pos) return;
387 f->pos = pos;
388#ifdef FBUF
389 _f_read_pos(f, f->pos, 1);
390#else
391 gzseek(f->fp, f->pos, SEEK_SET);
392#endif
393}
394
395
396/* stuff that was adapted from xcf.c */
397
398static void xcf_seek_pos(int pos);
399static int xcf_read_int32(void *fp, DATA32 *data, int count);
400static int xcf_read_int8(void *fp, DATA8 *data, int count);
401static int xcf_read_string(void *fp, char **data, int count);
402static char xcf_load_prop(PropType *prop_type, DATA32 *prop_size);
403static void xcf_load_image(void);
404static char xcf_load_image_props(void);
405
406static Layer* xcf_load_channel(void);
407static char xcf_load_channel_props(Layer *layer);
408static Layer* xcf_load_layer(void);
409static char xcf_load_layer_props(Layer *layer);
410static char xcf_load_hierarchy(Tile** tiles, int *num_rows, int *num_cols, int *bpp);
411static char xcf_load_level(Tile** tiles, int hierarchy_width, int hierarchy_height, int bpp, int* num_rows, int *num_cols);
412static char xcf_load_tile(Tile *tile);
413static char xcf_load_tile_rle(Tile *tile, int data_length);
414
415/* new stuff :) */
416
417static Tile* allocate_tiles(int width, int height, int bpp, int* num_rows, int* num_cols);
418static void free_tiles(Tile* tiles, int num_tiles);
419static void init_tile(Tile* tile, int width, int height, int bpp);
420static Layer* new_layer(int width, int height, GimpImageType type, int opacity, LayerModeEffects mode);
421static void free_layer(Layer* layer);
422static void add_layer_to_image(Layer* layer);
423static void read_tiles_into_data(Tile* tiles, int num_cols, int width, int height, int bpp, DATA8** data, int use_cmap);
424static void apply_layer_mask(Layer* layer);
425static void set_layer_opacity(Layer* layer);
426static void flatten_image(void);
427
428static char xcf_file_init(char* filename);
429static void xcf_cleanup(void);
430
431/* Stuff for layer merging: */
432extern void combine_pixels_normal (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y);
433extern void combine_pixels_add (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y);
434extern void combine_pixels_sub (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y);
435extern void combine_pixels_diff (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y);
436extern void combine_pixels_darken (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y);
437extern void combine_pixels_lighten (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y);
438extern void combine_pixels_mult (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y);
439extern void combine_pixels_div (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y);
440extern void combine_pixels_screen (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y);
441extern void combine_pixels_overlay (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y);
442extern void combine_pixels_hue (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y);
443extern void combine_pixels_sat (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y);
444extern void combine_pixels_val (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y);
445extern void combine_pixels_col (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y);
446extern void combine_pixels_diss (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y);
447
448/* ---------------------------------------------------------------------------- globals ------------ */
449
450/* This makes using the Gimp sources easier */
451static struct _GimpImage * image = &_image;
452
453/* ------------------------------------------------------------------------------- code ------------ */
454
455static void
456xcf_seek_pos(int pos)
457{
458 if (image->cp != pos)
459 {
460 image->cp = pos;
461 f_seek(image->file, image->cp);
462 }
463}
464
465static int
466xcf_read_int32(void *fp,
467 DATA32 *data,
468 int count)
469{
470 int total;
471
472 total = count;
473 if (count > 0)
474 {
475 xcf_read_int8(fp, (DATA8*) data, count * 4);
476 while (count--)
477 {
478 *data = (DATA32)ntohl(*data);
479 data++;
480 }
481 }
482 return total * 4;
483}
484
485static int
486xcf_read_int8(void *fp,
487 DATA8 *data,
488 int count)
489{
490 int total;
491 int bytes;
492
493 total = count;
494 while (count > 0)
495 {
496 bytes = f_read(fp, data, count);
497 if (bytes <= 0) /* something bad happened */
498 break;
499 count -= bytes;
500 data += bytes;
501 }
502 return total;
503}
504
505static int
506xcf_read_string(void *fp,
507 char **data,
508 int count)
509{
510 DATA32 tmp;
511 int total;
512 int i;
513
514 total = 0;
515 for (i = 0; i < count; i++)
516 {
517 total += xcf_read_int32(fp, &tmp, 1);
518 if (tmp > 0)
519 {
520 data[i] = malloc(sizeof(DATA8) * tmp);
521 if (data[i]) total += xcf_read_int8(fp, (DATA8 *)data[i], tmp);
522 }
523 else
524 data[i] = NULL;
525 }
526 return total;
527}
528
529
530static char
531xcf_load_prop(PropType *prop_type,
532 DATA32 *prop_size)
533{
534 image->cp += xcf_read_int32(image->file, (DATA32 *)prop_type, 1);
535 image->cp += xcf_read_int32(image->file, (DATA32 *)prop_size, 1);
536 return 1;
537}
538
539
540static char
541xcf_load_image_props(void)
542{
543 PropType prop_type;
544 DATA32 prop_size;
545
546 while (1)
547 {
548 if (!xcf_load_prop (&prop_type, &prop_size)) return 0;
549 switch (prop_type)
550 {
551 case PROP_END:
552 {
553 D("Finished reading image properties.\n");
554 return 1;
555 }
556 case PROP_COLORMAP:
557 {
558 if (image->file_version == 0)
559 {
560 int i;
561 fprintf (stderr,
562 "XCF warning: version 0 of XCF file format\n"
563 "did not save indexed colormaps correctly.\n"
564 "Substituting grayscale map.\n");
565 image->cp += xcf_read_int32(image->file, (DATA32 *)&image->num_cols, 1);
566 image->cmap = malloc(sizeof(DATA8) * image->num_cols * 3);
567 if (!image->cmap) return 0;
568 xcf_seek_pos (image->cp + image->num_cols);
569 for (i = 0; i < image->num_cols; i++)
570 {
571 image->cmap[(i * 3) + 0] = i;
572 image->cmap[(i * 3) + 1] = i;
573 image->cmap[(i * 3) + 2] = i;
574 }
575 }
576 else
577 {
578 D("Loading colormap.\n");
579 image->cp += xcf_read_int32(image->file, (DATA32 *)&image->num_cols, 1);
580 image->cmap = malloc(sizeof(DATA8) * image->num_cols * 3);
581 if (!image->cmap) return 0;
582 image->cp += xcf_read_int8(image->file, (DATA8 *)image->cmap, image->num_cols * 3);
583 }
584 }
585 break;
586 case PROP_COMPRESSION:
587 {
588 char compression;
589
590 image->cp += xcf_read_int8(image->file, (DATA8 *)&compression, 1);
591
592 if ((compression != COMPRESS_NONE) &&
593 (compression != COMPRESS_RLE) &&
594 (compression != COMPRESS_ZLIB) &&
595 (compression != COMPRESS_FRACTAL))
596 {
597 fprintf (stderr, "unknown xcf compression type: %d\n", (int) compression);
598 return 0;
599 }
600
601 D("Image compression type: %i\n", compression);
602
603 image->compression = compression;
604 }
605 break;
606 /* I threw out all of the following: --cK */
607 case PROP_TATTOO:
608 case PROP_PARASITES:
609 case PROP_UNIT:
610 case PROP_PATHS:
611 case PROP_USER_UNIT:
612 case PROP_GUIDES:
613 case PROP_RESOLUTION:
614 default:
615 {
616 DATA8 buf[16];
617 int amount;
618
619 D("Skipping unexpected/unknown image property: %d\n", prop_type);
620
621 while (prop_size > 0)
622 {
623 amount = (16 < prop_size ? 16 : prop_size);
624 image->cp += xcf_read_int8(image->file, buf, amount);
625 prop_size -= amount;
626 }
627 }
628 break;
629 }
630 }
631 return 0;
632}
633
634
635static void
636xcf_load_image(void)
637{
638 Layer *layer;
639 DATA32 saved_pos;
640 DATA32 offset;
641 int num_successful_elements = 0;
642
643 /* read the image properties */
644 if (!xcf_load_image_props()) goto hard_error;
645
646 while (1)
647 {
648 /* read in the offset of the next layer */
649 image->cp += xcf_read_int32(image->file, &offset, 1);
650 /* if the offset is 0 then we are at the end
651 * of the layer list. */
652 if (offset == 0) break;
653 /* save the current position as it is where the
654 * next layer offset is stored. */
655 saved_pos = image->cp;
656 /* seek to the layer offset */
657 xcf_seek_pos(offset);
658 /* read in the layer */
659 layer = xcf_load_layer();
660 if (!layer) goto error;
661 num_successful_elements++;
662 /* add the layer to the image if it's visible */
663 if (layer->visible) add_layer_to_image(layer);
664 else free_layer(layer);
665 /* restore the saved position so we'll be ready to
666 * read the next offset. */
667 xcf_seek_pos (saved_pos);
668 }
669 /* If we were a Gimp we would now load the user-defined channels here ... */
670 /* Flat-o-rama now :) */
671 flatten_image();
672 return;
673error:
674 if (num_successful_elements == 0) goto hard_error;
675 fprintf(stderr, "XCF: This file is corrupt! I have loaded as much\nof it as I can, but it is incomplete.\n");
676 return;
677hard_error:
678 fprintf(stderr, "XCF: This file is corrupt! I could not even\nsalvage any partial image data from it.\n");
679 return;
680}
681
682static char
683xcf_load_layer_props(Layer *layer)
684{
685 PropType prop_type;
686 DATA32 prop_size;
687
688 while (1)
689 {
690 if (!xcf_load_prop(&prop_type, &prop_size)) return 0;
691 switch (prop_type)
692 {
693 case PROP_END:
694 {
695 D("Finished reading layer properties.\n");
696 return 1;
697 }
698 case PROP_FLOATING_SELECTION:
699 D("Loading floating selection.\n");
700 image->floating_sel = layer;
701 image->cp += xcf_read_int32(image->file, (DATA32 *)&image->floating_sel_offset, 1);
702 break;
703 case PROP_OPACITY:
704 image->cp += xcf_read_int32(image->file, (DATA32 *)&layer->opacity, 1);
705 break;
706 case PROP_VISIBLE:
707 image->cp += xcf_read_int32(image->file, (DATA32 *)&layer->visible, 1);
708 break;
709 case PROP_PRESERVE_TRANSPARENCY:
710 image->cp += xcf_read_int32(image->file, (DATA32 *)&layer->preserve_trans, 1);
711 break;
712 case PROP_OFFSETS:
713 image->cp += xcf_read_int32(image->file, (DATA32 *)&layer->offset_x, 1);
714 image->cp += xcf_read_int32(image->file, (DATA32 *)&layer->offset_y, 1);
715 break;
716 case PROP_MODE:
717 image->cp += xcf_read_int32(image->file, (DATA32 *)&layer->mode, 1);
718 break;
719
720 /* I threw out all of the following: --cK */
721 case PROP_LINKED:
722 case PROP_ACTIVE_LAYER:
723 case PROP_TATTOO:
724 case PROP_APPLY_MASK:
725 case PROP_EDIT_MASK:
726 case PROP_SHOW_MASK:
727 case PROP_PARASITES:
728 default:
729 {
730 DATA8 buf[16];
731 int amount;
732
733 D("Skipping unexpected/unknown/unneeded channel property: %d\n", prop_type);
734 while (prop_size > 0)
735 {
736 amount = (16 < prop_size ? 16 : prop_size);
737 image->cp += xcf_read_int8 (image->file, buf, amount);
738 prop_size -= amount;
739 }
740 }
741 break;
742 }
743 }
744
745 return 0;
746}
747
748
749static Layer *
750xcf_load_layer(void)
751{
752 Layer *layer;
753 Layer *layer_mask;
754 DATA32 hierarchy_offset;
755 DATA32 layer_mask_offset;
756 int width;
757 int height;
758 int type;
759 char *name;
760
761 D("Loading one layer ...\n");
762 /* read in the layer width, height and type */
763 image->cp += xcf_read_int32(image->file, (DATA32 *)&width, 1);
764 image->cp += xcf_read_int32(image->file, (DATA32 *)&height, 1);
765 image->cp += xcf_read_int32(image->file, (DATA32 *)&type, 1);
766 image->cp += xcf_read_string(image->file, &name, 1);
767 /* ugly, I know */
768 FREE(name);
769
770 /* create a new layer */
771 layer = new_layer(width, height, type, 255, NORMAL_MODE);
772 if (!layer) return NULL;
773
774 /* read in the layer properties */
775 if (!xcf_load_layer_props(layer)) goto error;
776
777 D("Loading opacity: %i \n", layer->opacity);
778 if (!layer->visible) return layer;
779
780 /* read the hierarchy and layer mask offsets */
781 image->cp += xcf_read_int32(image->file, &hierarchy_offset, 1);
782 image->cp += xcf_read_int32(image->file, &layer_mask_offset, 1);
783 /* read in the hierarchy */
784 xcf_seek_pos(hierarchy_offset);
785 if (!xcf_load_hierarchy(&(layer->tiles), &(layer->num_rows),
786 &(layer->num_cols), &(layer->bpp)))
787 goto error;
788
789 /* read in the layer mask */
790 if (layer_mask_offset != 0)
791 {
792 D("Loading layer mask.\n");
793 xcf_seek_pos(layer_mask_offset);
794
795 layer_mask = xcf_load_channel();
796 if (!layer_mask) goto error;
797
798 /* set the offsets of the layer_mask */
799 layer_mask->offset_x = layer->offset_x;
800 layer_mask->offset_y = layer->offset_y;
801 layer->mask = layer_mask;
802 }
803 read_tiles_into_data(layer->tiles, layer->num_cols,
804 layer->width, layer->height,
805 layer->bpp, &(layer->data),
806 1);
807 free_tiles(layer->tiles, layer->num_rows * layer->num_cols);
808 layer->tiles = NULL;
809 set_layer_opacity(layer);
810 if (layer->mask) apply_layer_mask(layer);
811
812 return layer;
813
814error:
815 free_layer(layer);
816 return NULL;
817}
818
819
820static void
821read_tiles_into_data(Tile *tiles, int num_cols, int width,
822 int height, int bpp, DATA8 **data_p, int use_cmap)
823{
824 int tile_x, tile_y, x, y, offset_x, offset_y;
825 DATA8 *data;
826 DATA8 *ptr;
827 DATA8 *ptr2;
828 Tile *t;
829 int warned = 0;
830
831 if (tiles)
832 {
833 if (*data_p) FREE(*data_p);
834
835 /* Always allocate the data as 4 bytes per pixel */
836 data = (*data_p) = malloc(sizeof(DATA32) * width * height);
837 if (!data) return;
838
839 ptr = data;
840 for (y = 0; y < height; y++)
841 {
842 for (x = 0; x < width; x++)
843 {
844 tile_x = x / TILE_WIDTH;
845 tile_y = y / TILE_HEIGHT;
846 offset_x = x % TILE_WIDTH;
847 offset_y = y % TILE_HEIGHT;
848
849 t = &tiles[(tile_y * num_cols) + tile_x];
850 ptr2 = &(t->data[(offset_y * t->ewidth * bpp) +
851 (offset_x * bpp)]);
852 switch (bpp)
853 {
854 case 1:
855 {
856 /* use colormap if the image has one */
857 if (image->cmap && use_cmap)
858 {
859 R_VAL(ptr) = image->cmap[(*(ptr2) * 3)];
860 G_VAL(ptr) = image->cmap[(*(ptr2) * 3) + 1];
861 B_VAL(ptr) = image->cmap[(*(ptr2) * 3) + 2];
862 A_VAL(ptr) = 255;
863 }
864 /* else use colors themselves */
865 else
866 {
867 R_VAL(ptr) = *(ptr2);
868 G_VAL(ptr) = *(ptr2);
869 B_VAL(ptr) = *(ptr2);
870 A_VAL(ptr) = 255;
871 }
872 break;
873 }
874 case 2:
875 {
876 /* use colormap if the image has one */
877 if (image->cmap && use_cmap)
878 {
879 R_VAL(ptr) = image->cmap[(*(ptr2) * 3)];
880 G_VAL(ptr) = image->cmap[(*(ptr2) * 3) + 1];
881 B_VAL(ptr) = image->cmap[(*(ptr2) * 3) + 2];
882 A_VAL(ptr) = *(ptr2 + 1);
883 }
884 /* else use colors themselves */
885 else if (warned == 0)
886 {
887 warned++;
888 fprintf (stderr, "There's nothing to see here. 2 bpp without colormap not implemented yet.\n");
889 }
890 break;
891 }
892 case 3:
893 {
894 if (image->cmap)
895 {
896 if (warned == 0)
897 {
898 warned++;
899 fprintf (stderr, "There's nothing to see here. 3 bpp with colormap not implemented yet.\n");
900 }
901 }
902 else
903 {
904 R_VAL(ptr) = *(ptr2);
905 G_VAL(ptr) = *(ptr2 + 1);
906 B_VAL(ptr) = *(ptr2 + 2);
907 A_VAL(ptr) = 255;
908 }
909 break;
910 }
911 default:
912 {
913 R_VAL(ptr) = *(ptr2);
914 G_VAL(ptr) = *(ptr2 + 1);
915 B_VAL(ptr) = *(ptr2 + 2);
916 A_VAL(ptr) = *(ptr2 + 3);
917 break;
918 }
919 }
920 ptr += 4;
921 }
922 }
923 }
924}
925
926static Layer *
927xcf_load_channel(void)
928{
929 Layer *layer;
930 DATA32 hierarchy_offset;
931 int width;
932 int height;
933 char *name;
934
935 D("Loading channel ...\n");
936 /* read in the layer width, height and name */
937 image->cp += xcf_read_int32(image->file, (DATA32 *)&width, 1);
938 image->cp += xcf_read_int32(image->file, (DATA32 *)&height, 1);
939 image->cp += xcf_read_string(image->file, &name, 1);
940
941 /* Yeah, still ugly :) */
942 FREE(name);
943
944 /* create a new channel */
945 layer = new_layer(width, height, GRAY_GIMAGE, 255, NORMAL_MODE);
946 if (!layer) return NULL;
947 /* read in the channel properties */
948 if (!xcf_load_channel_props(layer)) goto error;
949 /* read the hierarchy and layer mask offsets */
950 image->cp += xcf_read_int32(image->file, &hierarchy_offset, 1);
951 /* read in the hierarchy */
952 xcf_seek_pos(hierarchy_offset);
953 if (!xcf_load_hierarchy(&(layer->tiles), &(layer->num_rows), &(layer->num_cols), &(layer->bpp)))
954 goto error;
955 read_tiles_into_data(layer->tiles, layer->num_cols, layer->width,
956 layer->height, layer->bpp, &(layer->data), 0);
957 free_tiles(layer->tiles, layer->num_rows * layer->num_cols);
958 layer->tiles = NULL;
959
960 D("Channel loaded successfully.\n");
961 return layer;
962
963error:
964 free_layer(layer);
965 return NULL;
966}
967
968static char
969xcf_load_channel_props(Layer *layer)
970{
971 PropType prop_type;
972 DATA32 prop_size;
973
974 while (1)
975 {
976 if (!xcf_load_prop(&prop_type, &prop_size)) return 0;
977
978 switch (prop_type)
979 {
980 case PROP_END:
981 {
982 D("Finished loading channel props.\n");
983 return 1;
984 }
985 case PROP_OPACITY:
986 image->cp += xcf_read_int32(image->file, (DATA32 *)&layer->opacity, 1);
987 break;
988 case PROP_VISIBLE:
989 image->cp += xcf_read_int32(image->file, (DATA32 *)&layer->visible, 1);
990 break;
991 case PROP_ACTIVE_CHANNEL:
992 case PROP_SHOW_MASKED:
993 case PROP_SELECTION:
994 case PROP_COLOR:
995 case PROP_TATTOO:
996 case PROP_PARASITES:
997 default:
998 {
999 DATA8 buf[16];
1000 int amount;
1001
1002 D("Skipping unexpected/unknown/unneeded channel property: %d\n", prop_type);
1003
1004 while (prop_size > 0)
1005 {
1006 amount = (16 < prop_size ? 16 : prop_size);
1007 image->cp += xcf_read_int8(image->file, buf, amount);
1008 prop_size -= amount;
1009 }
1010 }
1011 break;
1012 }
1013 }
1014 return 0;
1015}
1016
1017static char
1018xcf_load_hierarchy(Tile **tiles, int *num_rows, int *num_cols, int *bpp)
1019{
1020 DATA32 saved_pos;
1021 DATA32 offset;
1022 DATA32 junk;
1023 int width;
1024 int height;
1025
1026 image->cp += xcf_read_int32(image->file, (DATA32 *)&width, 1);
1027 image->cp += xcf_read_int32(image->file, (DATA32 *)&height, 1);
1028 image->cp += xcf_read_int32(image->file, (DATA32 *)bpp, 1);
1029 image->cp += xcf_read_int32(image->file, &offset, 1); /* top level */
1030
1031 D("Loading hierarchy: width %i, height %i, bpp %i\n", width, height, *bpp);
1032
1033 /* discard offsets for layers below first, if any. */
1034 do
1035 {
1036 image->cp += xcf_read_int32(image->file, &junk, 1);
1037 }
1038 while (junk != 0);
1039 /* save the current position as it is where the
1040 * next level offset is stored. */
1041 saved_pos = image->cp;
1042 /* seek to the level offset */
1043 xcf_seek_pos(offset);
1044 /* read in the level */
1045 if (!xcf_load_level(tiles, width, height, *bpp, num_rows, num_cols))
1046 return 0;
1047 /* restore the saved position so we'll be ready to
1048 * read the next offset. */
1049 xcf_seek_pos (saved_pos);
1050 D("Loaded hierarchy successfully.\n");
1051 return 1;
1052}
1053
1054static char
1055xcf_load_level(Tile **tiles_p, int hierarchy_width, int hierarchy_height,
1056 int bpp, int *num_rows, int *num_cols)
1057{
1058 DATA32 saved_pos;
1059 DATA32 offset, offset2;
1060 int ntiles;
1061 int width;
1062 int height;
1063 int i;
1064 int fail;
1065 Tile *tiles;
1066 Tile *current_tile;
1067
1068 image->cp += xcf_read_int32(image->file, (DATA32*) &width, 1);
1069 image->cp += xcf_read_int32(image->file, (DATA32*) &height, 1);
1070
1071 if ((width != hierarchy_width) || (height != hierarchy_height)) return 0;
1072
1073 D("Loading level of size %ix%i.\n", width, height);
1074 (*tiles_p) = allocate_tiles(width, height, bpp, num_rows, num_cols);
1075 tiles = (*tiles_p);
1076
1077 image->cp += xcf_read_int32(image->file, &offset, 1);
1078 if (offset == 0) return 1;
1079
1080 ntiles = (*num_rows) * (*num_cols);
1081 for (i = 0; i < ntiles; i++)
1082 {
1083 current_tile = &(tiles[i]);
1084 fail = 0;
1085
1086 if (offset == 0)
1087 {
1088 D("Not enough tiles found in level\n");
1089 return 0;
1090 }
1091
1092 /* save the current position as it is where the
1093 * next tile offset is stored.
1094 */
1095 saved_pos = image->cp;
1096
1097 /* read in the offset of the next tile so we can calculate the amount
1098 of data needed for this tile*/
1099 image->cp += xcf_read_int32(image->file, &offset2, 1);
1100
1101 /* if the offset is 0 then we need to read in the maximum possible
1102 allowing for negative compression */
1103 if (offset2 == 0)
1104 offset2 = offset + (TILE_WIDTH * TILE_WIDTH * 4 * 1.5);
1105 /* 1.5 is probably more than we need to allow */
1106
1107 /* seek to the tile offset */
1108 xcf_seek_pos(offset);
1109
1110 /* read in the current_tile */
1111 switch (image->compression)
1112 {
1113 case COMPRESS_NONE:
1114 if (!xcf_load_tile(current_tile)) fail = 1;
1115 break;
1116 case COMPRESS_RLE:
1117 if (!xcf_load_tile_rle(current_tile, offset2 - offset)) fail = 1;
1118 break;
1119 case COMPRESS_ZLIB:
1120 fprintf (stderr, "xcf: zlib compression unimplemented\n");
1121 fail = 1;
1122 break;
1123 case COMPRESS_FRACTAL:
1124 fprintf (stderr, "xcf: fractal compression unimplemented\n");
1125 fail = 1;
1126 break;
1127 }
1128
1129 if (fail)
1130 {
1131 D("Couldn't load tiles.\n");
1132 free_tiles(tiles, (*num_rows) * (*num_cols));
1133 return 0;
1134 }
1135 /* restore the saved position so we'll be ready to
1136 * read the next offset.
1137 */
1138 xcf_seek_pos(saved_pos);
1139 /* read in the offset of the next tile */
1140 image->cp += xcf_read_int32(image->file, &offset, 1);
1141 }
1142
1143 if (offset != 0)
1144 {
1145 D("encountered garbage after reading level: %d\n", offset);
1146 return 0;
1147 }
1148
1149 D("Loaded level successfully.\n");
1150 return 1;
1151}
1152
1153static char
1154xcf_load_tile(Tile *tile)
1155{
1156 image->cp += xcf_read_int8(image->file, tile->data,
1157 tile->ewidth * tile->eheight * tile->bpp);
1158 return 1;
1159}
1160
1161static char
1162xcf_load_tile_rle(Tile *tile,
1163 int data_length)
1164{
1165 DATA8 *data;
1166 DATA8 val;
1167 int size;
1168 int count;
1169 int length;
1170 int bpp;
1171 int i, j;
1172 int nmemb_read_successfully;
1173 DATA8 *xcfdata, *xcfodata, *xcfdatalimit;
1174
1175 data = tile->data;
1176 bpp = tile->bpp;
1177
1178 /*printf ("Reading encrypted tile %ix%ix%i, data_length %i\n", tile->ewidth, tile->eheight, tile->bpp, data_length);*/
1179
1180 xcfdata = xcfodata = malloc(sizeof(DATA8) * data_length);
1181 if (!xcfdata) return 0;
1182
1183 /* we have to use fread instead of xcf_read_* because we may be
1184 reading past the end of the file here */
1185 nmemb_read_successfully = f_read(image->file, xcfdata, data_length);
1186 image->cp += nmemb_read_successfully;
1187
1188 xcfdatalimit = &xcfodata[nmemb_read_successfully - 1];
1189
1190 for (i = 0; i < bpp; i++)
1191 {
1192 data = (tile->data) + i;
1193 size = tile->ewidth * tile->eheight;
1194 count = 0;
1195
1196 while (size > 0)
1197 {
1198 if (xcfdata > xcfdatalimit) goto bogus_rle;
1199
1200 val = *xcfdata++;
1201
1202 length = val;
1203 if (length >= 128)
1204 {
1205 length = 255 - (length - 1);
1206 if (length == 128)
1207 {
1208 if (xcfdata >= xcfdatalimit) goto bogus_rle;
1209
1210 length = (*xcfdata << 8) + xcfdata[1];
1211 xcfdata += 2;
1212 }
1213
1214 count += length;
1215 size -= length;
1216
1217 if (size < 0) goto bogus_rle;
1218 if (&xcfdata[length-1] > xcfdatalimit) goto bogus_rle;
1219
1220 while (length-- > 0)
1221 {
1222 *data = *xcfdata++;
1223 data += bpp;
1224 }
1225 }
1226 else
1227 {
1228 length += 1;
1229 if (length == 128)
1230 {
1231 if (xcfdata >= xcfdatalimit) goto bogus_rle;
1232
1233 length = (*xcfdata << 8) + xcfdata[1];
1234 xcfdata += 2;
1235 }
1236
1237 count += length;
1238 size -= length;
1239
1240 if (size < 0) goto bogus_rle;
1241 if (xcfdata > xcfdatalimit) goto bogus_rle;
1242
1243 val = *xcfdata++;
1244
1245 for (j = 0; j < length; j++)
1246 {
1247 *data = val;
1248 data += bpp;
1249 }
1250 }
1251 }
1252 }
1253 FREE(xcfodata);
1254 return 1;
1255
1256bogus_rle:
1257 fprintf(stderr, "WHOOOOOP -- bogus rle? Highly unlikely, blame cK for this one :) \n");
1258 if (xcfodata) FREE(xcfodata);
1259 return 0;
1260}
1261
1262static Layer *
1263new_layer(int width, int height, GimpImageType type, int opacity, LayerModeEffects mode)
1264{
1265 Layer *layer;
1266
1267 layer = calloc(1, sizeof(Layer));
1268 if (!layer)
1269 {
1270 D("Couldn't allocate layer.\n");
1271 return NULL;
1272 }
1273
1274 layer->width = width;
1275 layer->height = height;
1276 layer->type = type;
1277 layer->opacity = opacity;
1278 layer->mode = mode;
1279 layer->tiles = NULL;
1280 layer->next = NULL;
1281 layer->mask = NULL;
1282 return layer;
1283}
1284
1285static void
1286free_layer(Layer *layer)
1287{
1288 if (layer)
1289 {
1290 if (layer->tiles)
1291 free_tiles(layer->tiles, layer->num_rows * layer->num_cols);
1292 if (layer->mask) free_layer(layer->mask);
1293 if (layer->data) FREE(layer->data);
1294 FREE(layer);
1295 }
1296}
1297
1298static Tile *
1299allocate_tiles(int width, int height, int bpp, int* num_rows, int* num_cols)
1300{
1301 Tile* tiles;
1302 int i, j, k, right_tile, bottom_tile;
1303 int tile_width, tile_height;
1304
1305 (*num_rows) = (height + TILE_HEIGHT - 1) / TILE_HEIGHT;
1306 (*num_cols) = (width + TILE_WIDTH - 1) / TILE_WIDTH;
1307
1308 tiles = malloc(sizeof(Tile) * (*num_rows) * (*num_cols));
1309 if (!tiles)
1310 {
1311 D("Couldn't allocate tiles.\n");
1312 return NULL;
1313 }
1314
1315 right_tile = width - (((*num_cols) - 1) * TILE_WIDTH);
1316 bottom_tile = height - (((*num_rows) - 1) * TILE_HEIGHT);
1317
1318 for (i = 0, k = 0; i < (*num_rows); i++)
1319 {
1320 for (j = 0; j < (*num_cols); j++, k++)
1321 {
1322 tile_width = ((j == (*num_cols) - 1) ? right_tile : TILE_WIDTH);
1323 tile_height = ((i == (*num_rows) - 1) ? bottom_tile : TILE_HEIGHT);
1324 init_tile(&(tiles[k]), tile_width, tile_height, bpp);
1325 }
1326 }
1327 D("Allocated %ix%i tiles.\n", (*num_cols), (*num_rows));
1328 return tiles;
1329}
1330
1331static void
1332init_tile(Tile *tile, int width, int height, int bpp)
1333{
1334 if (tile)
1335 {
1336 tile->bpp = bpp;
1337 tile->ewidth = width;
1338 tile->eheight = height;
1339 tile->data = malloc(sizeof(DATA8) * width * height * bpp);
1340 if (!tile->data)
1341 {
1342 D("Couldn't allocate tile.\n");
1343 }
1344 }
1345}
1346
1347static void
1348free_tiles(Tile *tiles, int num_tiles)
1349{
1350 int i;
1351
1352 for (i = 0; i < num_tiles; i++)
1353 {
1354 if (tiles[i].data) FREE(tiles[i].data);
1355 }
1356 FREE(tiles);
1357}
1358
1359static void
1360add_layer_to_image(Layer *layer)
1361{
1362 if (layer)
1363 {
1364 if (image->last_layer)
1365 {
1366 image->last_layer->next = layer;
1367 layer->prev = image->last_layer;
1368 }
1369 else
1370 {
1371 image->layers = layer;
1372 layer->prev = NULL;
1373 }
1374 layer->next = NULL;
1375 image->last_layer = layer;
1376 }
1377}
1378
1379static void
1380set_layer_opacity(Layer *layer)
1381{
1382 int i;
1383 DATA8* ptr;
1384
1385 if (layer)
1386 {
1387 if (layer->opacity != 255)
1388 {
1389 for (i = 0, ptr = layer->data; i < layer->width * layer->height; i++, ptr += 4)
1390 {
1391 *(ptr + 3) = (*(ptr + 3) * layer->opacity) >> 8;
1392 }
1393 }
1394 }
1395}
1396
1397static void
1398apply_layer_mask(Layer *layer)
1399{
1400 DATA8* ptr1;
1401 DATA8* ptr2;
1402 int i, tmp;
1403
1404 D("Applying layer mask.\n");
1405 if (layer)
1406 {
1407 if (layer->mask)
1408 {
1409 ptr1 = layer->data;
1410 ptr2 = layer->mask->data;
1411 for (i = 0; i < layer->width * layer->height; i++)
1412 {
1413 tmp = (*(ptr1 + 3) * *(ptr2)) / 256;
1414 if (tmp > 255) tmp = 255;
1415 *(ptr1 + 3) = (DATA8)tmp;
1416 ptr1 += 4;
1417 ptr2 += 4;
1418 }
1419 }
1420 }
1421}
1422
1423static void
1424flatten_image(void)
1425{
1426 Layer* l = image->last_layer;
1427 Layer* lp;
1428 int layer_index;
1429
1430 shm_alloc(image->width * image->height * sizeof(DATA32));
1431 if (!shm_addr) return;
1432 image->data = shm_addr;
1433 memset(image->data, 0, image->width * image->height * sizeof(DATA32));
1434
1435 layer_index = 0;
1436
1437 while (l)
1438 {
1439 /* Ok, paste each layer on top of the image, using the mode's merging type.
1440 We're moving upward through the layer stack.
1441 --cK.
1442 */
1443 if ((image->single_layer_index < 0) ||
1444 (layer_index == image->single_layer_index))
1445 {
1446 // FIXME: not all modes are implemented right
1447 // xcf's may not render right :)
1448 switch (l->mode)
1449 {
1450 case MULTIPLY_MODE:
1451 D("MULTIPLY\n");
1452 combine_pixels_mult(l->data, l->width, l->height,
1453 image->data, image->width, image->height,
1454 l->offset_x, l->offset_y);
1455 break;
1456 case DIVIDE_MODE:
1457 D("DIVIDE\n");
1458 combine_pixels_div(l->data, l->width, l->height,
1459 image->data, image->width, image->height,
1460 l->offset_x, l->offset_y);
1461 break;
1462 case SCREEN_MODE:
1463 D("SCREEN\n");
1464 combine_pixels_screen(l->data, l->width, l->height,
1465 image->data, image->width, image->height,
1466 l->offset_x, l->offset_y);
1467 break;
1468 case OVERLAY_MODE:
1469 D("OVERLAY\n");
1470 combine_pixels_overlay(l->data, l->width, l->height,
1471 image->data, image->width, image->height,
1472 l->offset_x, l->offset_y);
1473 break;
1474 case DIFFERENCE_MODE:
1475 D("DIFF\n");
1476 combine_pixels_diff(l->data, l->width, l->height,
1477 image->data, image->width, image->height,
1478 l->offset_x, l->offset_y);
1479 break;
1480 case ADDITION_MODE:
1481 D("ADD\n");
1482 combine_pixels_add(l->data, l->width, l->height,
1483 image->data, image->width, image->height,
1484 l->offset_x, l->offset_y);
1485 break;
1486 case SUBTRACT_MODE:
1487 D("SUB\n");
1488 combine_pixels_sub(l->data, l->width, l->height,
1489 image->data, image->width, image->height,
1490 l->offset_x, l->offset_y);
1491 break;
1492 case DARKEN_ONLY_MODE:
1493 D("DARKEN\n");
1494 combine_pixels_darken(l->data, l->width, l->height,
1495 image->data, image->width, image->height,
1496 l->offset_x, l->offset_y);
1497 break;
1498 case LIGHTEN_ONLY_MODE:
1499 D("LIGHTEN\n");
1500 combine_pixels_lighten(l->data, l->width, l->height,
1501 image->data, image->width, image->height,
1502 l->offset_x, l->offset_y);
1503 break;
1504 case HUE_MODE:
1505 D("HUE\n");
1506 combine_pixels_hue(l->data, l->width, l->height,
1507 image->data, image->width, image->height,
1508 l->offset_x, l->offset_y);
1509 break;
1510 case SATURATION_MODE:
1511 D("SATURATION\n");
1512 combine_pixels_sat(l->data, l->width, l->height,
1513 image->data, image->width, image->height,
1514 l->offset_x, l->offset_y);
1515 break;
1516 case VALUE_MODE:
1517 D("VALUE\n");
1518 combine_pixels_val(l->data, l->width, l->height,
1519 image->data, image->width, image->height,
1520 l->offset_x, l->offset_y);
1521 break;
1522 case COLOR_MODE:
1523 D("COLOR\n");
1524 combine_pixels_col(l->data, l->width, l->height,
1525 image->data, image->width, image->height,
1526 l->offset_x, l->offset_y);
1527 break;
1528 case DISSOLVE_MODE:
1529 D("DISSOLVE\n");
1530 combine_pixels_diss(l->data, l->width, l->height,
1531 image->data, image->width, image->height,
1532 l->offset_x, l->offset_y);
1533 break;
1534 /* None of the following is actually valid for layer blending, fall through: */
1535 case BEHIND_MODE:
1536 case REPLACE_MODE:
1537 case ERASE_MODE:
1538 case ANTI_ERASE_MODE:
1539 D("EEEEEK -- this mode shouldn't be here\n");
1540 /* Fall through */
1541
1542 case NORMAL_MODE:
1543 D("NORMAL\n");
1544 combine_pixels_normal(l->data, l->width, l->height,
1545 image->data, image->width, image->height,
1546 l->offset_x, l->offset_y);
1547 break;
1548
1549 default:
1550 D("Unknown layer mode: %i. Skipping.\n", l->mode);
1551 }
1552 }
1553
1554 lp = l->prev;
1555 /* free the layer now, since it's not needed anymore */
1556 free_layer(l);
1557
1558 l = lp;
1559 layer_index++;
1560 }
1561
1562 /* We've used up all the layers now, so set them to NULL in the image: */
1563 image->layers = NULL;
1564 image->last_layer = NULL;
1565}
1566
1567static char
1568xcf_file_init(char *filename)
1569{
1570 char success = 1;
1571 char id[14];
1572 int width;
1573 int height;
1574 int image_type;
1575
1576 image->single_layer_index = -1;
1577 image->file = f_open(filename);
1578 D("image->file = %p\n", image->file);
1579 if (!image->file) return 0;
1580
1581 image->filename = filename;
1582 image->layers = NULL;
1583 image->last_layer = NULL;
1584 image->cmap = NULL;
1585 image->num_cols = 0;
1586 image->data = NULL;
1587
1588 image->cp = 0;
1589
1590 image->cp += xcf_read_int8(image->file, (DATA8 *)id, 14);
1591 if (strncmp(id, "gimp xcf ", 9))
1592 {
1593 success = 0;
1594 f_close(image->file);
1595 }
1596 else if (!strcmp(id + 9, "file"))
1597 {
1598 image->file_version = 0;
1599 }
1600 else if (id[9] == 'v')
1601 {
1602 image->file_version = atoi(id + 10);
1603 }
1604 else
1605 {
1606 success = 0;
1607 f_close(image->file);
1608 }
1609
1610 if (success)
1611 {
1612 image->cp += xcf_read_int32(image->file, (DATA32 *)&width, 1);
1613 image->cp += xcf_read_int32(image->file, (DATA32 *)&height, 1);
1614 image->cp += xcf_read_int32(image->file, (DATA32 *)&image_type, 1);
1615
1616 image->width = width;
1617 image->height = height;
1618 image->base_type = image_type;
1619
1620 D("Loading %ix%i image.\n", width, height);
1621 }
1622
1623 return success;
1624}
1625
1626static void
1627xcf_cleanup(void)
1628{
1629 Layer *l, *lp;
1630
1631 if (image->file) f_close(image->file);
1632 for (l = image->last_layer; l; l = lp)
1633 {
1634 lp = l->prev;
1635 free_layer(l);
1636 }
1637 if (image->cmap) FREE(image->cmap);
1638}
1639
1640static void
1641premul_image(void)
1642{
1643 DATA32 *p, *end;
1644
1645 end = (DATA32 *)image->data + (image->width * image->height);
1646 for (p = (DATA32 *)image->data; p < end; p++)
1647 {
1648 unsigned int r, g, b, a;
1649
1650 a = A_VAL(p);
1651 r = (R_VAL(p) * a) / 255;
1652 R_VAL(p) = r;
1653 g = (G_VAL(p) * a) / 255;
1654 G_VAL(p) = g;
1655 b = (B_VAL(p) * a) / 255;
1656 B_VAL(p) = b;
1657 }
1658}
1659
1660int
1661main(int argc, char **argv)
1662{
1663 char *file;
1664 int w, h, i;
1665 int head_only = 0;
1666
1667 if (argc < 2) return -1;
1668 // file is ALWAYS first arg, other options come after
1669 file = argv[1];
1670 for (i = 2; i < argc; i++)
1671 {
1672 if (!strcmp(argv[i], "-head"))
1673 // asked to only load header, not body/data
1674 head_only = 1;
1675 else if (!strcmp(argv[i], "-key"))
1676 { // not used by xcf loader
1677 i++;
1678 // const char *key = argv[i];
1679 }
1680 else if (!strcmp(argv[i], "-opt-scale-down-by"))
1681 { // not used by xcf loader
1682 i++;
1683 // int scale_down = atoi(argv[i]);
1684 }
1685 else if (!strcmp(argv[i], "-opt-dpi"))
1686 { // not used by xcf loader
1687 i++;
1688 // double dpi = ((double)atoi(argv[i])) / 1000.0;
1689 }
1690 else if (!strcmp(argv[i], "-opt-size"))
1691 { // not used by xcf loader
1692 i++;
1693 // int size_w = atoi(argv[i]);
1694 i++;
1695 // int size_h = atoi(argv[i]);
1696 }
1697 }
1698
1699 timeout_init(8);
1700
1701 D("xcf_file_init\n");
1702 if (!xcf_file_init(file)) return -1;
1703
1704 D("size %i %i\n", image->width, image->height);
1705 if (!head_only)
1706 {
1707 xcf_load_image();
1708 premul_image();
1709 }
1710 w = image->width;
1711 h = image->height;
1712 printf("size %i %i\n", w, h);
1713 printf("alpha 1\n");
1714 if (!head_only)
1715 {
1716 if (shm_fd >= 0) printf("shmfile %s\n", shmfile);
1717 else
1718 {
1719 // could also to "tmpfile %s\n" like shmfile but just
1720 // a mmaped tmp file on the system
1721 printf("data\n");
1722 fwrite(image->data, w * h * sizeof(DATA32), 1, stdout);
1723 }
1724 shm_free();
1725 }
1726 else
1727 printf("done\n");
1728 xcf_cleanup();
1729 fflush(stdout);
1730 return 0;
1731}
diff --git a/src/generic/evas/xcf/pixelfuncs.c b/src/generic/evas/xcf/pixelfuncs.c
new file mode 100644
index 0000000..67d66d8
--- /dev/null
+++ b/src/generic/evas/xcf/pixelfuncs.c
@@ -0,0 +1,759 @@
1/*
2
3 -----------------------------[ XCF Loader ]-----------------------------
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2, or (at your option)
8 any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software Foundation,
17 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20
21#include "common.h"
22
23#define RS R_VAL(src + s_idx)
24#define GS G_VAL(src + s_idx)
25#define BS B_VAL(src + s_idx)
26#define AS A_VAL(src + s_idx)
27#define RD R_VAL(dest + d_idx)
28#define GD G_VAL(dest + d_idx)
29#define BD B_VAL(dest + d_idx)
30#define AD A_VAL(dest + d_idx)
31
32#define EPS 0.00001
33#define PI 3.141592654
34#define MAX(a, b) ((a) > (b) ? (a) : (b))
35#define MIN(a, b) ((a) < (b) ? (a) : (b))
36#define INT_MULT(a,b,t) ((t) = (a) * (b) + 0x80, ((((t) >> 8) + (t)) >> 8))
37#define LINEAR(x,y,w) ((w*y + x)*4)
38
39static void
40rgb_to_hls (DATA8 *red, DATA8 *green, DATA8 *blue)
41{
42 int r, g, b;
43 double h, l, s;
44 int min, max;
45 int delta;
46
47 r = *red;
48 g = *green;
49 b = *blue;
50
51 if (r > g)
52 {
53 max = MAX (r, b);
54 min = MIN (g, b);
55 }
56 else
57 {
58 max = MAX (g, b);
59 min = MIN (r, b);
60 }
61
62 l = (max + min) / 2.0;
63
64 if (max == min)
65 {
66 s = 0.0;
67 h = 0.0;
68 }
69 else
70 {
71 delta = (max - min);
72
73 if (l < 128)
74 s = 255 * (double) delta / (double) (max + min);
75 else
76 s = 255 * (double) delta / (double) (511 - max - min);
77
78 if (r == max)
79 h = (g - b) / (double) delta;
80 else if (g == max)
81 h = 2 + (b - r) / (double) delta;
82 else
83 h = 4 + (r - g) / (double) delta;
84
85 h = h * 42.5;
86
87 if (h < 0)
88 h += 255;
89 else if (h > 255)
90 h -= 255;
91 }
92
93 *red = h;
94 *green = l;
95 *blue = s;
96}
97
98
99static DATA8
100gimp_hls_value (double n1, double n2, double hue)
101{
102 double value;
103
104 if (hue > 255)
105 hue -= 255;
106 else if (hue < 0)
107 hue += 255;
108 if (hue < 42.5)
109 value = n1 + (n2 - n1) * (hue / 42.5);
110 else if (hue < 127.5)
111 value = n2;
112 else if (hue < 170)
113 value = n1 + (n2 - n1) * ((170 - hue) / 42.5);
114 else
115 value = n1;
116
117 return (DATA8) (value * 255);
118}
119
120
121static void
122hls_to_rgb (DATA8 *hue, DATA8 *lightness, DATA8 *saturation)
123{
124 double h, l, s;
125 double m1, m2;
126
127 h = *hue;
128 l = *lightness;
129 s = *saturation;
130
131 if (s == 0)
132 {
133 /* achromatic case */
134 *hue = l;
135 *lightness = l;
136 *saturation = l;
137 }
138 else
139 {
140 if (l < 128)
141 m2 = (l * (255 + s)) / 65025.0;
142 else
143 m2 = (l + s - (l * s) / 255.0) / 255.0;
144
145 m1 = (l / 127.5) - m2;
146
147 /* chromatic case */
148 *hue = gimp_hls_value (m1, m2, h + 85);
149 *lightness = gimp_hls_value (m1, m2, h);
150 *saturation = gimp_hls_value (m1, m2, h - 85);
151 }
152}
153
154
155static void
156rgb_to_hsv (DATA8 *red, DATA8 *green, DATA8 *blue)
157{
158 int r, g, b;
159 double h, s, v;
160 int min, max;
161 int delta;
162
163 h = 0.0;
164
165 r = *red;
166 g = *green;
167 b = *blue;
168
169 if (r > g)
170 {
171 max = MAX (r, b);
172 min = MIN (g, b);
173 }
174 else
175 {
176 max = MAX (g, b);
177 min = MIN (r, b);
178 }
179
180 v = max;
181
182 if (max != 0)
183 s = ((max - min) * 255) / (double) max;
184 else
185 s = 0;
186
187 if (s == 0)
188 h = 0;
189 else
190 {
191 delta = max - min;
192 if (r == max)
193 h = (g - b) / (double) delta;
194 else if (g == max)
195 h = 2 + (b - r) / (double) delta;
196 else if (b == max)
197 h = 4 + (r - g) / (double) delta;
198 h *= 42.5;
199
200 if (h < 0)
201 h += 255;
202 if (h > 255)
203 h -= 255;
204 }
205
206 *red = h;
207 *green = s;
208 *blue = v;
209}
210
211static void
212hsv_to_rgb (DATA8 *hue, DATA8 *saturation, DATA8 *value)
213{
214 double h, s, v;
215 double f, p, q, t;
216
217 if (*saturation == 0)
218 {
219 *hue = *value;
220 *saturation = *value;
221 /* *value = *value; */
222 }
223 else
224 {
225 h = *hue * 6.0 / 255.0;
226 s = *saturation / 255.0;
227 v = *value / 255.0;
228
229 f = h - (int) h;
230 p = v * (1.0 - s);
231 q = v * (1.0 - (s * f));
232 t = v * (1.0 - (s * (1.0 - f)));
233
234 switch ((int) h)
235 {
236 case 0:
237 *hue = v * 255;
238 *saturation = t * 255;
239 *value = p * 255;
240 break;
241
242 case 1:
243 *hue = q * 255;
244 *saturation = v * 255;
245 *value = p * 255;
246 break;
247
248 case 2:
249 *hue = p * 255;
250 *saturation = v * 255;
251 *value = t * 255;
252 break;
253
254 case 3:
255 *hue = p * 255;
256 *saturation = q * 255;
257 *value = v * 255;
258 break;
259
260 case 4:
261 *hue = t * 255;
262 *saturation = p * 255;
263 *value = v * 255;
264 break;
265
266 case 5:
267 *hue = v * 255;
268 *saturation = p * 255;
269 *value = q * 255;
270 break;
271 }
272 }
273}
274
275/* translate negative destinations */
276static
277void _clip(int * src_tl_x, int * src_tl_y,
278 int * src_br_x, int * src_br_y,
279 int * dest_x, int * dest_y,
280 int dest_w, int dest_h)
281{
282 if (*dest_x + *src_br_x >= dest_w)
283 { *src_br_x -= (*dest_x + *src_br_x) - dest_w; }
284
285 if (*dest_y + *src_br_y >= dest_h)
286 { *src_br_y -= (*dest_y + *src_br_y) - dest_h; }
287
288 if (*dest_x < 0)
289 {
290 *src_tl_x = -(*dest_x);
291 *dest_x = 0;
292 }
293 if (*dest_y < 0)
294 {
295 *src_tl_y = -(*dest_y);
296 *dest_y = 0;
297 }
298}
299
300// FIXME: make sure layer alpha is used/applied in all cases
301void
302combine_pixels_normal (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y)
303{
304 int x, y, s_idx, d_idx;
305 int src_tl_x = 0, src_tl_y = 0;
306 int src_br_x = src_w, src_br_y = src_h;
307
308 int b;
309 unsigned char src_alpha;
310 unsigned char new_alpha;
311 float ratio, compl_ratio;
312 unsigned long tmp;
313
314 _clip(&src_tl_x, &src_tl_y, &src_br_x, &src_br_y, &dest_x, &dest_y, dest_w, dest_h);
315
316 for (y = src_tl_y; y < src_br_y; y++)
317 for (x = src_tl_x; x < src_br_x; x++)
318 {
319 d_idx = LINEAR((dest_x + x - src_tl_x), (dest_y + y - src_tl_y), dest_w);
320 s_idx = LINEAR(x, y, src_w);
321
322 src_alpha = AS;
323
324 if (src_alpha != 0)
325 {
326 if (src_alpha == 255)
327 new_alpha = src_alpha;
328 else
329 new_alpha = AD + INT_MULT((255u - AD), src_alpha, tmp);
330
331 b = 3;
332 if (new_alpha != 0)
333 {
334 ratio = (float) src_alpha / new_alpha;
335 compl_ratio = 1.0 - ratio;
336
337 do
338 {
339 b--;
340 dest[d_idx + b] =
341 (unsigned char) (src[s_idx + b] * ratio + dest[d_idx + b] * compl_ratio + EPS);
342 }
343 while (b);
344 }
345
346 AD = new_alpha;
347 }
348 }
349}
350
351
352void
353combine_pixels_add (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y)
354{
355 int x, y, s_idx, d_idx;
356 int src_tl_x = 0, src_tl_y = 0;
357 int src_br_x = src_w, src_br_y = src_h;
358 int tmp, tmp2;
359
360 _clip(&src_tl_x, &src_tl_y, &src_br_x, &src_br_y, &dest_x, &dest_y, dest_w, dest_h);
361
362 for (y = src_tl_y; y < src_br_y; y++)
363 for (x = src_tl_x; x < src_br_x; x++)
364 {
365 d_idx = LINEAR((dest_x + x - src_tl_x), (dest_y + y - src_tl_y), dest_w);
366 s_idx = LINEAR(x, y, src_w);
367
368 tmp2 = INT_MULT(AS, RS, tmp);
369 tmp = RD + tmp2;
370 RD = (tmp > 255 ? 255 : tmp);
371
372 tmp2 = INT_MULT(AS, GS, tmp);
373 tmp = GD + tmp2;
374 GD = (tmp > 255 ? 255 : tmp);
375
376 tmp2 = INT_MULT(AS, BS, tmp);
377 tmp = BD + tmp2;
378 BD = (tmp > 255 ? 255 : tmp);
379
380// AD = MIN(AD, AS);
381 }
382}
383
384
385void
386combine_pixels_sub (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y)
387{
388 int x, y, s_idx, d_idx;
389 int src_tl_x = 0, src_tl_y = 0;
390 int src_br_x = src_w, src_br_y = src_h;
391 int tmp, tmp2;
392
393 _clip(&src_tl_x, &src_tl_y, &src_br_x, &src_br_y, &dest_x, &dest_y, dest_w, dest_h);
394
395 for (y = src_tl_y; y < src_br_y; y++)
396 for (x = src_tl_x; x < src_br_x; x++)
397 {
398 d_idx = LINEAR((dest_x + x - src_tl_x), (dest_y + y - src_tl_y), dest_w);
399 s_idx = LINEAR(x, y, src_w);
400
401 tmp2 = INT_MULT(AS, RS, tmp);
402 tmp = RD - tmp2;
403 RD = (tmp < 0 ? 0 : tmp);
404
405 tmp2 = INT_MULT(AS, GS, tmp);
406 tmp = GD - tmp2;
407 GD = (tmp < 0 ? 0 : tmp);
408
409 tmp2 = INT_MULT(AS, BS, tmp);
410 tmp = BD - tmp2;
411 BD = (tmp < 0 ? 0 : tmp);
412
413// AD = MIN(AD, AS);
414 }
415}
416
417
418void
419combine_pixels_diff (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y)
420{
421 int x, y, s_idx, d_idx;
422 int src_tl_x = 0, src_tl_y = 0;
423 int src_br_x = src_w, src_br_y = src_h;
424 int tmp, tmp2;
425
426 _clip(&src_tl_x, &src_tl_y, &src_br_x, &src_br_y, &dest_x, &dest_y, dest_w, dest_h);
427
428 for (y = src_tl_y; y < src_br_y; y++)
429 for (x = src_tl_x; x < src_br_x; x++)
430 {
431 d_idx = LINEAR((dest_x + x - src_tl_x), (dest_y + y - src_tl_y), dest_w);
432 s_idx = LINEAR(x, y, src_w);
433
434 tmp2 = INT_MULT(AS, RS, tmp);
435 tmp = RD - tmp2;
436 RD = (tmp < 0 ? -tmp : tmp);
437
438 tmp2 = INT_MULT(AS, GS, tmp);
439 tmp = GD - tmp2;
440 GD = (tmp < 0 ? -tmp : tmp);
441
442 tmp2 = INT_MULT(AS, BS, tmp);
443 tmp = BD - tmp2;
444 BD = (tmp < 0 ? -tmp : tmp);
445
446// AD = MIN(AD, AS);
447 }
448}
449
450
451void
452combine_pixels_darken (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y)
453{
454 int x, y, s_idx, d_idx;
455 int src_tl_x = 0, src_tl_y = 0;
456 int src_br_x = src_w, src_br_y = src_h;
457
458 _clip(&src_tl_x, &src_tl_y, &src_br_x, &src_br_y, &dest_x, &dest_y, dest_w, dest_h);
459
460 for (y = src_tl_y; y < src_br_y; y++)
461 for (x = src_tl_x; x < src_br_x; x++)
462 {
463 d_idx = LINEAR((dest_x + x - src_tl_x), (dest_y + y - src_tl_y), dest_w);
464 s_idx = LINEAR(x, y, src_w);
465
466 RD = MIN(RD, RS);
467 GD = MIN(GD, GS);
468 BD = MIN(BD, BS);
469
470// AD = MIN(AD, AS);
471 }
472}
473
474
475void
476combine_pixels_lighten (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y)
477{
478 int x, y, s_idx, d_idx;
479 int src_tl_x = 0, src_tl_y = 0;
480 int src_br_x = src_w, src_br_y = src_h;
481
482 _clip(&src_tl_x, &src_tl_y, &src_br_x, &src_br_y, &dest_x, &dest_y, dest_w, dest_h);
483
484 for (y = src_tl_y; y < src_br_y; y++)
485 for (x = src_tl_x; x < src_br_x; x++)
486 {
487 d_idx = LINEAR((dest_x + x - src_tl_x), (dest_y + y - src_tl_y), dest_w);
488 s_idx = LINEAR(x, y, src_w);
489
490 RD = MAX(RD, RS);
491 GD = MAX(GD, GS);
492 BD = MAX(BD, BS);
493
494// AD = MIN(AD, AS);
495 }
496}
497
498
499void
500combine_pixels_mult (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y)
501{
502 int x, y, s_idx, d_idx;
503 int src_tl_x = 0, src_tl_y = 0;
504 int src_br_x = src_w, src_br_y = src_h;
505 int tmp, tmp2, tmp3;
506
507 _clip(&src_tl_x, &src_tl_y, &src_br_x, &src_br_y, &dest_x, &dest_y, dest_w, dest_h);
508
509 for (y = src_tl_y; y < src_br_y; y++)
510 for (x = src_tl_x; x < src_br_x; x++)
511 {
512 d_idx = LINEAR((dest_x + x - src_tl_x), (dest_y + y - src_tl_y), dest_w);
513 s_idx = LINEAR(x, y, src_w);
514
515 tmp2 = INT_MULT(RS, AS, tmp);
516 tmp2 = INT_MULT(RD, tmp2, tmp);
517 tmp3 = INT_MULT(RD, (255 - AS), tmp);
518 RD = (tmp2 + tmp3);
519
520 tmp2 = INT_MULT(GS, AS, tmp);
521 tmp2 = INT_MULT(GD, tmp2, tmp);
522 tmp3 = INT_MULT(GD, (255 - AS), tmp);
523 GD = (tmp2 + tmp3);
524
525 tmp2 = INT_MULT(BS, AS, tmp);
526 tmp2 = INT_MULT(BD, tmp2, tmp);
527 tmp3 = INT_MULT(BD, (255 - AS), tmp);
528 BD = (tmp2 + tmp3);
529
530// AS = MIN(AS, AD);
531 }
532
533// combine_pixels_normal(src, src_w, src_h, dest, dest_w, dest_h, dest_x, dest_y);
534}
535
536
537void
538combine_pixels_div (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y)
539{
540 int x, y, s_idx, d_idx;
541 int src_tl_x = 0, src_tl_y = 0;
542 int src_br_x = src_w, src_br_y = src_h;
543
544 _clip(&src_tl_x, &src_tl_y, &src_br_x, &src_br_y, &dest_x, &dest_y, dest_w, dest_h);
545
546 for (y = src_tl_y; y < src_br_y; y++)
547 for (x = src_tl_x; x < src_br_x; x++)
548 {
549 d_idx = LINEAR((dest_x + x - src_tl_x), (dest_y + y - src_tl_y), dest_w);
550 s_idx = LINEAR(x, y, src_w);
551
552 RS = MIN(255, ((float)RD / (RS + 1)) * 256);
553 GS = MIN(255, ((float)GD / (GS + 1)) * 256);
554 BS = MIN(255, ((float)BD / (BS + 1)) * 256);
555
556// AS = MIN(AD, AS);
557 }
558
559 combine_pixels_normal(src, src_w, src_h, dest, dest_w, dest_h, dest_x, dest_y);
560}
561
562
563void
564combine_pixels_screen (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y)
565{
566 int x, y, s_idx, d_idx;
567 int src_tl_x = 0, src_tl_y = 0;
568 int src_br_x = src_w, src_br_y = src_h;
569
570 _clip(&src_tl_x, &src_tl_y, &src_br_x, &src_br_y, &dest_x, &dest_y, dest_w, dest_h);
571
572 for (y = src_tl_y; y < src_br_y; y++)
573 for (x = src_tl_x; x < src_br_x; x++)
574 {
575 d_idx = LINEAR((dest_x + x - src_tl_x), (dest_y + y - src_tl_y), dest_w);
576 s_idx = LINEAR(x, y, src_w);
577
578 RD = 255 - (((255 - RD) * (255 - RS)) >> 8);
579 GD = 255 - (((255 - GD) * (255 - GS)) >> 8);
580 BD = 255 - (((255 - BD) * (255 - BS)) >> 8);
581
582// AD = MIN(AD, AS);
583 }
584}
585
586
587void
588combine_pixels_overlay (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y)
589{
590 int x, y, s_idx, d_idx;
591 int src_tl_x = 0, src_tl_y = 0;
592 int src_br_x = src_w, src_br_y = src_h;
593 int tmp_screen, tmp_mult;
594
595 _clip(&src_tl_x, &src_tl_y, &src_br_x, &src_br_y, &dest_x, &dest_y, dest_w, dest_h);
596
597 for (y = src_tl_y; y < src_br_y; y++)
598 for (x = src_tl_x; x < src_br_x; x++)
599 {
600 d_idx = LINEAR((dest_x + x - src_tl_x), (dest_y + y - src_tl_y), dest_w);
601 s_idx = LINEAR(x, y, src_w);
602
603 tmp_screen = 255 - (((255 - RD) * (255 - RS)) >> 8);
604 tmp_mult = (RD * RS) >> 8;
605 RD = (RD * tmp_screen + (255 - RD) * tmp_mult) >> 8;
606
607 tmp_screen = 255 - (((255 - GD) * (255 - GS)) >> 8);
608 tmp_mult = (GD * GS) >> 8;
609 GD = (GD * tmp_screen + (255 - GD) * tmp_mult) >> 8;
610
611 tmp_screen = 255 - (((255 - BD) * (255 - BS)) >> 8);
612 tmp_mult = (BD * BS) >> 8;
613 BD = (BD * tmp_screen + (255 - BD) * tmp_mult) >> 8;
614
615// AD = MIN(AD, AS);
616 }
617}
618
619
620static void
621combine_pixels_hsv (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y, int mode)
622{
623 int x, y, s_idx, d_idx;
624 int src_tl_x = 0, src_tl_y = 0;
625 int src_br_x = src_w, src_br_y = src_h;
626
627 _clip(&src_tl_x, &src_tl_y, &src_br_x, &src_br_y, &dest_x, &dest_y, dest_w, dest_h);
628
629 for (y = src_tl_y; y < src_br_y; y++)
630 for (x = src_tl_x; x < src_br_x; x++)
631 {
632 d_idx = LINEAR((dest_x + x - src_tl_x), (dest_y + y - src_tl_y), dest_w);
633 s_idx = LINEAR(x, y, src_w);
634
635 rgb_to_hsv(&RS, &GS, &BS);
636 rgb_to_hsv(&RD, &GD, &BD);
637
638 switch (mode)
639 {
640 case 0: /* hue mode */
641 RD = RS;
642 break;
643 case 1: /* saturation mode */
644 GD = GS;
645 break;
646 case 2: /* value mode */
647 BD = BS;
648 break;
649 default:
650 break;
651 }
652
653 hsv_to_rgb(&RD, &GD, &BD);
654// AD = MIN(AD, AS);
655 }
656}
657
658
659void
660combine_pixels_hue (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y)
661{
662 combine_pixels_hsv(src, src_w, src_h, dest, dest_w, dest_h, dest_x, dest_y, 0);
663}
664
665
666void
667combine_pixels_sat (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y)
668{
669 combine_pixels_hsv(src, src_w, src_h, dest, dest_w, dest_h, dest_x, dest_y, 1);
670}
671
672
673void
674combine_pixels_val (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y)
675{
676 combine_pixels_hsv(src, src_w, src_h, dest, dest_w, dest_h, dest_x, dest_y, 2);
677}
678
679
680void
681combine_pixels_col (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y)
682{
683 int x, y, s_idx, d_idx;
684 int src_tl_x = 0, src_tl_y = 0;
685 int src_br_x = src_w, src_br_y = src_h;
686
687 _clip(&src_tl_x, &src_tl_y, &src_br_x, &src_br_y, &dest_x, &dest_y, dest_w, dest_h);
688
689 for (y = src_tl_y; y < src_br_y; y++)
690 for (x = src_tl_x; x < src_br_x; x++)
691 {
692 d_idx = LINEAR((dest_x + x - src_tl_x), (dest_y + y - src_tl_y), dest_w);
693 s_idx = LINEAR(x, y, src_w);
694
695 rgb_to_hls(&RS, &GS, &BS);
696 rgb_to_hls(&RD, &GD, &BD);
697 RD = RS;
698 BD = BS;
699 hls_to_rgb(&RD, &GD, &BD);
700
701// AD = MIN(AD, AS);
702 }
703}
704
705
706void
707combine_pixels_diss (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y)
708{
709 int x, y, s_idx, d_idx;
710 int src_tl_x = 0, src_tl_y = 0;
711 int src_br_x = src_w, src_br_y = src_h;
712
713 srand(12345);
714
715 _clip(&src_tl_x, &src_tl_y, &src_br_x, &src_br_y, &dest_x, &dest_y, dest_w, dest_h);
716
717 for (y = src_tl_y; y < src_br_y; y++)
718 for (x = src_tl_x; x < src_br_x; x++)
719 {
720 d_idx = LINEAR((dest_x + x - src_tl_x), (dest_y + y - src_tl_y), dest_w);
721 s_idx = LINEAR(x, y, src_w);
722
723 if ((rand() % 255) < AS)
724 {
725 int b;
726 unsigned char src_alpha;
727 unsigned char new_alpha;
728 float ratio, compl_ratio;
729 unsigned long tmp;
730
731 src_alpha = AS;
732
733 if (src_alpha != 0)
734 {
735 if (src_alpha == 255)
736 new_alpha = src_alpha;
737 else
738 new_alpha = AD + INT_MULT((255u - AD), src_alpha, tmp);
739
740 b = 3;
741 if (new_alpha != 0)
742 {
743 ratio = (float) src_alpha / new_alpha;
744 compl_ratio = 1.0 - ratio;
745
746 do
747 {
748 b--;
749 dest[d_idx + b] =
750 (unsigned char) (src[s_idx + b] * ratio + dest[d_idx + b] * compl_ratio + EPS);
751 }
752 while (b);
753 }
754
755 AD = new_alpha;
756 }
757 }
758 }
759}