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)
downloadefl-6b5ed1b7118cd99b99a8d133b3e466952885f945.tar.gz
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 0000000000..f901c12b6d
--- /dev/null
+++ b/src/generic/.gitignore
@@ -0,0 +1,5 @@
+/emotion/vlc/vlc
+/evas/pdf/evas_image_loader.pdf
+/evas/ps/evas_image_loader.ps
+/evas/raw/evas_image_loader.raw
+/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 0000000000..538a3149a7
--- /dev/null
+++ b/src/generic/evas/common/shmfile.c
@@ -0,0 +1,87 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <math.h>
+#include <netinet/in.h>
+#include <time.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <zlib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int shm_fd = -1;
+static int shm_size = 0;
+void *shm_addr = NULL;
+char *shmfile = NULL;
+
+void
+shm_alloc(unsigned long dsize)
+{
+#ifdef HAVE_SHM_OPEN
+ if (!shmfile) shmfile = malloc(1024);
+ if (!shmfile) goto failed;
+ shmfile[0] = 0;
+ srand(time(NULL));
+ do
+ {
+ snprintf(shmfile, 1024, "/evas-loader.%i.%i",
+ (int)getpid(), (int)rand());
+ shm_fd = shm_open(shmfile, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
+ }
+ while (shm_fd < 0);
+
+ if (ftruncate(shm_fd, dsize) < 0)
+ {
+ close(shm_fd);
+ shm_unlink(shmfile);
+ shm_fd = -1;
+ goto failed;
+ }
+ shm_addr = mmap(NULL, dsize, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
+ if (shm_addr == MAP_FAILED)
+ {
+ close(shm_fd);
+ shm_unlink(shmfile);
+ shm_fd = -1;
+ goto failed;
+ }
+ shm_size = dsize;
+ return;
+failed:
+#endif
+ shm_addr = malloc(dsize);
+}
+
+void
+shm_free(void)
+{
+#ifdef HAVE_SHM_OPEN
+ if (shm_fd >= 0)
+ {
+ munmap(shm_addr, shm_size);
+ close(shm_fd);
+ shm_fd = -1;
+ shm_addr = NULL;
+ if (shmfile) free(shmfile);
+ shmfile = NULL;
+ return;
+ }
+#endif
+ free(shm_addr);
+ shm_addr = NULL;
+ shm_fd = -1;
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/generic/evas/common/shmfile.h b/src/generic/evas/common/shmfile.h
new file mode 100644
index 0000000000..f70a8fd157
--- /dev/null
+++ b/src/generic/evas/common/shmfile.h
@@ -0,0 +1,20 @@
+#ifndef SHMFILE_H
+#define SHMFILE_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int shm_fd;
+extern int shm_size;
+extern void *shm_addr;
+extern char *shmfile;
+
+void shm_alloc (unsigned long dsize);
+void shm_free (void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/generic/evas/common/timeout.c b/src/generic/evas/common/timeout.c
new file mode 100644
index 0000000000..6d52aa9609
--- /dev/null
+++ b/src/generic/evas/common/timeout.c
@@ -0,0 +1,16 @@
+#include <unistd.h>
+#include <signal.h>
+
+static void
+_timeout(int val)
+{
+ _exit(-1);
+ if (val) return;
+}
+
+void
+timeout_init(int seconds)
+{
+ signal(SIGALRM, _timeout);
+ alarm(seconds);
+}
diff --git a/src/generic/evas/common/timeout.h b/src/generic/evas/common/timeout.h
new file mode 100644
index 0000000000..8725627e06
--- /dev/null
+++ b/src/generic/evas/common/timeout.h
@@ -0,0 +1,14 @@
+#ifndef TIMEOUT_H
+#define TIMEOUT_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void timeout_init(int seconds);
+
+#ifdef __cplusplus
+}
+#endif
+
+#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 0000000000..b36e11e322
--- /dev/null
+++ b/src/generic/evas/pdf/evas_generic_pdf_loader.libreoffice
@@ -0,0 +1,8 @@
+#!/bin/sh
+LOBIN=soffice
+if [ -x /usr/lib/libreoffice/program/soffice.bin ]; then
+ LOBIN=/usr/lib/libreoffice/program/soffice.bin
+elif [ -x /usr/lib64/libreoffice/program/soffice.bin ]; then
+ LOBIN=/usr/lib64/libreoffice/program/soffice.bin
+fi
+$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 0000000000..6b1de13ce0
--- /dev/null
+++ b/src/generic/evas/pdf/main.cpp
@@ -0,0 +1,353 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <libgen.h>
+
+#include <GlobalParams.h>
+#include <PDFDoc.h>
+#include <ErrorCodes.h>
+#include <Page.h>
+#include <SplashOutputDev.h>
+#include <splash/SplashBitmap.h>
+
+#include <Eina.h>
+
+#include "shmfile.h"
+#include "timeout.h"
+
+#define DATA32 unsigned int
+
+//#define PDF_DBG
+
+#ifdef PDF_DBG
+#define D(fmt, args...) fprintf(stderr, fmt, ## args)
+#else
+#define D(fmt, args...)
+#endif
+
+
+PDFDoc *pdfdoc;
+bool locked = false;
+
+::Page *page;
+int width = 0, height = 0;
+int crop_width = 0, crop_height = 0;
+void *data = NULL;
+double dpi = -1.0;
+
+#define DEF_DPI 72.0
+
+Eina_Bool poppler_init(const char *file, int page_nbr, int size_w, int size_h)
+{
+ Object obj;
+ double w, h, cw, ch;
+ int rot;
+
+ if (!file || !*file)
+ return EINA_FALSE;
+
+ if (page_nbr < 0)
+ return EINA_FALSE;
+
+ if (!(globalParams = new GlobalParams()))
+ return EINA_FALSE;
+
+ if (!eina_init())
+ goto del_global_param;
+
+#ifndef HAVE_POPPLER_031
+ if (globalParams->getAntialias())
+ globalParams->setAntialias((char *)"yes");
+ if (globalParams->getVectorAntialias())
+ globalParams->setVectorAntialias((char *)"yes");
+#endif
+
+ pdfdoc = new PDFDoc(new GooString(file), NULL);
+ if (!pdfdoc)
+ goto del_global_param;
+
+ if (!pdfdoc->isOk() || (pdfdoc->getErrorCode() == errEncrypted))
+ goto del_pdfdoc;
+
+ if (page_nbr >= pdfdoc->getNumPages())
+ goto del_pdfdoc;
+
+ /* load the page */
+
+ page = pdfdoc->getCatalog()->getPage(page_nbr + 1);
+ if (!page || !page->isOk())
+ goto del_pdfdoc;
+
+ w = page->getMediaWidth();
+ h = page->getMediaHeight();
+ cw = page->getCropWidth();
+ ch = page->getCropHeight();
+ rot = page->getRotate();
+ if (cw > w) cw = w;
+ if (ch > h) ch = h;
+ if ((rot == 90) || (rot == 270))
+ {
+ double t;
+ // swap width & height
+ t = w; w = h; h = t;
+ // swap crop width & height
+ t = cw; cw = ch; ch = t;
+ }
+
+ if ((size_w > 0) || (size_h > 0))
+ {
+ double w2 = cw, h2 = ch;
+
+ w2 = size_w;
+ h2 = (size_w * ch) / cw;
+ if (h2 > size_h)
+ {
+ h2 = size_h;
+ w2 = (size_h * cw) / ch;
+ }
+ D("XXXXXXXXXXXXXXXXXXXXx %3.3fx%3.3f\n", w2, h2);
+ if (w2 > h2) dpi = (w2 * DEF_DPI) / cw;
+ else dpi = (h2 * DEF_DPI) / ch;
+ }
+
+ if (dpi > 0.0)
+ {
+ cw = (cw * dpi) / DEF_DPI;
+ ch = (ch * dpi) / DEF_DPI;
+ w = (w * dpi) / DEF_DPI;
+ h = (h * dpi) / DEF_DPI;
+ }
+ width = w;
+ height = h;
+ crop_width = cw;
+ crop_height = ch;
+
+ return EINA_TRUE;
+
+ del_pdfdoc:
+ delete pdfdoc;
+ del_global_param:
+ delete globalParams;
+
+ return EINA_FALSE;
+}
+
+void poppler_shutdown()
+{
+ delete pdfdoc;
+ eina_shutdown();
+ delete globalParams;
+}
+
+void poppler_load_image(int size_w EINA_UNUSED, int size_h EINA_UNUSED)
+{
+ SplashOutputDev *output_dev;
+ SplashColor white;
+ SplashColorPtr color_ptr;
+ DATA32 *src, *dst;
+ int y;
+
+ white[0] = 255;
+ white[1] = 255;
+ white[2] = 255;
+ white[3] = 255;
+
+ output_dev = new SplashOutputDev(splashModeXBGR8, 4, gFalse, white);
+ if (!output_dev)
+ return;
+
+#if defined(HAVE_POPPLER_020) || defined(HAVE_POPPLER_031)
+ output_dev->startDoc(pdfdoc);
+#else
+ output_dev->startDoc(pdfdoc->getXRef());
+#endif
+
+ if (dpi <= 0.0) dpi = DEF_DPI;
+
+#ifdef HAVE_POPPLER_031
+ output_dev->setFontAntialias(EINA_TRUE);
+ output_dev->setVectorAntialias(EINA_TRUE);
+#endif
+
+#if defined(HAVE_POPPLER_020) || defined(HAVE_POPPLER_031)
+ page->displaySlice(output_dev, dpi, dpi,
+ 0, false, false,
+ 0, 0, width, height,
+ false, NULL, NULL);
+#else
+ page->displaySlice(output_dev, dpi, dpi,
+ 0, false, false,
+ 0, 0, width, height,
+ false, pdfdoc->getCatalog());
+#endif
+ color_ptr = output_dev->getBitmap()->getDataPtr();
+
+ shm_alloc(crop_width * crop_height * sizeof(DATA32));
+ if (!shm_addr) goto del_outpput_dev;
+ data = shm_addr;
+ src = (DATA32 *)color_ptr;
+ dst = (DATA32 *)data;
+ for (y = 0; y < crop_height; y++)
+ {
+ memcpy(dst, src, crop_width * sizeof(DATA32));
+ src += width;
+ dst += crop_width;
+ }
+
+ del_outpput_dev:
+ delete output_dev;
+}
+
+int
+main(int argc, char **argv)
+{
+ Eina_Tmpstr *tmpdir = NULL;
+ Eina_Tmpstr *generated = NULL;
+ char *extension;
+ char *dir;
+ char *file;
+ int i;
+ int size_w = 0, size_h = 0;
+ int head_only = 0;
+ int page_num = 0;
+
+ if (argc < 2) return -1;
+ // file is ALWAYS first arg, other options come after
+ file = argv[1];
+ for (i = 2; i < argc; i++)
+ {
+ if (!strcmp(argv[i], "-head"))
+ // asked to only load header, not body/data
+ head_only = 1;
+ else if (!strcmp(argv[i], "-key"))
+ {
+ i++;
+ page_num = atoi(argv[i]);
+ i++;
+ }
+ else if (!strcmp(argv[i], "-opt-scale-down-by"))
+ { // not used by pdf loader
+ i++;
+ // int scale_down = atoi(argv[i]);
+ }
+ else if (!strcmp(argv[i], "-opt-dpi"))
+ {
+ i++;
+ dpi = ((double)atoi(argv[i])) / 1000.0; // dpi is an int multiplied by 1000 (so 72dpi is 72000)
+ i++;
+ }
+ else if (!strcmp(argv[i], "-opt-size"))
+ { // not used by pdf loader
+ i++;
+ size_w = atoi(argv[i]);
+ i++;
+ size_h = atoi(argv[i]);
+ }
+ }
+
+ D("dpi....: %f\n", dpi);
+ D("page...: %d\n", page_num);
+
+ // This is a funny hack to call an external tool to generate a pdf that will then be processed by poppler
+ extension = strrchr(file, '.');
+ dir = dirname(argv[0]);
+ if (extension && dir && strcmp(extension, ".pdf"))
+ {
+ if (eina_file_mkdtemp("evas_generic_pdf_loaderXXXXXX", &tmpdir))
+ {
+ Eina_Strbuf *tmp;
+ FILE *cmd;
+
+ tmp = eina_strbuf_new();
+ eina_strbuf_append_printf(tmp, "%s/evas_generic_pdf_loader.%s '%s' %s", dir, extension + 1, file, tmpdir);
+
+ cmd = popen(eina_strbuf_string_get(tmp), "r");
+ D("running preprocessing process '%s'...\n", eina_strbuf_string_get(tmp));
+ eina_strbuf_reset(tmp);
+
+ if (cmd)
+ {
+ struct stat st;
+ const char *filename;
+ char buf[1024];
+
+ while (fgets(buf, sizeof (buf), cmd))
+ ;
+ pclose(cmd);
+
+ filename = basename(file);
+ generated = eina_tmpstr_add_length(filename, strlen(filename) - strlen(extension));
+
+ eina_strbuf_append_printf(tmp, "%s/%s.pdf", tmpdir, generated);
+
+ eina_tmpstr_del(generated);
+ generated = NULL;
+
+ if (stat(eina_strbuf_string_get(tmp), &st) == 0)
+ {
+ generated = eina_tmpstr_add_length(eina_strbuf_string_get(tmp),
+ eina_strbuf_length_get(tmp));
+ file = (char*) generated;
+ }
+ }
+
+ D("generated file: '%s'\n", generated);
+ eina_strbuf_free(tmp);
+ }
+ }
+
+ // Let's force a timeout if things go wrong
+ timeout_init(10);
+
+ // Now process the pdf (or the generated pdf)
+ D("poppler_file_init\n");
+ if (!poppler_init(file, page_num, size_w, size_h))
+ return -1;
+ D("poppler_file_init done\n");
+
+ D("dpi2...: %f\n", dpi);
+ if (!head_only)
+ {
+ poppler_load_image(size_w, size_h);
+ }
+
+ D("size...: %ix%i\n", width, height);
+ D("crop...: %ix%i\n", crop_width, crop_height);
+ D("alpha..: 1\n");
+
+ printf("size %i %i\n", crop_width, crop_height);
+ printf("alpha 0\n");
+
+ if (!head_only)
+ {
+ if (shm_fd >= 0) printf("shmfile %s\n", shmfile);
+ else
+ {
+ // could also to "tmpfile %s\n" like shmfile but just
+ // a mmaped tmp file on the system
+ printf("data\n");
+ fwrite(data, crop_width * crop_height * sizeof(DATA32), 1, stdout);
+ }
+ shm_free();
+ }
+ else
+ printf("done\n");
+
+ poppler_shutdown();
+
+ if (tmpdir)
+ {
+ if (generated) unlink(generated);
+ rmdir(tmpdir);
+
+ eina_tmpstr_del(tmpdir);
+ eina_tmpstr_del(generated);
+ }
+ fflush(stdout);
+ return 0;
+}
diff --git a/src/generic/evas/ps/main.c b/src/generic/evas/ps/main.c
new file mode 100644
index 0000000000..48e8a4b6f6
--- /dev/null
+++ b/src/generic/evas/ps/main.c
@@ -0,0 +1,289 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <sys/mman.h>
+#include <fcntl.h>
+
+#include <libspectre/spectre.h>
+
+#include <Eina.h>
+
+#include "shmfile.h"
+#include "timeout.h"
+
+#define DATA32 unsigned int
+
+#define PS_DBG
+
+#ifdef PS_DBG
+#define D(fmt, args...) fprintf(stderr, fmt, ## args)
+#else
+#define D(fmt, args...)
+#endif
+
+
+static SpectreDocument *psdoc;
+static int page_count;
+
+static SpectrePage *page;
+
+static int width = 0;
+static int height = 0;
+static void *data = NULL;
+static double dpi = -1.0;
+
+#define DEF_DPI 72.0
+
+static Eina_Bool
+_spectre_init(const char *file, int page_nbr, int size_w, int size_h)
+{
+ double w, h;
+ int ww, hh;
+ SpectreOrientation rot;
+ SpectreStatus status;
+
+ if (!file || !*file)
+ return EINA_FALSE;
+
+ if (page_nbr < 0)
+ return EINA_FALSE;
+
+ if (!eina_init())
+ return EINA_FALSE;
+
+ psdoc = spectre_document_new();
+ if (!psdoc)
+ goto shutdown_eina;
+
+ spectre_document_load(psdoc, file);
+ status = spectre_document_status (psdoc);
+ if (status != SPECTRE_STATUS_SUCCESS)
+ {
+ D("[ps] %s\n", spectre_status_to_string(status));
+ goto free_psdoc;
+ }
+
+ page_count = spectre_document_get_n_pages(psdoc);
+ status = spectre_document_status(psdoc);
+ if (status != SPECTRE_STATUS_SUCCESS)
+ {
+ D("[eps] %s\n", spectre_status_to_string (status));
+ goto free_psdoc;
+ }
+
+ if (page_nbr >= page_count)
+ goto free_psdoc;
+
+ /* load the page */
+
+ page = spectre_document_get_page(psdoc, page_nbr);
+ status = spectre_document_status(psdoc);
+ if (status != SPECTRE_STATUS_SUCCESS)
+ {
+ D("[eps] %s\n", spectre_status_to_string (status));
+ goto free_page;
+ }
+
+ spectre_page_get_size(page, &ww, &hh);
+ w = ww;
+ h = hh;
+ rot = spectre_page_get_orientation(page);
+
+ if ((rot == SPECTRE_ORIENTATION_LANDSCAPE) || (rot == SPECTRE_ORIENTATION_REVERSE_LANDSCAPE))
+ {
+ double t;
+ // swap width & height
+ t = w; w = h; h = t;
+ }
+
+ if ((size_w > 0) || (size_h > 0))
+ {
+ double w2 = w, h2 = h;
+
+ w2 = size_w;
+ h2 = (size_w * h) / w;
+ if (h2 > size_h)
+ {
+ h2 = size_h;
+ w2 = (size_h * w) / h;
+ }
+ D("XXXXXXXXXXXXXXXXXXXXx %3.3fx%3.3f\n", w2, h2);
+ if (w2 > h2) dpi = (w2 * DEF_DPI) / w;
+ else dpi = (h2 * DEF_DPI) / h;
+ }
+
+ if (dpi > 0.0)
+ {
+ w = (w * dpi) / DEF_DPI;
+ h = (h * dpi) / DEF_DPI;
+ }
+ width = w;
+ height = h;
+
+ return EINA_TRUE;
+
+ free_page:
+ spectre_page_free(page);
+ free_psdoc:
+ spectre_document_free(psdoc);
+ shutdown_eina:
+ eina_shutdown();
+
+ return EINA_FALSE;
+}
+
+static void
+_spectre_shutdown()
+{
+ spectre_page_free(page);
+ spectre_document_free(psdoc);
+ eina_shutdown();
+}
+
+static void
+_pixcopy(DATA32 *dst, unsigned char *src, int size)
+{
+ DATA32 *d;
+ unsigned char *s, *e;
+
+ d = dst;
+ s = src;
+ e = s + size;
+ while (s < e)
+ {
+ d[0] =
+ 0xff000000 |
+ (s[2] << 16) |
+ (s[1] << 8 ) |
+ (s[0] );
+ d++;
+ s += 4;
+ }
+}
+
+static void
+_spectre_load_image(int size_w EINA_UNUSED, int size_h EINA_UNUSED)
+{
+ SpectreRenderContext *rc;
+ unsigned char *psdata;
+ int stride;
+ unsigned char *src;
+ DATA32 *dst;
+ int yy;
+ SpectreStatus status;
+
+ rc = spectre_render_context_new();
+ if (!rc)
+ return;
+
+ spectre_page_render(page, rc, &psdata, &stride);
+ spectre_render_context_set_page_size (rc, width, height);
+ status = spectre_page_status(page);
+ if (status != SPECTRE_STATUS_SUCCESS)
+ {
+ D("[eps] %s\n", spectre_status_to_string (status));
+ return;
+ }
+
+ shm_alloc(width * height * sizeof(DATA32));
+ if (!shm_addr) return;
+ data = shm_addr;
+
+ if (stride == 4 * width)
+ _pixcopy(data, psdata, height * stride);
+ else
+ {
+ src = psdata;
+ dst = (DATA32 *)data;
+ for (yy = 0; yy < height; src += stride, dst += width, ++yy)
+ _pixcopy (dst, src, width * 4);
+ }
+
+ spectre_render_context_free(rc);
+}
+
+int
+main(int argc, char **argv)
+{
+ char *file;
+ int i;
+ int size_w = 0, size_h = 0;
+ int head_only = 0;
+ int page_nbr = 0;
+
+ if (argc < 2) return -1;
+ // file is ALWAYS first arg, other options come after
+ file = argv[1];
+ for (i = 2; i < argc; i++)
+ {
+ if (!strcmp(argv[i], "-head"))
+ // asked to only load header, not body/data
+ head_only = 1;
+ else if (!strcmp(argv[i], "-key"))
+ {
+ i++;
+ page_nbr = atoi(argv[i]);
+ i++;
+ }
+ else if (!strcmp(argv[i], "-opt-scale-down-by"))
+ { // not used by ps loader
+ i++;
+ // int scale_down = atoi(argv[i]);
+ }
+ else if (!strcmp(argv[i], "-opt-dpi"))
+ {
+ i++;
+ dpi = ((double)atoi(argv[i])) / 1000.0; // dpi is an int multiplied by 1000 (so 72dpi is 72000)
+ i++;
+ }
+ else if (!strcmp(argv[i], "-opt-size"))
+ { // not used by ps loader
+ i++;
+ size_w = atoi(argv[i]);
+ i++;
+ size_h = atoi(argv[i]);
+ }
+ }
+
+ D("_spectre_init_file\n");
+ D("dpi....: %f\n", dpi);
+ D("page...: %d\n", page_nbr);
+
+ timeout_init(10);
+
+ if (!_spectre_init(file, page_nbr, size_w, size_h))
+ return -1;
+ D("_spectre_init done\n");
+
+ D("dpi2...: %f\n", dpi);
+ if (!head_only)
+ {
+ _spectre_load_image(size_w, size_h);
+ }
+
+ D("size...: %ix%i\n", width, height);
+ D("alpha..: 0\n");
+
+ printf("size %i %i\n", width, height);
+ printf("alpha 0\n");
+
+ if (!head_only)
+ {
+ if (shm_fd >= 0) printf("shmfile %s\n", shmfile);
+ else
+ {
+ // could also to "tmpfile %s\n" like shmfile but just
+ // a mmaped tmp file on the system
+ printf("data\n");
+ fwrite(data, width * height * sizeof(DATA32), 1, stdout);
+ }
+ shm_free();
+ }
+ else
+ printf("done\n");
+
+ _spectre_shutdown();
+ fflush(stdout);
+ return 0;
+}
diff --git a/src/generic/evas/raw/main.c b/src/generic/evas/raw/main.c
new file mode 100644
index 0000000000..ac9f810048
--- /dev/null
+++ b/src/generic/evas/raw/main.c
@@ -0,0 +1,242 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <libraw.h>
+#include "shmfile.h"
+#include "timeout.h"
+
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include <Eina.h>
+
+
+#define DATA32 unsigned int
+#define DATA8 unsigned char
+
+#define ARGB_JOIN(a,r,g,b) \
+ (((a) << 24) + ((r) << 16) + ((g) << 8) + (b))
+
+//#define RAW_DBG 1
+
+#ifdef RAW_DBG
+#define D(fmt, args...) fprintf(stderr, fmt, ## args)
+#else
+#define D(fmt, args...)
+#endif
+
+static int fd = -1;
+static size_t seg_size = 0;
+static unsigned char *seg = MAP_FAILED;
+static libraw_data_t *raw_data = NULL;
+static void *data = NULL;
+static int width = 0;
+static int height = 0;
+
+static int
+_raw_init(const char *file)
+{
+ struct stat ss;
+ fd = open(file, O_RDONLY);
+ if (fd < 0) return EINA_FALSE;
+
+ if (stat(file, &ss)) goto close_file;
+ seg_size = ss.st_size;
+ seg = mmap(NULL, seg_size, PROT_READ, MAP_SHARED, fd, 0);
+ if (seg == MAP_FAILED) goto close_file;
+
+ D("raw_init\n");
+ raw_data = libraw_init(0);
+ raw_data->params.half_size = 0;
+ raw_data->params.user_qual = 2;
+
+ D("raw_open_buffer\n");
+ if (libraw_open_buffer(raw_data, seg, seg_size) != LIBRAW_SUCCESS)
+ return EINA_FALSE;
+ return EINA_TRUE;
+
+close_file:
+ close(fd);
+ return EINA_FALSE;
+}
+
+static void
+_raw_shutdown()
+{
+ D("raw_shutdown\n");
+ if (raw_data)
+ libraw_close(raw_data);
+ if (seg != MAP_FAILED) munmap(seg, seg_size);
+ close(fd);
+}
+
+static int
+read_raw_header()
+{
+ int ret;
+
+ D("raw_open_buffer\n");
+ if ((ret = libraw_open_buffer(raw_data, seg, seg_size)) != LIBRAW_SUCCESS)
+ return 0;
+
+ D("raw_adjust_size\n");
+ if ((ret = libraw_adjust_sizes_info_only(raw_data)) != LIBRAW_SUCCESS)
+ {
+ if (LIBRAW_FATAL_ERROR(ret))
+ return 0;
+ }
+
+ if ((raw_data->sizes.width < 1) || (raw_data->sizes.height < 1))
+ return 0;
+
+ width = raw_data->sizes.iwidth;
+ height = raw_data->sizes.iheight;
+
+ return 1;
+
+}
+
+
+static int
+read_raw_data()
+{
+ int ret;
+ unsigned int count;
+ libraw_processed_image_t *image = NULL;
+ DATA8 *bufptr;
+ DATA32 *dataptr;
+
+
+ D("raw_open_unpack\n");
+ if ((ret = libraw_unpack(raw_data)) != LIBRAW_SUCCESS)
+ return 0;
+
+ D("raw_dcraw_process\n");
+ if ((ret = libraw_dcraw_process(raw_data)) != LIBRAW_SUCCESS)
+ {
+ if (LIBRAW_FATAL_ERROR(ret))
+ return 0;;
+ }
+
+ D("raw_make_mem_image\n");
+ image = libraw_dcraw_make_mem_image(raw_data, &ret);
+ if (image)
+ {
+ if ((image->width < 1) || (image->height < 1))
+ goto clean_image;
+ width = image->width;
+ height = image->height;
+ if (image->type != LIBRAW_IMAGE_BITMAP)
+ goto clean_image;
+ if (image->colors != 3)
+ goto clean_image;
+#define SWAP(a, b) { a ^= b; a = (b ^=a); }
+ if ((image->bits == 16) && (htons(0x55aa) != 0x55aa))
+ for (count = 0; count < image->data_size; count +=2)
+ SWAP(image->data[count], image->data[count + 1]);
+#undef SWAP
+ shm_alloc((unsigned int)(image->width * image->height) * (sizeof(DATA32)));
+ if (!shm_addr)
+ goto clean_image;
+ data = shm_addr;
+ memset(shm_addr, 0, (unsigned int)(image->width * image->height) * (sizeof(DATA32)));
+ dataptr = data;
+ bufptr = image->data;
+ for (count = (unsigned int)(image->width * image->height); count > 0; --count)
+ {
+ *dataptr = ARGB_JOIN(0xff, bufptr[0], bufptr[1], bufptr[2]);
+ dataptr++;
+ bufptr += 3;
+ }
+
+ free(image);
+ }
+ return 1;
+
+clean_image:
+ free(image);
+ return 0;
+}
+
+
+int main(int argc, char **argv)
+{
+ char *file;
+ int i;
+ int head_only = 0;
+
+ if (argc < 2) return -1;
+ file = argv[1];
+
+ for (i = 2; i < argc; ++i)
+ {
+ if (!strcmp(argv[i], "-head"))
+ head_only = 1;
+ else if (!strcmp(argv[i], "-key"))
+ { // not used by raw loader
+ i++;
+ // const char *key = argv[i];
+ }
+ else if (!strcmp(argv[i], "-opt-scale-down-by"))
+ { // not used by raw loader
+ i++;
+ // int scale_down = atoi(argv[i]);
+ }
+ else if (!strcmp(argv[i], "-opt-dpi"))
+ { // not used by raw loader
+ i++;
+ // double dpi = ((double)atoi(argv[i])) / 1000.0;
+ }
+ else if (!strcmp(argv[i], "-opt-size"))
+ { // not used by raw loader
+ i++;
+ // int size_w = atoi(argv[i]);
+ i++;
+ // int size_h = atoi(argv[i]);
+ }
+ }
+
+ timeout_init(4);
+
+ if (!_raw_init(file)) return -1;
+ if (head_only != 0)
+ {
+ if (read_raw_header())
+ {
+ printf("size %d %d\n", width, height);
+ printf("alpha 1\n");
+ }
+ printf("done\n");
+ }
+ else
+ {
+ if (read_raw_data())
+ {
+ printf("size %d %d\n", width, height);
+ printf("alpha 1\n");
+ if (shm_fd >= 0) printf("shmfile %s\n", shmfile);
+ else
+ {
+ printf("data\n");
+ fwrite(data, (unsigned int)(width * height) * sizeof(DATA32), 1, stdout);
+ }
+ shm_free();
+ }
+ }
+ _raw_shutdown();
+ fflush(stdout);
+ return 0;
+
+}
+
diff --git a/src/generic/evas/svg/main.c b/src/generic/evas/svg/main.c
new file mode 100644
index 0000000000..5fc7912e87
--- /dev/null
+++ b/src/generic/evas/svg/main.c
@@ -0,0 +1,230 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <stdio.h>
+#include "shmfile.h"
+#include "timeout.h"
+
+#include <Eina.h>
+
+#include <librsvg/rsvg.h>
+#ifndef LIBRSVG_CHECK_VERSION
+# include <librsvg/librsvg-features.h>
+#endif
+#if LIBRSVG_CHECK_VERSION(2,36,2)
+#else
+# include <librsvg/rsvg-cairo.h>
+#endif
+
+#define DATA32 unsigned int
+
+static RsvgHandle *rsvg = NULL;
+static int width = 0;
+static int height = 0;
+static RsvgDimensionData dim;
+
+static inline Eina_Bool evas_image_load_file_is_svg(const char *file)
+{
+ int i, len = strlen(file);
+ Eina_Bool is_gz = EINA_FALSE;
+
+ for (i = len - 1; i > 0; i--)
+ {
+ if (file[i] == '.')
+ {
+ if (is_gz)
+ break;
+ else if (strcasecmp(file + i + 1, "gz") == 0)
+ is_gz = EINA_TRUE;
+ else
+ break;
+ }
+ }
+
+ if (i < 1) return EINA_FALSE;
+ i++;
+ if (i >= len) return EINA_FALSE;
+ if (strncasecmp(file + i, "svg", 3) != 0) return EINA_FALSE;
+ i += 3;
+ if (is_gz)
+ {
+ if (file[i] == '.') return EINA_TRUE;
+ else return EINA_FALSE;
+ }
+ else
+ {
+ if (file[i] == '\0') return EINA_TRUE;
+ else if (((file[i] == 'z') || (file[i] == 'Z')) && (!file[i + 1])) return EINA_TRUE;
+ else return EINA_FALSE;
+ }
+}
+
+static int
+_svg_init(const char *file)
+{
+#ifdef HAVE_SVG_2_36
+# if !defined(GLIB_VERSION_2_36)
+ g_type_init();
+# endif
+#else
+ rsvg_init();
+#endif
+
+ if (!evas_image_load_file_is_svg(file)) return 0;
+
+ rsvg = rsvg_handle_new_from_file(file, NULL);
+
+ return 1;
+}
+
+static void
+_svg_shutdown(void)
+{
+ if (rsvg)
+ {
+ rsvg_handle_close(rsvg, NULL);
+ g_object_unref(rsvg);
+ }
+ // Maybe it's not crashing anymore, let's try it.
+#ifndef HAVE_SVG_2_36
+ rsvg_term();
+#endif
+}
+
+static int
+read_svg_header(int scale_down, double dpi, int size_w, int size_h)
+{
+ rsvg_handle_set_dpi(rsvg, 75.0);
+ rsvg_handle_get_dimensions(rsvg, &dim);
+ width = dim.width;
+ height = dim.height;
+
+ if ((width < 1) || (height < 1)) return 0;
+
+ if (scale_down > 1)
+ {
+ width /= scale_down;
+ height /= scale_down;
+ }
+ else if (dpi > 0.0)
+ {
+ width = (width * dpi) / 75;
+ height = (height * dpi) / 75;
+ }
+ else if (size_w > 0 && size_h > 0)
+ {
+ int w, h;
+
+ w = size_w;
+ h = (size_w * height) / width;
+ if (h > size_h)
+ {
+ h = size_h;
+ w = (size_h * width) / height;
+ }
+ width = w;
+ height = h;
+ }
+ if (width < 1) width = 1;
+ if (height < 1) height = 1;
+
+ return 1;
+}
+
+static int
+read_svg_data(void)
+{
+ cairo_surface_t *surface;
+ cairo_t *cr;
+
+ shm_alloc(width * height * (sizeof(DATA32)));
+ if (!shm_addr) return 0;
+
+ memset(shm_addr, 0, width * height * sizeof (DATA32));
+ surface = cairo_image_surface_create_for_data((unsigned char *)shm_addr, CAIRO_FORMAT_ARGB32,
+ width, height, width * sizeof(DATA32));;
+ if (!surface) return 0;
+
+ cr = cairo_create(surface);
+ if (!cr) return 0;
+
+ cairo_scale(cr, (double) width / dim.em, (double) height / dim.ex);
+ rsvg_handle_render_cairo(rsvg, cr);
+ cairo_surface_destroy(surface);
+ cairo_destroy(cr);
+
+ return 1;
+}
+
+int main(int argc, char **argv)
+{
+ char *file;
+ int i;
+ int head_only = 0;
+ int scale_down = 0;
+ double dpi = 0.0;
+ int size_w = 0, size_h = 0;
+
+ if (argc < 2) return -1;
+ file = argv[1];
+
+ for (i = 2; i < argc; ++i)
+ {
+ if (!strcmp(argv[i], "-head"))
+ head_only = 1;
+ else if (!strcmp(argv[i], "-key"))
+ { // not used by svg loader
+ i++;
+ // const char *key = argv[i];
+ }
+ else if (!strcmp(argv[i], "-opt-scale-down-by"))
+ {
+ i++;
+ scale_down = atoi(argv[i]);
+ }
+ else if (!strcmp(argv[i], "-opt-dpi"))
+ {
+ i++;
+ dpi = ((double)atoi(argv[i])) / 1000.0;
+ }
+ else if (!strcmp(argv[i], "-opt-size"))
+ {
+ i++;
+ size_w = atoi(argv[i]);
+ i++;
+ size_h = atoi(argv[i]);
+ }
+ }
+
+ timeout_init(5);
+
+ if (!_svg_init(file)) return -1;
+ if (!read_svg_header(scale_down, dpi, size_w, size_h)) return -1;
+
+ if (head_only != 0)
+ {
+ printf("size %d %d\n", width, height);
+ printf("alpha 1\n");
+ printf("done\n");
+ }
+ else
+ {
+ if (read_svg_data())
+ {
+ printf("size %d %d\n", width, height);
+ printf("alpha 1\n");
+ if (shm_fd >= 0) printf("shmfile %s\n", shmfile);
+ else
+ {
+ printf("data\n");
+ fwrite(shm_addr, width * height * sizeof(DATA32), 1, stdout);
+ }
+ shm_free();
+ }
+ }
+ _svg_shutdown();
+ fflush(stdout);
+ return 0;
+
+}
+
diff --git a/src/generic/evas/xcf/common.h b/src/generic/evas/xcf/common.h
new file mode 100644
index 0000000000..5abaab8677
--- /dev/null
+++ b/src/generic/evas/xcf/common.h
@@ -0,0 +1,51 @@
+#ifndef __COMMON
+#define __COMMON 1
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <math.h>
+#include <netinet/in.h>
+#include <time.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <zlib.h>
+
+#define DATABIG unsigned long long
+#define DATA64 unsigned long long
+#define DATA32 unsigned int
+#define DATA16 unsigned short
+#define DATA8 unsigned char
+
+#ifndef WORDS_BIGENDIAN
+
+#define A_VAL(p) ((DATA8 *)(p))[3]
+#define R_VAL(p) ((DATA8 *)(p))[2]
+#define G_VAL(p) ((DATA8 *)(p))[1]
+#define B_VAL(p) ((DATA8 *)(p))[0]
+
+#else
+
+#define A_VAL(p) ((DATA8 *)(p))[0]
+#define R_VAL(p) ((DATA8 *)(p))[1]
+#define G_VAL(p) ((DATA8 *)(p))[2]
+#define B_VAL(p) ((DATA8 *)(p))[3]
+
+#endif
+
+//#define XCF_DBG 1
+
+#ifdef XCF_DBG
+#define D(fmt, args...) fprintf(stderr, fmt, ## args)
+#else
+#define D(fmt, args...)
+#endif
+
+#endif
diff --git a/src/generic/evas/xcf/main.c b/src/generic/evas/xcf/main.c
new file mode 100644
index 0000000000..373823bf32
--- /dev/null
+++ b/src/generic/evas/xcf/main.c
@@ -0,0 +1,1731 @@
+/*
+
+ -----------------------------[ XCF Loader ]-----------------------------
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ ------------------------------------------------------------------------
+
+ There's a quick overview of the XCF file structure in Gimp's source
+ tree, in docs/xcf.doc. However it's brief, so here's a more verbose
+ overview based on my understanding of XCF. All image characteristics
+ are defined in "properties". In the data stream properties are defined
+ through a 4 bit index number (see enum below), followed by a 4 byte
+ length. The property data directly follows this information. A list of
+ properties ends when PROP_END is encountered. There is a properties
+ block at the beginning of the file, as well as at the beginning of each
+ layer and channel. Layers and channels are read at offsets in the file,
+ the list of layers (resp. channels) is exhausted when the next offset
+ read in is zero.
+
+ The actual image data is stored in tiles, which are by default 64x64 in
+ size, likely with smaller ones on the right and bottom edges.
+
+ The position of the tiles on the image is left->right, row by row. The
+ actual DATA8* data is contained in a "level" which is contained in a
+ "hierarchy". I've not really understood the purpose of the hierarchy, as
+ it seems to always contain only one level anyway.
+
+ Layer masks are stored as channels (basically grayscale layers with a
+ single color definition. For the purpose of this loader I replaced the
+ concept of a channel with a layer, since it doesn't really matter.
+
+ Ok, hope this helps with understanding XCF. -- cK.
+
+*/
+#include "common.h"
+#include "shmfile.h"
+#include "timeout.h"
+
+#define FREE(X) { free(X); X = NULL; }
+
+#define TILE_WIDTH 64
+#define TILE_HEIGHT 64
+
+/* --------------------------------------------------------------------------- typedefs ------------ */
+
+typedef struct _Layer Layer;
+typedef struct _Tile Tile;
+
+/* ------------------------------------------------------------------------------ enums ------------ */
+
+
+/* These are all the properties that a layer or channel can have.
+ Only some of them are actually used. */
+typedef enum
+{
+ PROP_END = 0,
+ PROP_COLORMAP = 1,
+ PROP_ACTIVE_LAYER = 2,
+ PROP_ACTIVE_CHANNEL = 3,
+ PROP_SELECTION = 4,
+ PROP_FLOATING_SELECTION = 5,
+ PROP_OPACITY = 6,
+ PROP_MODE = 7,
+ PROP_VISIBLE = 8,
+ PROP_LINKED = 9,
+ PROP_PRESERVE_TRANSPARENCY = 10,
+ PROP_APPLY_MASK = 11,
+ PROP_EDIT_MASK = 12,
+ PROP_SHOW_MASK = 13,
+ PROP_SHOW_MASKED = 14,
+ PROP_OFFSETS = 15,
+ PROP_COLOR = 16,
+ PROP_COMPRESSION = 17,
+ PROP_GUIDES = 18,
+ PROP_RESOLUTION = 19,
+ PROP_TATTOO = 20,
+ PROP_PARASITES = 21,
+ PROP_UNIT = 22,
+ PROP_PATHS = 23,
+ PROP_USER_UNIT = 24
+}
+PropType;
+
+/* The tiles can be stored in an encrypted fashion, defined as follows: */
+typedef enum
+{
+ COMPRESS_NONE = 0,
+ COMPRESS_RLE = 1,
+ COMPRESS_ZLIB = 2,
+ COMPRESS_FRACTAL = 3 /* Unused. */
+} CompressionType;
+
+/* Layer modes (*SIGH*) */
+typedef enum
+{
+ NORMAL_MODE,
+ DISSOLVE_MODE,
+ BEHIND_MODE,
+ MULTIPLY_MODE,
+ SCREEN_MODE,
+ OVERLAY_MODE,
+ DIFFERENCE_MODE,
+ ADDITION_MODE,
+ SUBTRACT_MODE,
+ DARKEN_ONLY_MODE,
+ LIGHTEN_ONLY_MODE,
+ HUE_MODE,
+ SATURATION_MODE,
+ COLOR_MODE,
+ VALUE_MODE,
+ DIVIDE_MODE,
+ ERASE_MODE, /*< skip >*/
+ REPLACE_MODE, /*< skip >*/
+ ANTI_ERASE_MODE /*< skip >*/
+}
+LayerModeEffects;
+
+/* Base image types */
+typedef enum
+{
+ RGB,
+ GRAY,
+ INDEXED
+} GimpImageBaseType;
+
+/* Image types */
+typedef enum
+{
+ RGB_GIMAGE,
+ RGBA_GIMAGE,
+ GRAY_GIMAGE,
+ GRAYA_GIMAGE,
+ INDEXED_GIMAGE,
+ INDEXEDA_GIMAGE
+} GimpImageType;
+
+/* ---------------------------------------------------------------------------- structs ------------ */
+
+/* Ok, this is what's left of Gimp's layer abstraction. I kicked out
+ all the stuff that's unnecessary and added the necessary stuff
+ from the Gimp drawable superclass. This one also serves as a
+ Channel, e.g. for use as a layer mask.
+ --cK.
+*/
+struct _Layer
+{
+ int visible; /* controls visibility */
+ int width, height; /* size of drawable */
+ int bpp; /* depth */
+ int offset_x, offset_y; /* offset of layer in image */
+
+ int ID; /* provides a unique ID */
+ GimpImageType type; /* type of drawable */
+ char has_alpha; /* drawable has alpha */
+
+ int preserve_trans; /* preserve transparency */
+
+ Layer *mask; /* possible layer mask */
+
+ int opacity; /* layer opacity */
+ LayerModeEffects mode; /* layer combination mode */
+
+
+ /* XCF stores the actual image data as tiles. A Layer is covered with
+ tiles, the tiles on the right and bottom will (usually) be a bit
+ smaller. num_rows and num_cols gives the number of tile rows and
+ columns.
+ */
+
+ Tile* tiles; /* tiles for drawable data */
+ int num_rows;
+ int num_cols;
+
+ /* After the tiles are read in, they're serialized int an array
+ of DATA8's, that will always contain 4 bpp data. Not optimal,
+ I know, but makes life easier
+ */
+
+ DATA8* data;
+
+ /* Layers are stored as a linked list. */
+ struct _Layer* next;
+ struct _Layer* prev;
+};
+
+
+/* The tile structure:
+*/
+struct _Tile
+{
+ unsigned char bpp; /* the bytes per pixel (1, 2, 3 or 4) */
+ unsigned short ewidth; /* the effective width of the tile */
+ unsigned short eheight; /* the effective height of the tile */
+
+ /* a tile's effective width and height may be smaller
+ * (but not larger) than TILE_WIDTH and TILE_HEIGHT.
+ * This is to handle edge tiles of a drawable.
+ */
+
+ DATA8 *data;
+};
+
+
+/* This struct simply contains everything that didn't fit elsewhere,
+ based on GimpImage :)
+*/
+struct _GimpImage
+{
+ void *file;
+ char *filename;
+ long cp;
+ int compression; /* file compression mode */
+ int file_version;
+
+ int width, height; /* width and height attributes */
+ GimpImageBaseType base_type; /* base gimp_image type */
+
+ DATA32 floating_sel_offset;
+
+ DATA8* cmap; /* colormap--for indexed */
+ int num_cols; /* number of colors in map */
+
+ /* If a layer number was passed to the loader, it goes here: */
+ int single_layer_index;
+
+ /* Tadaa -- the final image data. Layers get pasted
+ onto this one, bottom-up.
+ */
+ DATA8* data;
+
+ Layer* layers;
+ Layer* last_layer;
+ Layer* floating_sel;
+}
+_image;
+
+/* ------------------------------------------------------------------------- prototypes ------------ */
+
+typedef struct _File File;
+typedef struct _Chunk Chunk;
+
+#define FBUF 1
+#define CHUNK_SIZE (32 * 1024)
+
+struct _Chunk
+{
+ int size;
+ unsigned char data[CHUNK_SIZE];
+};
+
+struct _File
+{
+ int fd;
+ gzFile fp;
+ long pos, size;
+ int chunk_num;
+ Chunk **chunk;
+};
+
+static File *
+f_open(const char *file)
+{
+ File *f;
+
+ f = calloc(1, sizeof(File));
+ if (!f) return NULL;
+ f->fd = open(file, O_RDONLY);
+ if (f->fd < 0)
+ {
+ D("open of %s failed\n", file);
+ free(f);
+ return NULL;
+ }
+ f->fp = gzdopen(f->fd, "r");
+ if (!f->fp)
+ {
+ D("gzdopen of %i failed\n", f->fd);
+ close(f->fd);
+ free(f);
+ return NULL;
+ }
+ return f;
+}
+
+static void
+f_close(File *f)
+{
+ // FIXME: free chunks
+ gzclose(f->fp);
+ free(f);
+}
+
+#ifdef FBUF
+static void
+_f_read_pos(File *f, long pos, long bytes)
+{
+ long i, cnum;
+ Chunk **cks;
+
+ if (f->size > 0) return;
+ cnum = ((pos + bytes) / CHUNK_SIZE) + 1;
+ if (f->chunk_num >= cnum) return;
+ D("FFFF: go up to %li + %li, chunks %li\n", pos, bytes, cnum);
+ cks = realloc(f->chunk, sizeof(Chunk *) * cnum);
+ if (!cks) return;
+ f->chunk = cks;
+ for (i = f->chunk_num; i < cnum; i++)
+ {
+ if (f->size != 0)
+ {
+ f->chunk[i] = NULL;
+ continue;
+ }
+ f->chunk[i] = malloc(sizeof(Chunk));
+ if (f->chunk[i])
+ {
+ f->chunk[i]->size = gzread(f->fp, f->chunk[i]->data, CHUNK_SIZE);
+ D("FFFF: go %i\n", f->chunk[i]->size);
+ if (f->chunk[i]->size < CHUNK_SIZE)
+ {
+ f->size = (i * CHUNK_SIZE) + f->chunk[i]->size;
+ }
+ }
+ }
+ f->chunk_num = cnum;
+}
+#endif
+
+static long
+f_read(File *f, unsigned char *dest, long bytes)
+{
+#ifdef FBUF
+ long done = 0, off = 0;
+ int c;
+ unsigned char *p;
+ _f_read_pos(f, f->pos, bytes);
+
+ c = f->pos / CHUNK_SIZE;
+ off = f->pos - (c * CHUNK_SIZE);
+ p = dest;
+ while ((done < bytes) && (c < f->chunk_num))
+ {
+ long amount = bytes - done;
+
+ if (!f->chunk[c]) break;
+ if (amount > (f->chunk[c]->size - off))
+ amount = (f->chunk[c]->size - off);
+ if (amount < 1) return 0;
+ memcpy(p, f->chunk[c]->data + off, amount);
+ p += amount;
+ off = 0;
+ done += amount;
+ c++;
+ }
+ f->pos += done;
+ return done;
+#else
+ long done = gzread(f->fp, dest, bytes);
+ f->pos += done;
+ return done;
+#endif
+}
+
+static void
+f_seek(File *f, long pos)
+{
+#ifdef FBUF
+ if (f->size > 0)
+ {
+ if (pos >= f->size) pos = f->size -1;
+ }
+#endif
+ if (f->pos == pos) return;
+ f->pos = pos;
+#ifdef FBUF
+ _f_read_pos(f, f->pos, 1);
+#else
+ gzseek(f->fp, f->pos, SEEK_SET);
+#endif
+}
+
+
+/* stuff that was adapted from xcf.c */
+
+static void xcf_seek_pos(int pos);
+static int xcf_read_int32(void *fp, DATA32 *data, int count);
+static int xcf_read_int8(void *fp, DATA8 *data, int count);
+static int xcf_read_string(void *fp, char **data, int count);
+static char xcf_load_prop(PropType *prop_type, DATA32 *prop_size);
+static void xcf_load_image(void);
+static char xcf_load_image_props(void);
+
+static Layer* xcf_load_channel(void);
+static char xcf_load_channel_props(Layer *layer);
+static Layer* xcf_load_layer(void);
+static char xcf_load_layer_props(Layer *layer);
+static char xcf_load_hierarchy(Tile** tiles, int *num_rows, int *num_cols, int *bpp);
+static char xcf_load_level(Tile** tiles, int hierarchy_width, int hierarchy_height, int bpp, int* num_rows, int *num_cols);
+static char xcf_load_tile(Tile *tile);
+static char xcf_load_tile_rle(Tile *tile, int data_length);
+
+/* new stuff :) */
+
+static Tile* allocate_tiles(int width, int height, int bpp, int* num_rows, int* num_cols);
+static void free_tiles(Tile* tiles, int num_tiles);
+static void init_tile(Tile* tile, int width, int height, int bpp);
+static Layer* new_layer(int width, int height, GimpImageType type, int opacity, LayerModeEffects mode);
+static void free_layer(Layer* layer);
+static void add_layer_to_image(Layer* layer);
+static void read_tiles_into_data(Tile* tiles, int num_cols, int width, int height, int bpp, DATA8** data, int use_cmap);
+static void apply_layer_mask(Layer* layer);
+static void set_layer_opacity(Layer* layer);
+static void flatten_image(void);
+
+static char xcf_file_init(char* filename);
+static void xcf_cleanup(void);
+
+/* Stuff for layer merging: */
+extern 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);
+extern 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);
+extern 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);
+extern 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);
+extern 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);
+extern 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);
+extern 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);
+extern 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);
+extern 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);
+extern 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);
+extern 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);
+extern 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);
+extern 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);
+extern 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);
+extern 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);
+
+/* ---------------------------------------------------------------------------- globals ------------ */
+
+/* This makes using the Gimp sources easier */
+static struct _GimpImage * image = &_image;
+
+/* ------------------------------------------------------------------------------- code ------------ */
+
+static void
+xcf_seek_pos(int pos)
+{
+ if (image->cp != pos)
+ {
+ image->cp = pos;
+ f_seek(image->file, image->cp);
+ }
+}
+
+static int
+xcf_read_int32(void *fp,
+ DATA32 *data,
+ int count)
+{
+ int total;
+
+ total = count;
+ if (count > 0)
+ {
+ xcf_read_int8(fp, (DATA8*) data, count * 4);
+ while (count--)
+ {
+ *data = (DATA32)ntohl(*data);
+ data++;
+ }
+ }
+ return total * 4;
+}
+
+static int
+xcf_read_int8(void *fp,
+ DATA8 *data,
+ int count)
+{
+ int total;
+ int bytes;
+
+ total = count;
+ while (count > 0)
+ {
+ bytes = f_read(fp, data, count);
+ if (bytes <= 0) /* something bad happened */
+ break;
+ count -= bytes;
+ data += bytes;
+ }
+ return total;
+}
+
+static int
+xcf_read_string(void *fp,
+ char **data,
+ int count)
+{
+ DATA32 tmp;
+ int total;
+ int i;
+
+ total = 0;
+ for (i = 0; i < count; i++)
+ {
+ total += xcf_read_int32(fp, &tmp, 1);
+ if (tmp > 0)
+ {
+ data[i] = malloc(sizeof(DATA8) * tmp);
+ if (data[i]) total += xcf_read_int8(fp, (DATA8 *)data[i], tmp);
+ }
+ else
+ data[i] = NULL;
+ }
+ return total;
+}
+
+
+static char
+xcf_load_prop(PropType *prop_type,
+ DATA32 *prop_size)
+{
+ image->cp += xcf_read_int32(image->file, (DATA32 *)prop_type, 1);
+ image->cp += xcf_read_int32(image->file, (DATA32 *)prop_size, 1);
+ return 1;
+}
+
+
+static char
+xcf_load_image_props(void)
+{
+ PropType prop_type;
+ DATA32 prop_size;
+
+ while (1)
+ {
+ if (!xcf_load_prop (&prop_type, &prop_size)) return 0;
+ switch (prop_type)
+ {
+ case PROP_END:
+ {
+ D("Finished reading image properties.\n");
+ return 1;
+ }
+ case PROP_COLORMAP:
+ {
+ if (image->file_version == 0)
+ {
+ int i;
+ fprintf (stderr,
+ "XCF warning: version 0 of XCF file format\n"
+ "did not save indexed colormaps correctly.\n"
+ "Substituting grayscale map.\n");
+ image->cp += xcf_read_int32(image->file, (DATA32 *)&image->num_cols, 1);
+ image->cmap = malloc(sizeof(DATA8) * image->num_cols * 3);
+ if (!image->cmap) return 0;
+ xcf_seek_pos (image->cp + image->num_cols);
+ for (i = 0; i < image->num_cols; i++)
+ {
+ image->cmap[(i * 3) + 0] = i;
+ image->cmap[(i * 3) + 1] = i;
+ image->cmap[(i * 3) + 2] = i;
+ }
+ }
+ else
+ {
+ D("Loading colormap.\n");
+ image->cp += xcf_read_int32(image->file, (DATA32 *)&image->num_cols, 1);
+ image->cmap = malloc(sizeof(DATA8) * image->num_cols * 3);
+ if (!image->cmap) return 0;
+ image->cp += xcf_read_int8(image->file, (DATA8 *)image->cmap, image->num_cols * 3);
+ }
+ }
+ break;
+ case PROP_COMPRESSION:
+ {
+ char compression;
+
+ image->cp += xcf_read_int8(image->file, (DATA8 *)&compression, 1);
+
+ if ((compression != COMPRESS_NONE) &&
+ (compression != COMPRESS_RLE) &&
+ (compression != COMPRESS_ZLIB) &&
+ (compression != COMPRESS_FRACTAL))
+ {
+ fprintf (stderr, "unknown xcf compression type: %d\n", (int) compression);
+ return 0;
+ }
+
+ D("Image compression type: %i\n", compression);
+
+ image->compression = compression;
+ }
+ break;
+ /* I threw out all of the following: --cK */
+ case PROP_TATTOO:
+ case PROP_PARASITES:
+ case PROP_UNIT:
+ case PROP_PATHS:
+ case PROP_USER_UNIT:
+ case PROP_GUIDES:
+ case PROP_RESOLUTION:
+ default:
+ {
+ DATA8 buf[16];
+ int amount;
+
+ D("Skipping unexpected/unknown image property: %d\n", prop_type);
+
+ while (prop_size > 0)
+ {
+ amount = (16 < prop_size ? 16 : prop_size);
+ image->cp += xcf_read_int8(image->file, buf, amount);
+ prop_size -= amount;
+ }
+ }
+ break;
+ }
+ }
+ return 0;
+}
+
+
+static void
+xcf_load_image(void)
+{
+ Layer *layer;
+ DATA32 saved_pos;
+ DATA32 offset;
+ int num_successful_elements = 0;
+
+ /* read the image properties */
+ if (!xcf_load_image_props()) goto hard_error;
+
+ while (1)
+ {
+ /* read in the offset of the next layer */
+ image->cp += xcf_read_int32(image->file, &offset, 1);
+ /* if the offset is 0 then we are at the end
+ * of the layer list. */
+ if (offset == 0) break;
+ /* save the current position as it is where the
+ * next layer offset is stored. */
+ saved_pos = image->cp;
+ /* seek to the layer offset */
+ xcf_seek_pos(offset);
+ /* read in the layer */
+ layer = xcf_load_layer();
+ if (!layer) goto error;
+ num_successful_elements++;
+ /* add the layer to the image if it's visible */
+ if (layer->visible) add_layer_to_image(layer);
+ else free_layer(layer);
+ /* restore the saved position so we'll be ready to
+ * read the next offset. */
+ xcf_seek_pos (saved_pos);
+ }
+ /* If we were a Gimp we would now load the user-defined channels here ... */
+ /* Flat-o-rama now :) */
+ flatten_image();
+ return;
+error:
+ if (num_successful_elements == 0) goto hard_error;
+ fprintf(stderr, "XCF: This file is corrupt! I have loaded as much\nof it as I can, but it is incomplete.\n");
+ return;
+hard_error:
+ fprintf(stderr, "XCF: This file is corrupt! I could not even\nsalvage any partial image data from it.\n");
+ return;
+}
+
+static char
+xcf_load_layer_props(Layer *layer)
+{
+ PropType prop_type;
+ DATA32 prop_size;
+
+ while (1)
+ {
+ if (!xcf_load_prop(&prop_type, &prop_size)) return 0;
+ switch (prop_type)
+ {
+ case PROP_END:
+ {
+ D("Finished reading layer properties.\n");
+ return 1;
+ }
+ case PROP_FLOATING_SELECTION:
+ D("Loading floating selection.\n");
+ image->floating_sel = layer;
+ image->cp += xcf_read_int32(image->file, (DATA32 *)&image->floating_sel_offset, 1);
+ break;
+ case PROP_OPACITY:
+ image->cp += xcf_read_int32(image->file, (DATA32 *)&layer->opacity, 1);
+ break;
+ case PROP_VISIBLE:
+ image->cp += xcf_read_int32(image->file, (DATA32 *)&layer->visible, 1);
+ break;
+ case PROP_PRESERVE_TRANSPARENCY:
+ image->cp += xcf_read_int32(image->file, (DATA32 *)&layer->preserve_trans, 1);
+ break;
+ case PROP_OFFSETS:
+ image->cp += xcf_read_int32(image->file, (DATA32 *)&layer->offset_x, 1);
+ image->cp += xcf_read_int32(image->file, (DATA32 *)&layer->offset_y, 1);
+ break;
+ case PROP_MODE:
+ image->cp += xcf_read_int32(image->file, (DATA32 *)&layer->mode, 1);
+ break;
+
+ /* I threw out all of the following: --cK */
+ case PROP_LINKED:
+ case PROP_ACTIVE_LAYER:
+ case PROP_TATTOO:
+ case PROP_APPLY_MASK:
+ case PROP_EDIT_MASK:
+ case PROP_SHOW_MASK:
+ case PROP_PARASITES:
+ default:
+ {
+ DATA8 buf[16];
+ int amount;
+
+ D("Skipping unexpected/unknown/unneeded channel property: %d\n", prop_type);
+ while (prop_size > 0)
+ {
+ amount = (16 < prop_size ? 16 : prop_size);
+ image->cp += xcf_read_int8 (image->file, buf, amount);
+ prop_size -= amount;
+ }
+ }
+ break;
+ }
+ }
+
+ return 0;
+}
+
+
+static Layer *
+xcf_load_layer(void)
+{
+ Layer *layer;
+ Layer *layer_mask;
+ DATA32 hierarchy_offset;
+ DATA32 layer_mask_offset;
+ int width;
+ int height;
+ int type;
+ char *name;
+
+ D("Loading one layer ...\n");
+ /* read in the layer width, height and type */
+ image->cp += xcf_read_int32(image->file, (DATA32 *)&width, 1);
+ image->cp += xcf_read_int32(image->file, (DATA32 *)&height, 1);
+ image->cp += xcf_read_int32(image->file, (DATA32 *)&type, 1);
+ image->cp += xcf_read_string(image->file, &name, 1);
+ /* ugly, I know */
+ FREE(name);
+
+ /* create a new layer */
+ layer = new_layer(width, height, type, 255, NORMAL_MODE);
+ if (!layer) return NULL;
+
+ /* read in the layer properties */
+ if (!xcf_load_layer_props(layer)) goto error;
+
+ D("Loading opacity: %i \n", layer->opacity);
+ if (!layer->visible) return layer;
+
+ /* read the hierarchy and layer mask offsets */
+ image->cp += xcf_read_int32(image->file, &hierarchy_offset, 1);
+ image->cp += xcf_read_int32(image->file, &layer_mask_offset, 1);
+ /* read in the hierarchy */
+ xcf_seek_pos(hierarchy_offset);
+ if (!xcf_load_hierarchy(&(layer->tiles), &(layer->num_rows),
+ &(layer->num_cols), &(layer->bpp)))
+ goto error;
+
+ /* read in the layer mask */
+ if (layer_mask_offset != 0)
+ {
+ D("Loading layer mask.\n");
+ xcf_seek_pos(layer_mask_offset);
+
+ layer_mask = xcf_load_channel();
+ if (!layer_mask) goto error;
+
+ /* set the offsets of the layer_mask */
+ layer_mask->offset_x = layer->offset_x;
+ layer_mask->offset_y = layer->offset_y;
+ layer->mask = layer_mask;
+ }
+ read_tiles_into_data(layer->tiles, layer->num_cols,
+ layer->width, layer->height,
+ layer->bpp, &(layer->data),
+ 1);
+ free_tiles(layer->tiles, layer->num_rows * layer->num_cols);
+ layer->tiles = NULL;
+ set_layer_opacity(layer);
+ if (layer->mask) apply_layer_mask(layer);
+
+ return layer;
+
+error:
+ free_layer(layer);
+ return NULL;
+}
+
+
+static void
+read_tiles_into_data(Tile *tiles, int num_cols, int width,
+ int height, int bpp, DATA8 **data_p, int use_cmap)
+{
+ int tile_x, tile_y, x, y, offset_x, offset_y;
+ DATA8 *data;
+ DATA8 *ptr;
+ DATA8 *ptr2;
+ Tile *t;
+ int warned = 0;
+
+ if (tiles)
+ {
+ if (*data_p) FREE(*data_p);
+
+ /* Always allocate the data as 4 bytes per pixel */
+ data = (*data_p) = malloc(sizeof(DATA32) * width * height);
+ if (!data) return;
+
+ ptr = data;
+ for (y = 0; y < height; y++)
+ {
+ for (x = 0; x < width; x++)
+ {
+ tile_x = x / TILE_WIDTH;
+ tile_y = y / TILE_HEIGHT;
+ offset_x = x % TILE_WIDTH;
+ offset_y = y % TILE_HEIGHT;
+
+ t = &tiles[(tile_y * num_cols) + tile_x];
+ ptr2 = &(t->data[(offset_y * t->ewidth * bpp) +
+ (offset_x * bpp)]);
+ switch (bpp)
+ {
+ case 1:
+ {
+ /* use colormap if the image has one */
+ if (image->cmap && use_cmap)
+ {
+ R_VAL(ptr) = image->cmap[(*(ptr2) * 3)];
+ G_VAL(ptr) = image->cmap[(*(ptr2) * 3) + 1];
+ B_VAL(ptr) = image->cmap[(*(ptr2) * 3) + 2];
+ A_VAL(ptr) = 255;
+ }
+ /* else use colors themselves */
+ else
+ {
+ R_VAL(ptr) = *(ptr2);
+ G_VAL(ptr) = *(ptr2);
+ B_VAL(ptr) = *(ptr2);
+ A_VAL(ptr) = 255;
+ }
+ break;
+ }
+ case 2:
+ {
+ /* use colormap if the image has one */
+ if (image->cmap && use_cmap)
+ {
+ R_VAL(ptr) = image->cmap[(*(ptr2) * 3)];
+ G_VAL(ptr) = image->cmap[(*(ptr2) * 3) + 1];
+ B_VAL(ptr) = image->cmap[(*(ptr2) * 3) + 2];
+ A_VAL(ptr) = *(ptr2 + 1);
+ }
+ /* else use colors themselves */
+ else if (warned == 0)
+ {
+ warned++;
+ fprintf (stderr, "There's nothing to see here. 2 bpp without colormap not implemented yet.\n");
+ }
+ break;
+ }
+ case 3:
+ {
+ if (image->cmap)
+ {
+ if (warned == 0)
+ {
+ warned++;
+ fprintf (stderr, "There's nothing to see here. 3 bpp with colormap not implemented yet.\n");
+ }
+ }
+ else
+ {
+ R_VAL(ptr) = *(ptr2);
+ G_VAL(ptr) = *(ptr2 + 1);
+ B_VAL(ptr) = *(ptr2 + 2);
+ A_VAL(ptr) = 255;
+ }
+ break;
+ }
+ default:
+ {
+ R_VAL(ptr) = *(ptr2);
+ G_VAL(ptr) = *(ptr2 + 1);
+ B_VAL(ptr) = *(ptr2 + 2);
+ A_VAL(ptr) = *(ptr2 + 3);
+ break;
+ }
+ }
+ ptr += 4;
+ }
+ }
+ }
+}
+
+static Layer *
+xcf_load_channel(void)
+{
+ Layer *layer;
+ DATA32 hierarchy_offset;
+ int width;
+ int height;
+ char *name;
+
+ D("Loading channel ...\n");
+ /* read in the layer width, height and name */
+ image->cp += xcf_read_int32(image->file, (DATA32 *)&width, 1);
+ image->cp += xcf_read_int32(image->file, (DATA32 *)&height, 1);
+ image->cp += xcf_read_string(image->file, &name, 1);
+
+ /* Yeah, still ugly :) */
+ FREE(name);
+
+ /* create a new channel */
+ layer = new_layer(width, height, GRAY_GIMAGE, 255, NORMAL_MODE);
+ if (!layer) return NULL;
+ /* read in the channel properties */
+ if (!xcf_load_channel_props(layer)) goto error;
+ /* read the hierarchy and layer mask offsets */
+ image->cp += xcf_read_int32(image->file, &hierarchy_offset, 1);
+ /* read in the hierarchy */
+ xcf_seek_pos(hierarchy_offset);
+ if (!xcf_load_hierarchy(&(layer->tiles), &(layer->num_rows), &(layer->num_cols), &(layer->bpp)))
+ goto error;
+ read_tiles_into_data(layer->tiles, layer->num_cols, layer->width,
+ layer->height, layer->bpp, &(layer->data), 0);
+ free_tiles(layer->tiles, layer->num_rows * layer->num_cols);
+ layer->tiles = NULL;
+
+ D("Channel loaded successfully.\n");
+ return layer;
+
+error:
+ free_layer(layer);
+ return NULL;
+}
+
+static char
+xcf_load_channel_props(Layer *layer)
+{
+ PropType prop_type;
+ DATA32 prop_size;
+
+ while (1)
+ {
+ if (!xcf_load_prop(&prop_type, &prop_size)) return 0;
+
+ switch (prop_type)
+ {
+ case PROP_END:
+ {
+ D("Finished loading channel props.\n");
+ return 1;
+ }
+ case PROP_OPACITY:
+ image->cp += xcf_read_int32(image->file, (DATA32 *)&layer->opacity, 1);
+ break;
+ case PROP_VISIBLE:
+ image->cp += xcf_read_int32(image->file, (DATA32 *)&layer->visible, 1);
+ break;
+ case PROP_ACTIVE_CHANNEL:
+ case PROP_SHOW_MASKED:
+ case PROP_SELECTION:
+ case PROP_COLOR:
+ case PROP_TATTOO:
+ case PROP_PARASITES:
+ default:
+ {
+ DATA8 buf[16];
+ int amount;
+
+ D("Skipping unexpected/unknown/unneeded channel property: %d\n", prop_type);
+
+ while (prop_size > 0)
+ {
+ amount = (16 < prop_size ? 16 : prop_size);
+ image->cp += xcf_read_int8(image->file, buf, amount);
+ prop_size -= amount;
+ }
+ }
+ break;
+ }
+ }
+ return 0;
+}
+
+static char
+xcf_load_hierarchy(Tile **tiles, int *num_rows, int *num_cols, int *bpp)
+{
+ DATA32 saved_pos;
+ DATA32 offset;
+ DATA32 junk;
+ int width;
+ int height;
+
+ image->cp += xcf_read_int32(image->file, (DATA32 *)&width, 1);
+ image->cp += xcf_read_int32(image->file, (DATA32 *)&height, 1);
+ image->cp += xcf_read_int32(image->file, (DATA32 *)bpp, 1);
+ image->cp += xcf_read_int32(image->file, &offset, 1); /* top level */
+
+ D("Loading hierarchy: width %i, height %i, bpp %i\n", width, height, *bpp);
+
+ /* discard offsets for layers below first, if any. */
+ do
+ {
+ image->cp += xcf_read_int32(image->file, &junk, 1);
+ }
+ while (junk != 0);
+ /* save the current position as it is where the
+ * next level offset is stored. */
+ saved_pos = image->cp;
+ /* seek to the level offset */
+ xcf_seek_pos(offset);
+ /* read in the level */
+ if (!xcf_load_level(tiles, width, height, *bpp, num_rows, num_cols))
+ return 0;
+ /* restore the saved position so we'll be ready to
+ * read the next offset. */
+ xcf_seek_pos (saved_pos);
+ D("Loaded hierarchy successfully.\n");
+ return 1;
+}
+
+static char
+xcf_load_level(Tile **tiles_p, int hierarchy_width, int hierarchy_height,
+ int bpp, int *num_rows, int *num_cols)
+{
+ DATA32 saved_pos;
+ DATA32 offset, offset2;
+ int ntiles;
+ int width;
+ int height;
+ int i;
+ int fail;
+ Tile *tiles;
+ Tile *current_tile;
+
+ image->cp += xcf_read_int32(image->file, (DATA32*) &width, 1);
+ image->cp += xcf_read_int32(image->file, (DATA32*) &height, 1);
+
+ if ((width != hierarchy_width) || (height != hierarchy_height)) return 0;
+
+ D("Loading level of size %ix%i.\n", width, height);
+ (*tiles_p) = allocate_tiles(width, height, bpp, num_rows, num_cols);
+ tiles = (*tiles_p);
+
+ image->cp += xcf_read_int32(image->file, &offset, 1);
+ if (offset == 0) return 1;
+
+ ntiles = (*num_rows) * (*num_cols);
+ for (i = 0; i < ntiles; i++)
+ {
+ current_tile = &(tiles[i]);
+ fail = 0;
+
+ if (offset == 0)
+ {
+ D("Not enough tiles found in level\n");
+ return 0;
+ }
+
+ /* save the current position as it is where the
+ * next tile offset is stored.
+ */
+ saved_pos = image->cp;
+
+ /* read in the offset of the next tile so we can calculate the amount
+ of data needed for this tile*/
+ image->cp += xcf_read_int32(image->file, &offset2, 1);
+
+ /* if the offset is 0 then we need to read in the maximum possible
+ allowing for negative compression */
+ if (offset2 == 0)
+ offset2 = offset + (TILE_WIDTH * TILE_WIDTH * 4 * 1.5);
+ /* 1.5 is probably more than we need to allow */
+
+ /* seek to the tile offset */
+ xcf_seek_pos(offset);
+
+ /* read in the current_tile */
+ switch (image->compression)
+ {
+ case COMPRESS_NONE:
+ if (!xcf_load_tile(current_tile)) fail = 1;
+ break;
+ case COMPRESS_RLE:
+ if (!xcf_load_tile_rle(current_tile, offset2 - offset)) fail = 1;
+ break;
+ case COMPRESS_ZLIB:
+ fprintf (stderr, "xcf: zlib compression unimplemented\n");
+ fail = 1;
+ break;
+ case COMPRESS_FRACTAL:
+ fprintf (stderr, "xcf: fractal compression unimplemented\n");
+ fail = 1;
+ break;
+ }
+
+ if (fail)
+ {
+ D("Couldn't load tiles.\n");
+ free_tiles(tiles, (*num_rows) * (*num_cols));
+ return 0;
+ }
+ /* restore the saved position so we'll be ready to
+ * read the next offset.
+ */
+ xcf_seek_pos(saved_pos);
+ /* read in the offset of the next tile */
+ image->cp += xcf_read_int32(image->file, &offset, 1);
+ }
+
+ if (offset != 0)
+ {
+ D("encountered garbage after reading level: %d\n", offset);
+ return 0;
+ }
+
+ D("Loaded level successfully.\n");
+ return 1;
+}
+
+static char
+xcf_load_tile(Tile *tile)
+{
+ image->cp += xcf_read_int8(image->file, tile->data,
+ tile->ewidth * tile->eheight * tile->bpp);
+ return 1;
+}
+
+static char
+xcf_load_tile_rle(Tile *tile,
+ int data_length)
+{
+ DATA8 *data;
+ DATA8 val;
+ int size;
+ int count;
+ int length;
+ int bpp;
+ int i, j;
+ int nmemb_read_successfully;
+ DATA8 *xcfdata, *xcfodata, *xcfdatalimit;
+
+ data = tile->data;
+ bpp = tile->bpp;
+
+ /*printf ("Reading encrypted tile %ix%ix%i, data_length %i\n", tile->ewidth, tile->eheight, tile->bpp, data_length);*/
+
+ xcfdata = xcfodata = malloc(sizeof(DATA8) * data_length);
+ if (!xcfdata) return 0;
+
+ /* we have to use fread instead of xcf_read_* because we may be
+ reading past the end of the file here */
+ nmemb_read_successfully = f_read(image->file, xcfdata, data_length);
+ image->cp += nmemb_read_successfully;
+
+ xcfdatalimit = &xcfodata[nmemb_read_successfully - 1];
+
+ for (i = 0; i < bpp; i++)
+ {
+ data = (tile->data) + i;
+ size = tile->ewidth * tile->eheight;
+ count = 0;
+
+ while (size > 0)
+ {
+ if (xcfdata > xcfdatalimit) goto bogus_rle;
+
+ val = *xcfdata++;
+
+ length = val;
+ if (length >= 128)
+ {
+ length = 255 - (length - 1);
+ if (length == 128)
+ {
+ if (xcfdata >= xcfdatalimit) goto bogus_rle;
+
+ length = (*xcfdata << 8) + xcfdata[1];
+ xcfdata += 2;
+ }
+
+ count += length;
+ size -= length;
+
+ if (size < 0) goto bogus_rle;
+ if (&xcfdata[length-1] > xcfdatalimit) goto bogus_rle;
+
+ while (length-- > 0)
+ {
+ *data = *xcfdata++;
+ data += bpp;
+ }
+ }
+ else
+ {
+ length += 1;
+ if (length == 128)
+ {
+ if (xcfdata >= xcfdatalimit) goto bogus_rle;
+
+ length = (*xcfdata << 8) + xcfdata[1];
+ xcfdata += 2;
+ }
+
+ count += length;
+ size -= length;
+
+ if (size < 0) goto bogus_rle;
+ if (xcfdata > xcfdatalimit) goto bogus_rle;
+
+ val = *xcfdata++;
+
+ for (j = 0; j < length; j++)
+ {
+ *data = val;
+ data += bpp;
+ }
+ }
+ }
+ }
+ FREE(xcfodata);
+ return 1;
+
+bogus_rle:
+ fprintf(stderr, "WHOOOOOP -- bogus rle? Highly unlikely, blame cK for this one :) \n");
+ if (xcfodata) FREE(xcfodata);
+ return 0;
+}
+
+static Layer *
+new_layer(int width, int height, GimpImageType type, int opacity, LayerModeEffects mode)
+{
+ Layer *layer;
+
+ layer = calloc(1, sizeof(Layer));
+ if (!layer)
+ {
+ D("Couldn't allocate layer.\n");
+ return NULL;
+ }
+
+ layer->width = width;
+ layer->height = height;
+ layer->type = type;
+ layer->opacity = opacity;
+ layer->mode = mode;
+ layer->tiles = NULL;
+ layer->next = NULL;
+ layer->mask = NULL;
+ return layer;
+}
+
+static void
+free_layer(Layer *layer)
+{
+ if (layer)
+ {
+ if (layer->tiles)
+ free_tiles(layer->tiles, layer->num_rows * layer->num_cols);
+ if (layer->mask) free_layer(layer->mask);
+ if (layer->data) FREE(layer->data);
+ FREE(layer);
+ }
+}
+
+static Tile *
+allocate_tiles(int width, int height, int bpp, int* num_rows, int* num_cols)
+{
+ Tile* tiles;
+ int i, j, k, right_tile, bottom_tile;
+ int tile_width, tile_height;
+
+ (*num_rows) = (height + TILE_HEIGHT - 1) / TILE_HEIGHT;
+ (*num_cols) = (width + TILE_WIDTH - 1) / TILE_WIDTH;
+
+ tiles = malloc(sizeof(Tile) * (*num_rows) * (*num_cols));
+ if (!tiles)
+ {
+ D("Couldn't allocate tiles.\n");
+ return NULL;
+ }
+
+ right_tile = width - (((*num_cols) - 1) * TILE_WIDTH);
+ bottom_tile = height - (((*num_rows) - 1) * TILE_HEIGHT);
+
+ for (i = 0, k = 0; i < (*num_rows); i++)
+ {
+ for (j = 0; j < (*num_cols); j++, k++)
+ {
+ tile_width = ((j == (*num_cols) - 1) ? right_tile : TILE_WIDTH);
+ tile_height = ((i == (*num_rows) - 1) ? bottom_tile : TILE_HEIGHT);
+ init_tile(&(tiles[k]), tile_width, tile_height, bpp);
+ }
+ }
+ D("Allocated %ix%i tiles.\n", (*num_cols), (*num_rows));
+ return tiles;
+}
+
+static void
+init_tile(Tile *tile, int width, int height, int bpp)
+{
+ if (tile)
+ {
+ tile->bpp = bpp;
+ tile->ewidth = width;
+ tile->eheight = height;
+ tile->data = malloc(sizeof(DATA8) * width * height * bpp);
+ if (!tile->data)
+ {
+ D("Couldn't allocate tile.\n");
+ }
+ }
+}
+
+static void
+free_tiles(Tile *tiles, int num_tiles)
+{
+ int i;
+
+ for (i = 0; i < num_tiles; i++)
+ {
+ if (tiles[i].data) FREE(tiles[i].data);
+ }
+ FREE(tiles);
+}
+
+static void
+add_layer_to_image(Layer *layer)
+{
+ if (layer)
+ {
+ if (image->last_layer)
+ {
+ image->last_layer->next = layer;
+ layer->prev = image->last_layer;
+ }
+ else
+ {
+ image->layers = layer;
+ layer->prev = NULL;
+ }
+ layer->next = NULL;
+ image->last_layer = layer;
+ }
+}
+
+static void
+set_layer_opacity(Layer *layer)
+{
+ int i;
+ DATA8* ptr;
+
+ if (layer)
+ {
+ if (layer->opacity != 255)
+ {
+ for (i = 0, ptr = layer->data; i < layer->width * layer->height; i++, ptr += 4)
+ {
+ *(ptr + 3) = (*(ptr + 3) * layer->opacity) >> 8;
+ }
+ }
+ }
+}
+
+static void
+apply_layer_mask(Layer *layer)
+{
+ DATA8* ptr1;
+ DATA8* ptr2;
+ int i, tmp;
+
+ D("Applying layer mask.\n");
+ if (layer)
+ {
+ if (layer->mask)
+ {
+ ptr1 = layer->data;
+ ptr2 = layer->mask->data;
+ for (i = 0; i < layer->width * layer->height; i++)
+ {
+ tmp = (*(ptr1 + 3) * *(ptr2)) / 256;
+ if (tmp > 255) tmp = 255;
+ *(ptr1 + 3) = (DATA8)tmp;
+ ptr1 += 4;
+ ptr2 += 4;
+ }
+ }
+ }
+}
+
+static void
+flatten_image(void)
+{
+ Layer* l = image->last_layer;
+ Layer* lp;
+ int layer_index;
+
+ shm_alloc(image->width * image->height * sizeof(DATA32));
+ if (!shm_addr) return;
+ image->data = shm_addr;
+ memset(image->data, 0, image->width * image->height * sizeof(DATA32));
+
+ layer_index = 0;
+
+ while (l)
+ {
+ /* Ok, paste each layer on top of the image, using the mode's merging type.
+ We're moving upward through the layer stack.
+ --cK.
+ */
+ if ((image->single_layer_index < 0) ||
+ (layer_index == image->single_layer_index))
+ {
+ // FIXME: not all modes are implemented right
+ // xcf's may not render right :)
+ switch (l->mode)
+ {
+ case MULTIPLY_MODE:
+ D("MULTIPLY\n");
+ combine_pixels_mult(l->data, l->width, l->height,
+ image->data, image->width, image->height,
+ l->offset_x, l->offset_y);
+ break;
+ case DIVIDE_MODE:
+ D("DIVIDE\n");
+ combine_pixels_div(l->data, l->width, l->height,
+ image->data, image->width, image->height,
+ l->offset_x, l->offset_y);
+ break;
+ case SCREEN_MODE:
+ D("SCREEN\n");
+ combine_pixels_screen(l->data, l->width, l->height,
+ image->data, image->width, image->height,
+ l->offset_x, l->offset_y);
+ break;
+ case OVERLAY_MODE:
+ D("OVERLAY\n");
+ combine_pixels_overlay(l->data, l->width, l->height,
+ image->data, image->width, image->height,
+ l->offset_x, l->offset_y);
+ break;
+ case DIFFERENCE_MODE:
+ D("DIFF\n");
+ combine_pixels_diff(l->data, l->width, l->height,
+ image->data, image->width, image->height,
+ l->offset_x, l->offset_y);
+ break;
+ case ADDITION_MODE:
+ D("ADD\n");
+ combine_pixels_add(l->data, l->width, l->height,
+ image->data, image->width, image->height,
+ l->offset_x, l->offset_y);
+ break;
+ case SUBTRACT_MODE:
+ D("SUB\n");
+ combine_pixels_sub(l->data, l->width, l->height,
+ image->data, image->width, image->height,
+ l->offset_x, l->offset_y);
+ break;
+ case DARKEN_ONLY_MODE:
+ D("DARKEN\n");
+ combine_pixels_darken(l->data, l->width, l->height,
+ image->data, image->width, image->height,
+ l->offset_x, l->offset_y);
+ break;
+ case LIGHTEN_ONLY_MODE:
+ D("LIGHTEN\n");
+ combine_pixels_lighten(l->data, l->width, l->height,
+ image->data, image->width, image->height,
+ l->offset_x, l->offset_y);
+ break;
+ case HUE_MODE:
+ D("HUE\n");
+ combine_pixels_hue(l->data, l->width, l->height,
+ image->data, image->width, image->height,
+ l->offset_x, l->offset_y);
+ break;
+ case SATURATION_MODE:
+ D("SATURATION\n");
+ combine_pixels_sat(l->data, l->width, l->height,
+ image->data, image->width, image->height,
+ l->offset_x, l->offset_y);
+ break;
+ case VALUE_MODE:
+ D("VALUE\n");
+ combine_pixels_val(l->data, l->width, l->height,
+ image->data, image->width, image->height,
+ l->offset_x, l->offset_y);
+ break;
+ case COLOR_MODE:
+ D("COLOR\n");
+ combine_pixels_col(l->data, l->width, l->height,
+ image->data, image->width, image->height,
+ l->offset_x, l->offset_y);
+ break;
+ case DISSOLVE_MODE:
+ D("DISSOLVE\n");
+ combine_pixels_diss(l->data, l->width, l->height,
+ image->data, image->width, image->height,
+ l->offset_x, l->offset_y);
+ break;
+ /* None of the following is actually valid for layer blending, fall through: */
+ case BEHIND_MODE:
+ case REPLACE_MODE:
+ case ERASE_MODE:
+ case ANTI_ERASE_MODE:
+ D("EEEEEK -- this mode shouldn't be here\n");
+ /* Fall through */
+
+ case NORMAL_MODE:
+ D("NORMAL\n");
+ combine_pixels_normal(l->data, l->width, l->height,
+ image->data, image->width, image->height,
+ l->offset_x, l->offset_y);
+ break;
+
+ default:
+ D("Unknown layer mode: %i. Skipping.\n", l->mode);
+ }
+ }
+
+ lp = l->prev;
+ /* free the layer now, since it's not needed anymore */
+ free_layer(l);
+
+ l = lp;
+ layer_index++;
+ }
+
+ /* We've used up all the layers now, so set them to NULL in the image: */
+ image->layers = NULL;
+ image->last_layer = NULL;
+}
+
+static char
+xcf_file_init(char *filename)
+{
+ char success = 1;
+ char id[14];
+ int width;
+ int height;
+ int image_type;
+
+ image->single_layer_index = -1;
+ image->file = f_open(filename);
+ D("image->file = %p\n", image->file);
+ if (!image->file) return 0;
+
+ image->filename = filename;
+ image->layers = NULL;
+ image->last_layer = NULL;
+ image->cmap = NULL;
+ image->num_cols = 0;
+ image->data = NULL;
+
+ image->cp = 0;
+
+ image->cp += xcf_read_int8(image->file, (DATA8 *)id, 14);
+ if (strncmp(id, "gimp xcf ", 9))
+ {
+ success = 0;
+ f_close(image->file);
+ }
+ else if (!strcmp(id + 9, "file"))
+ {
+ image->file_version = 0;
+ }
+ else if (id[9] == 'v')
+ {
+ image->file_version = atoi(id + 10);
+ }
+ else
+ {
+ success = 0;
+ f_close(image->file);
+ }
+
+ if (success)
+ {
+ image->cp += xcf_read_int32(image->file, (DATA32 *)&width, 1);
+ image->cp += xcf_read_int32(image->file, (DATA32 *)&height, 1);
+ image->cp += xcf_read_int32(image->file, (DATA32 *)&image_type, 1);
+
+ image->width = width;
+ image->height = height;
+ image->base_type = image_type;
+
+ D("Loading %ix%i image.\n", width, height);
+ }
+
+ return success;
+}
+
+static void
+xcf_cleanup(void)
+{
+ Layer *l, *lp;
+
+ if (image->file) f_close(image->file);
+ for (l = image->last_layer; l; l = lp)
+ {
+ lp = l->prev;
+ free_layer(l);
+ }
+ if (image->cmap) FREE(image->cmap);
+}
+
+static void
+premul_image(void)
+{
+ DATA32 *p, *end;
+
+ end = (DATA32 *)image->data + (image->width * image->height);
+ for (p = (DATA32 *)image->data; p < end; p++)
+ {
+ unsigned int r, g, b, a;
+
+ a = A_VAL(p);
+ r = (R_VAL(p) * a) / 255;
+ R_VAL(p) = r;
+ g = (G_VAL(p) * a) / 255;
+ G_VAL(p) = g;
+ b = (B_VAL(p) * a) / 255;
+ B_VAL(p) = b;
+ }
+}
+
+int
+main(int argc, char **argv)
+{
+ char *file;
+ int w, h, i;
+ int head_only = 0;
+
+ if (argc < 2) return -1;
+ // file is ALWAYS first arg, other options come after
+ file = argv[1];
+ for (i = 2; i < argc; i++)
+ {
+ if (!strcmp(argv[i], "-head"))
+ // asked to only load header, not body/data
+ head_only = 1;
+ else if (!strcmp(argv[i], "-key"))
+ { // not used by xcf loader
+ i++;
+ // const char *key = argv[i];
+ }
+ else if (!strcmp(argv[i], "-opt-scale-down-by"))
+ { // not used by xcf loader
+ i++;
+ // int scale_down = atoi(argv[i]);
+ }
+ else if (!strcmp(argv[i], "-opt-dpi"))
+ { // not used by xcf loader
+ i++;
+ // double dpi = ((double)atoi(argv[i])) / 1000.0;
+ }
+ else if (!strcmp(argv[i], "-opt-size"))
+ { // not used by xcf loader
+ i++;
+ // int size_w = atoi(argv[i]);
+ i++;
+ // int size_h = atoi(argv[i]);
+ }
+ }
+
+ timeout_init(8);
+
+ D("xcf_file_init\n");
+ if (!xcf_file_init(file)) return -1;
+
+ D("size %i %i\n", image->width, image->height);
+ if (!head_only)
+ {
+ xcf_load_image();
+ premul_image();
+ }
+ w = image->width;
+ h = image->height;
+ printf("size %i %i\n", w, h);
+ printf("alpha 1\n");
+ if (!head_only)
+ {
+ if (shm_fd >= 0) printf("shmfile %s\n", shmfile);
+ else
+ {
+ // could also to "tmpfile %s\n" like shmfile but just
+ // a mmaped tmp file on the system
+ printf("data\n");
+ fwrite(image->data, w * h * sizeof(DATA32), 1, stdout);
+ }
+ shm_free();
+ }
+ else
+ printf("done\n");
+ xcf_cleanup();
+ fflush(stdout);
+ return 0;
+}
diff --git a/src/generic/evas/xcf/pixelfuncs.c b/src/generic/evas/xcf/pixelfuncs.c
new file mode 100644
index 0000000000..67d66d8129
--- /dev/null
+++ b/src/generic/evas/xcf/pixelfuncs.c
@@ -0,0 +1,759 @@
+/*
+
+ -----------------------------[ XCF Loader ]-----------------------------
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+#include "common.h"
+
+#define RS R_VAL(src + s_idx)
+#define GS G_VAL(src + s_idx)
+#define BS B_VAL(src + s_idx)
+#define AS A_VAL(src + s_idx)
+#define RD R_VAL(dest + d_idx)
+#define GD G_VAL(dest + d_idx)
+#define BD B_VAL(dest + d_idx)
+#define AD A_VAL(dest + d_idx)
+
+#define EPS 0.00001
+#define PI 3.141592654
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#define INT_MULT(a,b,t) ((t) = (a) * (b) + 0x80, ((((t) >> 8) + (t)) >> 8))
+#define LINEAR(x,y,w) ((w*y + x)*4)
+
+static void
+rgb_to_hls (DATA8 *red, DATA8 *green, DATA8 *blue)
+{
+ int r, g, b;
+ double h, l, s;
+ int min, max;
+ int delta;
+
+ r = *red;
+ g = *green;
+ b = *blue;
+
+ if (r > g)
+ {
+ max = MAX (r, b);
+ min = MIN (g, b);
+ }
+ else
+ {
+ max = MAX (g, b);
+ min = MIN (r, b);
+ }
+
+ l = (max + min) / 2.0;
+
+ if (max == min)
+ {
+ s = 0.0;
+ h = 0.0;
+ }
+ else
+ {
+ delta = (max - min);
+
+ if (l < 128)
+ s = 255 * (double) delta / (double) (max + min);
+ else
+ s = 255 * (double) delta / (double) (511 - max - min);
+
+ if (r == max)
+ h = (g - b) / (double) delta;
+ else if (g == max)
+ h = 2 + (b - r) / (double) delta;
+ else
+ h = 4 + (r - g) / (double) delta;
+
+ h = h * 42.5;
+
+ if (h < 0)
+ h += 255;
+ else if (h > 255)
+ h -= 255;
+ }
+
+ *red = h;
+ *green = l;
+ *blue = s;
+}
+
+
+static DATA8
+gimp_hls_value (double n1, double n2, double hue)
+{
+ double value;
+
+ if (hue > 255)
+ hue -= 255;
+ else if (hue < 0)
+ hue += 255;
+ if (hue < 42.5)
+ value = n1 + (n2 - n1) * (hue / 42.5);
+ else if (hue < 127.5)
+ value = n2;
+ else if (hue < 170)
+ value = n1 + (n2 - n1) * ((170 - hue) / 42.5);
+ else
+ value = n1;
+
+ return (DATA8) (value * 255);
+}
+
+
+static void
+hls_to_rgb (DATA8 *hue, DATA8 *lightness, DATA8 *saturation)
+{
+ double h, l, s;
+ double m1, m2;
+
+ h = *hue;
+ l = *lightness;
+ s = *saturation;
+
+ if (s == 0)
+ {
+ /* achromatic case */
+ *hue = l;
+ *lightness = l;
+ *saturation = l;
+ }
+ else
+ {
+ if (l < 128)
+ m2 = (l * (255 + s)) / 65025.0;
+ else
+ m2 = (l + s - (l * s) / 255.0) / 255.0;
+
+ m1 = (l / 127.5) - m2;
+
+ /* chromatic case */
+ *hue = gimp_hls_value (m1, m2, h + 85);
+ *lightness = gimp_hls_value (m1, m2, h);
+ *saturation = gimp_hls_value (m1, m2, h - 85);
+ }
+}
+
+
+static void
+rgb_to_hsv (DATA8 *red, DATA8 *green, DATA8 *blue)
+{
+ int r, g, b;
+ double h, s, v;
+ int min, max;
+ int delta;
+
+ h = 0.0;
+
+ r = *red;
+ g = *green;
+ b = *blue;
+
+ if (r > g)
+ {
+ max = MAX (r, b);
+ min = MIN (g, b);
+ }
+ else
+ {
+ max = MAX (g, b);
+ min = MIN (r, b);
+ }
+
+ v = max;
+
+ if (max != 0)
+ s = ((max - min) * 255) / (double) max;
+ else
+ s = 0;
+
+ if (s == 0)
+ h = 0;
+ else
+ {
+ delta = max - min;
+ if (r == max)
+ h = (g - b) / (double) delta;
+ else if (g == max)
+ h = 2 + (b - r) / (double) delta;
+ else if (b == max)
+ h = 4 + (r - g) / (double) delta;
+ h *= 42.5;
+
+ if (h < 0)
+ h += 255;
+ if (h > 255)
+ h -= 255;
+ }
+
+ *red = h;
+ *green = s;
+ *blue = v;
+}
+
+static void
+hsv_to_rgb (DATA8 *hue, DATA8 *saturation, DATA8 *value)
+{
+ double h, s, v;
+ double f, p, q, t;
+
+ if (*saturation == 0)
+ {
+ *hue = *value;
+ *saturation = *value;
+ /* *value = *value; */
+ }
+ else
+ {
+ h = *hue * 6.0 / 255.0;
+ s = *saturation / 255.0;
+ v = *value / 255.0;
+
+ f = h - (int) h;
+ p = v * (1.0 - s);
+ q = v * (1.0 - (s * f));
+ t = v * (1.0 - (s * (1.0 - f)));
+
+ switch ((int) h)
+ {
+ case 0:
+ *hue = v * 255;
+ *saturation = t * 255;
+ *value = p * 255;
+ break;
+
+ case 1:
+ *hue = q * 255;
+ *saturation = v * 255;
+ *value = p * 255;
+ break;
+
+ case 2:
+ *hue = p * 255;
+ *saturation = v * 255;
+ *value = t * 255;
+ break;
+
+ case 3:
+ *hue = p * 255;
+ *saturation = q * 255;
+ *value = v * 255;
+ break;
+
+ case 4:
+ *hue = t * 255;
+ *saturation = p * 255;
+ *value = v * 255;
+ break;
+
+ case 5:
+ *hue = v * 255;
+ *saturation = p * 255;
+ *value = q * 255;
+ break;
+ }
+ }
+}
+
+/* translate negative destinations */
+static
+void _clip(int * src_tl_x, int * src_tl_y,
+ int * src_br_x, int * src_br_y,
+ int * dest_x, int * dest_y,
+ int dest_w, int dest_h)
+{
+ if (*dest_x + *src_br_x >= dest_w)
+ { *src_br_x -= (*dest_x + *src_br_x) - dest_w; }
+
+ if (*dest_y + *src_br_y >= dest_h)
+ { *src_br_y -= (*dest_y + *src_br_y) - dest_h; }
+
+ if (*dest_x < 0)
+ {
+ *src_tl_x = -(*dest_x);
+ *dest_x = 0;
+ }
+ if (*dest_y < 0)
+ {
+ *src_tl_y = -(*dest_y);
+ *dest_y = 0;
+ }
+}
+
+// FIXME: make sure layer alpha is used/applied in all cases
+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)
+{
+ int x, y, s_idx, d_idx;
+ int src_tl_x = 0, src_tl_y = 0;
+ int src_br_x = src_w, src_br_y = src_h;
+
+ int b;
+ unsigned char src_alpha;
+ unsigned char new_alpha;
+ float ratio, compl_ratio;
+ unsigned long tmp;
+
+ _clip(&src_tl_x, &src_tl_y, &src_br_x, &src_br_y, &dest_x, &dest_y, dest_w, dest_h);
+
+ for (y = src_tl_y; y < src_br_y; y++)
+ for (x = src_tl_x; x < src_br_x; x++)
+ {
+ d_idx = LINEAR((dest_x + x - src_tl_x), (dest_y + y - src_tl_y), dest_w);
+ s_idx = LINEAR(x, y, src_w);
+
+ src_alpha = AS;
+
+ if (src_alpha != 0)
+ {
+ if (src_alpha == 255)
+ new_alpha = src_alpha;
+ else
+ new_alpha = AD + INT_MULT((255u - AD), src_alpha, tmp);
+
+ b = 3;
+ if (new_alpha != 0)
+ {
+ ratio = (float) src_alpha / new_alpha;
+ compl_ratio = 1.0 - ratio;
+
+ do
+ {
+ b--;
+ dest[d_idx + b] =
+ (unsigned char) (src[s_idx + b] * ratio + dest[d_idx + b] * compl_ratio + EPS);
+ }
+ while (b);
+ }
+
+ AD = new_alpha;
+ }
+ }
+}
+
+
+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)
+{
+ int x, y, s_idx, d_idx;
+ int src_tl_x = 0, src_tl_y = 0;
+ int src_br_x = src_w, src_br_y = src_h;
+ int tmp, tmp2;
+
+ _clip(&src_tl_x, &src_tl_y, &src_br_x, &src_br_y, &dest_x, &dest_y, dest_w, dest_h);
+
+ for (y = src_tl_y; y < src_br_y; y++)
+ for (x = src_tl_x; x < src_br_x; x++)
+ {
+ d_idx = LINEAR((dest_x + x - src_tl_x), (dest_y + y - src_tl_y), dest_w);
+ s_idx = LINEAR(x, y, src_w);
+
+ tmp2 = INT_MULT(AS, RS, tmp);
+ tmp = RD + tmp2;
+ RD = (tmp > 255 ? 255 : tmp);
+
+ tmp2 = INT_MULT(AS, GS, tmp);
+ tmp = GD + tmp2;
+ GD = (tmp > 255 ? 255 : tmp);
+
+ tmp2 = INT_MULT(AS, BS, tmp);
+ tmp = BD + tmp2;
+ BD = (tmp > 255 ? 255 : tmp);
+
+// AD = MIN(AD, AS);
+ }
+}
+
+
+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)
+{
+ int x, y, s_idx, d_idx;
+ int src_tl_x = 0, src_tl_y = 0;
+ int src_br_x = src_w, src_br_y = src_h;
+ int tmp, tmp2;
+
+ _clip(&src_tl_x, &src_tl_y, &src_br_x, &src_br_y, &dest_x, &dest_y, dest_w, dest_h);
+
+ for (y = src_tl_y; y < src_br_y; y++)
+ for (x = src_tl_x; x < src_br_x; x++)
+ {
+ d_idx = LINEAR((dest_x + x - src_tl_x), (dest_y + y - src_tl_y), dest_w);
+ s_idx = LINEAR(x, y, src_w);
+
+ tmp2 = INT_MULT(AS, RS, tmp);
+ tmp = RD - tmp2;
+ RD = (tmp < 0 ? 0 : tmp);
+
+ tmp2 = INT_MULT(AS, GS, tmp);
+ tmp = GD - tmp2;
+ GD = (tmp < 0 ? 0 : tmp);
+
+ tmp2 = INT_MULT(AS, BS, tmp);
+ tmp = BD - tmp2;
+ BD = (tmp < 0 ? 0 : tmp);
+
+// AD = MIN(AD, AS);
+ }
+}
+
+
+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)
+{
+ int x, y, s_idx, d_idx;
+ int src_tl_x = 0, src_tl_y = 0;
+ int src_br_x = src_w, src_br_y = src_h;
+ int tmp, tmp2;
+
+ _clip(&src_tl_x, &src_tl_y, &src_br_x, &src_br_y, &dest_x, &dest_y, dest_w, dest_h);
+
+ for (y = src_tl_y; y < src_br_y; y++)
+ for (x = src_tl_x; x < src_br_x; x++)
+ {
+ d_idx = LINEAR((dest_x + x - src_tl_x), (dest_y + y - src_tl_y), dest_w);
+ s_idx = LINEAR(x, y, src_w);
+
+ tmp2 = INT_MULT(AS, RS, tmp);
+ tmp = RD - tmp2;
+ RD = (tmp < 0 ? -tmp : tmp);
+
+ tmp2 = INT_MULT(AS, GS, tmp);
+ tmp = GD - tmp2;
+ GD = (tmp < 0 ? -tmp : tmp);
+
+ tmp2 = INT_MULT(AS, BS, tmp);
+ tmp = BD - tmp2;
+ BD = (tmp < 0 ? -tmp : tmp);
+
+// AD = MIN(AD, AS);
+ }
+}
+
+
+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)
+{
+ int x, y, s_idx, d_idx;
+ int src_tl_x = 0, src_tl_y = 0;
+ int src_br_x = src_w, src_br_y = src_h;
+
+ _clip(&src_tl_x, &src_tl_y, &src_br_x, &src_br_y, &dest_x, &dest_y, dest_w, dest_h);
+
+ for (y = src_tl_y; y < src_br_y; y++)
+ for (x = src_tl_x; x < src_br_x; x++)
+ {
+ d_idx = LINEAR((dest_x + x - src_tl_x), (dest_y + y - src_tl_y), dest_w);
+ s_idx = LINEAR(x, y, src_w);
+
+ RD = MIN(RD, RS);
+ GD = MIN(GD, GS);
+ BD = MIN(BD, BS);
+
+// AD = MIN(AD, AS);
+ }
+}
+
+
+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)
+{
+ int x, y, s_idx, d_idx;
+ int src_tl_x = 0, src_tl_y = 0;
+ int src_br_x = src_w, src_br_y = src_h;
+
+ _clip(&src_tl_x, &src_tl_y, &src_br_x, &src_br_y, &dest_x, &dest_y, dest_w, dest_h);
+
+ for (y = src_tl_y; y < src_br_y; y++)
+ for (x = src_tl_x; x < src_br_x; x++)
+ {
+ d_idx = LINEAR((dest_x + x - src_tl_x), (dest_y + y - src_tl_y), dest_w);
+ s_idx = LINEAR(x, y, src_w);
+
+ RD = MAX(RD, RS);
+ GD = MAX(GD, GS);
+ BD = MAX(BD, BS);
+
+// AD = MIN(AD, AS);
+ }
+}
+
+
+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)
+{
+ int x, y, s_idx, d_idx;
+ int src_tl_x = 0, src_tl_y = 0;
+ int src_br_x = src_w, src_br_y = src_h;
+ int tmp, tmp2, tmp3;
+
+ _clip(&src_tl_x, &src_tl_y, &src_br_x, &src_br_y, &dest_x, &dest_y, dest_w, dest_h);
+
+ for (y = src_tl_y; y < src_br_y; y++)
+ for (x = src_tl_x; x < src_br_x; x++)
+ {
+ d_idx = LINEAR((dest_x + x - src_tl_x), (dest_y + y - src_tl_y), dest_w);
+ s_idx = LINEAR(x, y, src_w);
+
+ tmp2 = INT_MULT(RS, AS, tmp);
+ tmp2 = INT_MULT(RD, tmp2, tmp);
+ tmp3 = INT_MULT(RD, (255 - AS), tmp);
+ RD = (tmp2 + tmp3);
+
+ tmp2 = INT_MULT(GS, AS, tmp);
+ tmp2 = INT_MULT(GD, tmp2, tmp);
+ tmp3 = INT_MULT(GD, (255 - AS), tmp);
+ GD = (tmp2 + tmp3);
+
+ tmp2 = INT_MULT(BS, AS, tmp);
+ tmp2 = INT_MULT(BD, tmp2, tmp);
+ tmp3 = INT_MULT(BD, (255 - AS), tmp);
+ BD = (tmp2 + tmp3);
+
+// AS = MIN(AS, AD);
+ }
+
+// combine_pixels_normal(src, src_w, src_h, dest, dest_w, dest_h, dest_x, dest_y);
+}
+
+
+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)
+{
+ int x, y, s_idx, d_idx;
+ int src_tl_x = 0, src_tl_y = 0;
+ int src_br_x = src_w, src_br_y = src_h;
+
+ _clip(&src_tl_x, &src_tl_y, &src_br_x, &src_br_y, &dest_x, &dest_y, dest_w, dest_h);
+
+ for (y = src_tl_y; y < src_br_y; y++)
+ for (x = src_tl_x; x < src_br_x; x++)
+ {
+ d_idx = LINEAR((dest_x + x - src_tl_x), (dest_y + y - src_tl_y), dest_w);
+ s_idx = LINEAR(x, y, src_w);
+
+ RS = MIN(255, ((float)RD / (RS + 1)) * 256);
+ GS = MIN(255, ((float)GD / (GS + 1)) * 256);
+ BS = MIN(255, ((float)BD / (BS + 1)) * 256);
+
+// AS = MIN(AD, AS);
+ }
+
+ combine_pixels_normal(src, src_w, src_h, dest, dest_w, dest_h, dest_x, dest_y);
+}
+
+
+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)
+{
+ int x, y, s_idx, d_idx;
+ int src_tl_x = 0, src_tl_y = 0;
+ int src_br_x = src_w, src_br_y = src_h;
+
+ _clip(&src_tl_x, &src_tl_y, &src_br_x, &src_br_y, &dest_x, &dest_y, dest_w, dest_h);
+
+ for (y = src_tl_y; y < src_br_y; y++)
+ for (x = src_tl_x; x < src_br_x; x++)
+ {
+ d_idx = LINEAR((dest_x + x - src_tl_x), (dest_y + y - src_tl_y), dest_w);
+ s_idx = LINEAR(x, y, src_w);
+
+ RD = 255 - (((255 - RD) * (255 - RS)) >> 8);
+ GD = 255 - (((255 - GD) * (255 - GS)) >> 8);
+ BD = 255 - (((255 - BD) * (255 - BS)) >> 8);
+
+// AD = MIN(AD, AS);
+ }
+}
+
+
+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)
+{
+ int x, y, s_idx, d_idx;
+ int src_tl_x = 0, src_tl_y = 0;
+ int src_br_x = src_w, src_br_y = src_h;
+ int tmp_screen, tmp_mult;
+
+ _clip(&src_tl_x, &src_tl_y, &src_br_x, &src_br_y, &dest_x, &dest_y, dest_w, dest_h);
+
+ for (y = src_tl_y; y < src_br_y; y++)
+ for (x = src_tl_x; x < src_br_x; x++)
+ {
+ d_idx = LINEAR((dest_x + x - src_tl_x), (dest_y + y - src_tl_y), dest_w);
+ s_idx = LINEAR(x, y, src_w);
+
+ tmp_screen = 255 - (((255 - RD) * (255 - RS)) >> 8);
+ tmp_mult = (RD * RS) >> 8;
+ RD = (RD * tmp_screen + (255 - RD) * tmp_mult) >> 8;
+
+ tmp_screen = 255 - (((255 - GD) * (255 - GS)) >> 8);
+ tmp_mult = (GD * GS) >> 8;
+ GD = (GD * tmp_screen + (255 - GD) * tmp_mult) >> 8;
+
+ tmp_screen = 255 - (((255 - BD) * (255 - BS)) >> 8);
+ tmp_mult = (BD * BS) >> 8;
+ BD = (BD * tmp_screen + (255 - BD) * tmp_mult) >> 8;
+
+// AD = MIN(AD, AS);
+ }
+}
+
+
+static void
+combine_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)
+{
+ int x, y, s_idx, d_idx;
+ int src_tl_x = 0, src_tl_y = 0;
+ int src_br_x = src_w, src_br_y = src_h;
+
+ _clip(&src_tl_x, &src_tl_y, &src_br_x, &src_br_y, &dest_x, &dest_y, dest_w, dest_h);
+
+ for (y = src_tl_y; y < src_br_y; y++)
+ for (x = src_tl_x; x < src_br_x; x++)
+ {
+ d_idx = LINEAR((dest_x + x - src_tl_x), (dest_y + y - src_tl_y), dest_w);
+ s_idx = LINEAR(x, y, src_w);
+
+ rgb_to_hsv(&RS, &GS, &BS);
+ rgb_to_hsv(&RD, &GD, &BD);
+
+ switch (mode)
+ {
+ case 0: /* hue mode */
+ RD = RS;
+ break;
+ case 1: /* saturation mode */
+ GD = GS;
+ break;
+ case 2: /* value mode */
+ BD = BS;
+ break;
+ default:
+ break;
+ }
+
+ hsv_to_rgb(&RD, &GD, &BD);
+// AD = MIN(AD, AS);
+ }
+}
+
+
+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)
+{
+ combine_pixels_hsv(src, src_w, src_h, dest, dest_w, dest_h, dest_x, dest_y, 0);
+}
+
+
+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)
+{
+ combine_pixels_hsv(src, src_w, src_h, dest, dest_w, dest_h, dest_x, dest_y, 1);
+}
+
+
+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)
+{
+ combine_pixels_hsv(src, src_w, src_h, dest, dest_w, dest_h, dest_x, dest_y, 2);
+}
+
+
+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)
+{
+ int x, y, s_idx, d_idx;
+ int src_tl_x = 0, src_tl_y = 0;
+ int src_br_x = src_w, src_br_y = src_h;
+
+ _clip(&src_tl_x, &src_tl_y, &src_br_x, &src_br_y, &dest_x, &dest_y, dest_w, dest_h);
+
+ for (y = src_tl_y; y < src_br_y; y++)
+ for (x = src_tl_x; x < src_br_x; x++)
+ {
+ d_idx = LINEAR((dest_x + x - src_tl_x), (dest_y + y - src_tl_y), dest_w);
+ s_idx = LINEAR(x, y, src_w);
+
+ rgb_to_hls(&RS, &GS, &BS);
+ rgb_to_hls(&RD, &GD, &BD);
+ RD = RS;
+ BD = BS;
+ hls_to_rgb(&RD, &GD, &BD);
+
+// AD = MIN(AD, AS);
+ }
+}
+
+
+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)
+{
+ int x, y, s_idx, d_idx;
+ int src_tl_x = 0, src_tl_y = 0;
+ int src_br_x = src_w, src_br_y = src_h;
+
+ srand(12345);
+
+ _clip(&src_tl_x, &src_tl_y, &src_br_x, &src_br_y, &dest_x, &dest_y, dest_w, dest_h);
+
+ for (y = src_tl_y; y < src_br_y; y++)
+ for (x = src_tl_x; x < src_br_x; x++)
+ {
+ d_idx = LINEAR((dest_x + x - src_tl_x), (dest_y + y - src_tl_y), dest_w);
+ s_idx = LINEAR(x, y, src_w);
+
+ if ((rand() % 255) < AS)
+ {
+ int b;
+ unsigned char src_alpha;
+ unsigned char new_alpha;
+ float ratio, compl_ratio;
+ unsigned long tmp;
+
+ src_alpha = AS;
+
+ if (src_alpha != 0)
+ {
+ if (src_alpha == 255)
+ new_alpha = src_alpha;
+ else
+ new_alpha = AD + INT_MULT((255u - AD), src_alpha, tmp);
+
+ b = 3;
+ if (new_alpha != 0)
+ {
+ ratio = (float) src_alpha / new_alpha;
+ compl_ratio = 1.0 - ratio;
+
+ do
+ {
+ b--;
+ dest[d_idx + b] =
+ (unsigned char) (src[s_idx + b] * ratio + dest[d_idx + b] * compl_ratio + EPS);
+ }
+ while (b);
+ }
+
+ AD = new_alpha;
+ }
+ }
+ }
+}