Gfxprim
Threads by month
- ----- 2026 -----
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- 929 discussions
14 Mar '14
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project gfxprim.git.
The branch, master has been updated
via c2fb0ec9b8d440b7128d76344907b20ad292885e (commit)
via f4d0b3a334fc0d0e84c10d610e857f2f7d63af4b (commit)
via e046ca8ac123e9c4f0e619077fe9db4a81a14abe (commit)
via d2e38530ca219f78533be17c4dc3d6637279478c (commit)
from a33888669a0b42c82e7664debb6c255d33efecd2 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
http://repo.or.cz/w/gfxprim.git/commit/c2fb0ec9b8d440b7128d76344907b20ad292…
commit c2fb0ec9b8d440b7128d76344907b20ad292885e
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Fri Mar 14 00:07:12 2014 +0100
doc: Add GFXprim to specialwords.
Now all occurences of GFXprim are emphasized automatically
Signed-off-by: Cyril Hrubis <metan(a)ucw.cz>
diff --git a/doc/about.txt b/doc/about.txt
index f632eaaf..9708ccd0 100644
--- a/doc/about.txt
+++ b/doc/about.txt
@@ -1,7 +1,7 @@
General information
-------------------
-Gfxprim is simple modular 2D bitmap graphics library with emphasis on speed
+GFXprim is simple modular 2D bitmap graphics library with emphasis on speed
and correctness.
One of the key points of the library are code generators. Most of the
diff --git a/doc/asciidoc.conf b/doc/asciidoc.conf
index 4cca66ee..cd6e25b3 100644
--- a/doc/asciidoc.conf
+++ b/doc/asciidoc.conf
@@ -1,3 +1,6 @@
+[specialwords]
+emphasizedwords=GFXprim
+
[attributes]
# use image icons
icons
diff --git a/doc/index.txt b/doc/index.txt
index 48596e31..240d7b9e 100644
--- a/doc/index.txt
+++ b/doc/index.txt
@@ -1,7 +1,7 @@
GFXprim
-------
-'GFXprim' is Open-source modular 2D bitmap graphics library with emphasis on
+GFXprim is Open-source modular 2D bitmap graphics library with emphasis on
speed and correctness.
The goal of the library is to provide simple but powerful API for applications
http://repo.or.cz/w/gfxprim.git/commit/f4d0b3a334fc0d0e84c10d610e857f2f7d63…
commit f4d0b3a334fc0d0e84c10d610e857f2f7d63af4b
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Fri Mar 14 00:00:32 2014 +0100
doc: Minor css style tweak.
Signed-off-by: Cyril Hrubis <metan(a)ucw.cz>
diff --git a/doc/asciidoc.css b/doc/asciidoc.css
index 9d4173ad..09829b1f 100644
--- a/doc/asciidoc.css
+++ b/doc/asciidoc.css
@@ -31,9 +31,9 @@ a:hover {
}
em {
- font-style: normal;
- font-weight: 600;
- color: #444;
+ font-style: italic;
+ font-weight: bolder;
+ color: #223;
}
strong {
http://repo.or.cz/w/gfxprim.git/commit/e046ca8ac123e9c4f0e619077fe9db4a81a1…
commit e046ca8ac123e9c4f0e619077fe9db4a81a14abe
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Sat Mar 8 11:10:57 2014 +0100
loaders: TIFF: Fix Big Endian signature.
It's "MM0*"
Signed-off-by: Cyril Hrubis <metan(a)ucw.cz>
diff --git a/libs/loaders/GP_TIFF.c b/libs/loaders/GP_TIFF.c
index f8e56d60..65513c77 100644
--- a/libs/loaders/GP_TIFF.c
+++ b/libs/loaders/GP_TIFF.c
@@ -45,7 +45,7 @@
#include <tiffio.h>
#define TIFF_HEADER_LITTLE "IIx2a0"
-#define TIFF_HEADER_BIG "BB0x2a"
+#define TIFF_HEADER_BIG "MM0x2a"
int GP_MatchTIFF(const void *buf)
{
http://repo.or.cz/w/gfxprim.git/commit/d2e38530ca219f78533be17c4dc3d6637279…
commit d2e38530ca219f78533be17c4dc3d6637279478c
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Mon Mar 3 01:02:43 2014 +0100
loader: PSD: Propagate errors correctly.
Fix error propagation from combined image loader.
Signed-off-by: Cyril Hrubis <metan(a)ucw.cz>
diff --git a/libs/loaders/GP_PSD.c b/libs/loaders/GP_PSD.c
index f05ab316..a3e5030d 100644
--- a/libs/loaders/GP_PSD.c
+++ b/libs/loaders/GP_PSD.c
@@ -22,7 +22,7 @@
/*
- Photoshop PSD thumbnail image loader.
+ Photoshop PSD image loader.
Written using documentation available freely on the internet.
@@ -442,7 +442,7 @@ static const char *compress_method_type(uint16_t compress)
struct rle {
/* RLE State */
int8_t op;
- int size;
+ unsigned int size;
uint8_t val;
/* Source I/O stream */
@@ -625,9 +625,8 @@ static int psd_load_rle_cmyk(GP_IO *rle_io, GP_Context *res,
return 0;
}
-static GP_Context *psd_combined_image(GP_IO *io,
- struct psd_header *header,
- GP_ProgressCallback *callback)
+static int psd_combined_image(GP_IO *io, struct psd_header *header,
+ GP_Context **res, GP_ProgressCallback *callback)
{
uint16_t compress;
GP_PixelType pixel_type = GP_PIXEL_UNKNOWN;
@@ -635,17 +634,15 @@ static GP_Context *psd_combined_image(GP_IO *io,
if (GP_IOReadB2(io, &compress)) {
GP_DEBUG(1, "Failed to read Combined Image compression");
- return NULL;
+ return errno;
}
GP_DEBUG(1, "Combined image compression %s (%"PRIu16")",
compress_method_type(compress), compress);
-
if (compress != PSD_COMPRESS_RLE) {
GP_DEBUG(1, "Unsupported compression");
- errno = ENOSYS;
- return NULL;
+ return ENOSYS;
}
if (header->color_mode == PSD_RGB) {
@@ -677,8 +674,7 @@ static GP_Context *psd_combined_image(GP_IO *io,
if (pixel_type == GP_PIXEL_UNKNOWN) {
GP_DEBUG(1, "Unsupported color_mode/channels/bpp combination");
- errno = ENOSYS;
- return NULL;
+ return ENOSYS;
}
/*
@@ -688,31 +684,28 @@ static GP_Context *psd_combined_image(GP_IO *io,
*/
if (GP_IOSeek(io, 2 * header->channels * header->h, GP_IO_SEEK_CUR) == (off_t)-1) {
GP_DEBUG(1, "Failed to skip Line Bytes Counts");
- return NULL;
+ return errno;
}
- GP_Context *res = GP_ContextAlloc(header->w, header->h, pixel_type);
+ *res = GP_ContextAlloc(header->w, header->h, pixel_type);
- if (!res)
- return NULL;
+ if (!*res)
+ return ENOMEM;
GP_IO *rle_io = rle(io);
if (!rle_io)
- return NULL;
+ return ENOMEM;
if (pixel_type == GP_PIXEL_CMYK8888)
- ret = psd_load_rle_cmyk(rle_io, res, callback);
+ ret = psd_load_rle_cmyk(rle_io, *res, callback);
else
- ret = psd_load_rle_rgb(rle_io, res, callback);
+ ret = psd_load_rle_rgb(rle_io, *res, callback);
- if (ret) {
- GP_ContextFree(res);
- GP_IOClose(rle_io);
- return NULL;
- }
+ if (ret)
+ GP_ContextFree(*res);
GP_IOClose(rle_io);
- return res;
+ return ret;
}
GP_Context *GP_ReadPSD(GP_IO *io, GP_ProgressCallback *callback)
@@ -720,6 +713,7 @@ GP_Context *GP_ReadPSD(GP_IO *io, GP_ProgressCallback *callback)
int err;
uint32_t len, size, read_size = 0;
struct psd_header header;
+ GP_Context *thumbnail = NULL;
uint16_t psd_header[] = {
'8', 'B', 'P', 'S',
@@ -737,8 +731,8 @@ GP_Context *GP_ReadPSD(GP_IO *io, GP_ProgressCallback *callback)
if (GP_IOReadF(io, psd_header, &header.channels, &header.h, &header.w,
&header.depth, &header.color_mode, &len) != 13) {
GP_DEBUG(1, "Failed to read file header");
- err = EIO;
- goto err0;
+ err = errno;
+ goto err;
}
GP_DEBUG(1, "Have PSD %"PRIu32"x%"PRIu32" channels=%"PRIu16","
@@ -773,8 +767,6 @@ GP_Context *GP_ReadPSD(GP_IO *io, GP_ProgressCallback *callback)
GP_DEBUG(1, "Image Resource Section length is %u", len);
- GP_Context *thumbnail = NULL;
-
do {
size = psd_next_img_res_block(io, &thumbnail, NULL);
@@ -787,28 +779,34 @@ GP_Context *GP_ReadPSD(GP_IO *io, GP_ProgressCallback *callback)
/* Skip Layer and Mask information */
if (GP_IOReadB4(io, &size)) {
GP_DEBUG(1, "Failed to read Layer and Mask Section size");
- goto end;
+ err = errno;
+ goto err;
}
if (GP_IOSeek(io, size, GP_IO_SEEK_CUR) == (off_t)-1) {
GP_DEBUG(1, "Failed to seek to Image Data Section");
- goto end;
+ err = errno;
+ goto err;
}
- GP_Context *combined = psd_combined_image(io, &header, callback);
+ GP_Context *combined = NULL;
+ err = psd_combined_image(io, &header, &combined, callback);
- if (combined) {
+ if (!err) {
GP_ContextFree(thumbnail);
return combined;
}
-end:
+ if (err == ECANCELED)
+ goto err;
+
if (thumbnail)
return thumbnail;
errno = ENOSYS;
return NULL;
-err0:
+err:
+ GP_ContextFree(thumbnail);
errno = err;
return NULL;
}
-----------------------------------------------------------------------
Summary of changes:
doc/about.txt | 2 +-
doc/asciidoc.conf | 3 ++
doc/asciidoc.css | 6 ++--
doc/index.txt | 2 +-
libs/loaders/GP_PSD.c | 66 +++++++++++++++++++++++------------------------
libs/loaders/GP_TIFF.c | 2 +-
6 files changed, 41 insertions(+), 40 deletions(-)
repo.or.cz automatic notification. Contact project admin jiri.bluebear.dluhos(a)gmail.com
if you want to unsubscribe, or site admin admin(a)repo.or.cz if you receive
no reply.
--
gfxprim.git ("A simple 2D graphics library with emphasis on correctness and well-defined operation.")
1
0
02 Mar '14
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project gfxprim.git.
The branch, master has been updated
via a33888669a0b42c82e7664debb6c255d33efecd2 (commit)
from d06611ad4c578b85bc46a11767e4d18c80fdbbd1 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
http://repo.or.cz/w/gfxprim.git/commit/a33888669a0b42c82e7664debb6c255d33ef…
commit a33888669a0b42c82e7664debb6c255d33efecd2
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Sun Mar 2 23:38:19 2014 +0100
loaders: PSD: Implement RLE I/O stream
This adds a RLE I/O stream to PSD loader.
Signed-off-by: Cyril Hrubis <metan(a)ucw.cz>
diff --git a/libs/loaders/GP_PSD.c b/libs/loaders/GP_PSD.c
index c53e9b50..f05ab316 100644
--- a/libs/loaders/GP_PSD.c
+++ b/libs/loaders/GP_PSD.c
@@ -436,82 +436,135 @@ static const char *compress_method_type(uint16_t compress)
}
}
-static int get_byte(GP_IO *io)
+/*
+ * PSD RLE I/O Stream
+ */
+struct rle {
+ /* RLE State */
+ int8_t op;
+ int size;
+ uint8_t val;
+
+ /* Source I/O stream */
+ GP_IO *io;
+
+ /* Read buffer */
+ ssize_t buf_fill;
+ ssize_t buf_pos;
+ uint8_t buf[1024];
+};
+
+static int rle_getc(struct rle *rle)
{
- uint8_t buf;
+ if (rle->buf_pos < rle->buf_fill)
+ return rle->buf[rle->buf_pos++];
+
+ rle->buf_fill = GP_IORead(rle->io, rle->buf, sizeof(rle->buf));
- if (GP_IORead(io, &buf, 1) != 1) {
- GP_WARN("END OF FILE REACHED");
+ if (rle->buf_fill <= 0)
return -1;
- }
- return buf;
+ rle->buf_pos = 1;
+ return rle->buf[0];
}
-struct rle {
- int8_t op;
- int size;
- uint8_t val;
-};
+static int rle_readb(struct rle *rle, void *buf, size_t size)
+{
+ ssize_t bytes = rle->buf_fill - rle->buf_pos;
+ size_t s = GP_MIN(size, (size_t)bytes);
+
+ memcpy(buf, rle->buf + rle->buf_pos, s);
+
+ rle->buf_pos += s;
-static void read_rle(GP_IO *io, struct rle *rle,
- uint8_t *buf, unsigned int size)
+ if (s < size)
+ return GP_IOFill(rle->io, buf + s, size - s);
+
+ return 0;
+}
+
+static ssize_t rle_read(GP_IO *self, void *buf, size_t size)
{
- unsigned int read = 0;
+ struct rle *rle = GP_IO_PRIV(self);
+ size_t read = 0, s;
+ uint8_t *bbuf = buf;
while (read < size) {
switch (rle->op) {
case -128:
- rle->op = get_byte(io);
-// fprintf(stderr, "Read command %in", rle->op);
+ rle->op = rle_getc(rle);
break;
case 0 ... 127:
rle->size = rle->op + 1;
-// fprintf(stderr, "VERBATIM %un", rle->size);
- while (rle->size-- && read < size)
- buf[read++] = get_byte(io);
- if (rle->size < 0)
+ s = GP_MIN(rle->size, read - size);
+ rle_readb(rle, bbuf + read, s);
+ rle->size -= s;
+ read += s;
+
+// while (rle->size-- && read < size)
+// bbuf[read++] = rle_getc(rle);
+
+ if (rle->size <= 0)
rle->op = -128;
break;
case -127 ... -1:
rle->size = 1 - rle->op;
- rle->val = get_byte(io);
+ rle->val = rle_getc(rle);
-// fprintf(stderr, "REPEAT %u x %in", rle->size, rle->val);
+ s = GP_MIN(rle->size, size - read);
+ memset(bbuf + read, rle->val, s);
+ rle->size -= s;
+ read += s;
- while (rle->size-- && read < size)
- buf[read++] = rle->val;
- if (rle->size < 0)
+// while (rle->size-- && read < size)
+// bbuf[read++] = rle->val;
+
+ if (rle->size <= 0)
rle->op = -128;
break;
}
}
+
+ return read;
+}
+
+static int rle_close(GP_IO *self)
+{
+ free(self);
+ return 0;
+}
+
+static GP_IO *rle(GP_IO *io)
+{
+ GP_IO *rle = malloc(sizeof(GP_IO) + sizeof(struct rle));
+
+ if (!rle)
+ return NULL;
+
+ struct rle *priv = GP_IO_PRIV(rle);
+
+ priv->op = -128;
+ priv->buf_fill = 0;
+ priv->buf_pos = 0;
+ priv->io = io;
+
+ rle->Read = rle_read;
+ rle->Write = NULL;
+ rle->Seek = NULL;
+ rle->Close = rle_close;
+
+ return rle;
}
/*
- * UnPackBits RLE
- *
* Data are in planar mode RRRRR... GGGGG... BBBBB... etc.
- *
- * TODO: Use buffered I/O
*/
-static int psd_load_rle_rgb(GP_IO *io, GP_Context *res,
+static int psd_load_rle_rgb(GP_IO *rle_io, GP_Context *res,
GP_ProgressCallback *callback)
{
unsigned int x, y, c, p;
unsigned int chans = res->pixel_type == GP_PIXEL_RGB888 ? 3 : 4;
uint8_t b[res->w], *bp;
- struct rle rle = {.op = -128};
-
- /*
- * Skip line byte counts
- *
- * Two bytes per channel per row
- */
- if (GP_IOSeek(io, 2 * chans * res->h, GP_IO_SEEK_CUR) == (off_t)-1) {
- GP_DEBUG(1, "Failed to skip Line Bytes Counts");
- return 1;
- }
for (c = 0; c < chans; c++) {
switch (c) {
@@ -527,7 +580,7 @@ static int psd_load_rle_rgb(GP_IO *io, GP_Context *res,
for (y = 0; y < res->h; y++) {
bp = GP_PIXEL_ADDR(res, 0, y);
- read_rle(io, &rle, b, sizeof(b));
+ GP_IORead(rle_io, b, sizeof(b));
for (x = 0; x < res->w; x++)
bp[x * chans + p] = b[x];
@@ -545,27 +598,16 @@ static int psd_load_rle_rgb(GP_IO *io, GP_Context *res,
return 0;
}
-static int psd_load_rle_cmyk(GP_IO *io, GP_Context *res,
+static int psd_load_rle_cmyk(GP_IO *rle_io, GP_Context *res,
GP_ProgressCallback *callback)
{
unsigned int x, y, c;
uint8_t b[res->w], *bp;
- struct rle rle = {.op = -128};
-
- /*
- * Skip line byte counts
- *
- * Two bytes per channel per row
- */
- if (GP_IOSeek(io, 2 * 4 * res->h, GP_IO_SEEK_CUR) == (off_t)-1) {
- GP_DEBUG(1, "Failed to skip Line Bytes Counts");
- return 1;
- }
for (c = 0; c < 4; c++) {
for (y = 0; y < res->h; y++) {
bp = GP_PIXEL_ADDR(res, 0, y);
- read_rle(io, &rle, b, sizeof(b));
+ GP_IORead(rle_io, b, sizeof(b));
for (x = 0; x < res->w; x++)
bp[x * 4 + c] = 255 - b[x];
@@ -589,6 +631,7 @@ static GP_Context *psd_combined_image(GP_IO *io,
{
uint16_t compress;
GP_PixelType pixel_type = GP_PIXEL_UNKNOWN;
+ int ret;
if (GP_IOReadB2(io, &compress)) {
GP_DEBUG(1, "Failed to read Combined Image compression");
@@ -638,23 +681,37 @@ static GP_Context *psd_combined_image(GP_IO *io,
return NULL;
}
+ /*
+ * Skip line byte counts
+ *
+ * Two bytes per channel per row
+ */
+ if (GP_IOSeek(io, 2 * header->channels * header->h, GP_IO_SEEK_CUR) == (off_t)-1) {
+ GP_DEBUG(1, "Failed to skip Line Bytes Counts");
+ return NULL;
+ }
+
GP_Context *res = GP_ContextAlloc(header->w, header->h, pixel_type);
if (!res)
return NULL;
- int ret;
+ GP_IO *rle_io = rle(io);
+ if (!rle_io)
+ return NULL;
if (pixel_type == GP_PIXEL_CMYK8888)
- ret = psd_load_rle_cmyk(io, res, callback);
+ ret = psd_load_rle_cmyk(rle_io, res, callback);
else
- ret = psd_load_rle_rgb(io, res, callback);
+ ret = psd_load_rle_rgb(rle_io, res, callback);
if (ret) {
GP_ContextFree(res);
+ GP_IOClose(rle_io);
return NULL;
}
+ GP_IOClose(rle_io);
return res;
}
@@ -719,7 +776,7 @@ GP_Context *GP_ReadPSD(GP_IO *io, GP_ProgressCallback *callback)
GP_Context *thumbnail = NULL;
do {
- size = psd_next_img_res_block(io, &thumbnail, callback);
+ size = psd_next_img_res_block(io, &thumbnail, NULL);
if (size == 0)
return thumbnail;
-----------------------------------------------------------------------
Summary of changes:
libs/loaders/GP_PSD.c | 175 ++++++++++++++++++++++++++++++++-----------------
1 files changed, 116 insertions(+), 59 deletions(-)
repo.or.cz automatic notification. Contact project admin jiri.bluebear.dluhos(a)gmail.com
if you want to unsubscribe, or site admin admin(a)repo.or.cz if you receive
no reply.
--
gfxprim.git ("A simple 2D graphics library with emphasis on correctness and well-defined operation.")
1
0
02 Mar '14
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project gfxprim.git.
The branch, master has been updated
discards 972b83d7f74f4c22839536d0604183c717f545dc (commit)
via d06611ad4c578b85bc46a11767e4d18c80fdbbd1 (commit)
This update added new revisions after undoing existing revisions. That is
to say, the old revision is not a strict subset of the new revision. This
situation occurs when you --force push a change and generate a repository
containing something like this:
* -- * -- B -- O -- O -- O (972b83d7f74f4c22839536d0604183c717f545dc)
N -- N -- N (d06611ad4c578b85bc46a11767e4d18c80fdbbd1)
When this happens we assume that you've already had alert emails for all
of the O revisions, and so we here report only the revisions in the N
branch from the common base, B.
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
http://repo.or.cz/w/gfxprim.git/commit/d06611ad4c578b85bc46a11767e4d18c80fd…
commit d06611ad4c578b85bc46a11767e4d18c80fdbbd1
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Sun Mar 2 21:29:00 2014 +0100
PCX: Implement PCX RLE I/O stream.
The loaders now internally uses RLE I/O stream.
TODO: Check errors from GP_IORead() in inner loops
More tests
Signed-off-by: Cyril Hrubis <metan(a)ucw.cz>
diff --git a/include/loaders/GP_PCX.h b/include/loaders/GP_PCX.h
index 0d7d6e22..f5ce05c1 100644
--- a/include/loaders/GP_PCX.h
+++ b/include/loaders/GP_PCX.h
@@ -33,7 +33,6 @@
#include "core/GP_ProgressCallback.h"
#include "loaders/GP_IO.h"
-
/*
* Reads a PCX from an IO stream.
*
diff --git a/libs/loaders/GP_PCX.c b/libs/loaders/GP_PCX.c
index 698f82eb..8d92c0f2 100644
--- a/libs/loaders/GP_PCX.c
+++ b/libs/loaders/GP_PCX.c
@@ -37,6 +37,133 @@
#include "GP_PCX.h"
+/*
+ * PCX RLE I/O Stream
+ */
+struct rle {
+ /* RLE internal state */
+ int cnt;
+ int val;
+
+ /* Read counter */
+ off_t pos;
+
+ /* Source I/O stream */
+ GP_IO *io;
+
+ /* Read buffer */
+ ssize_t buf_fill;
+ ssize_t buf_pos;
+ uint8_t buf[128];
+};
+
+static int rle_getc(struct rle *rle)
+{
+ if (rle->buf_pos < rle->buf_fill)
+ return rle->buf[rle->buf_pos++];
+
+ rle->buf_fill = GP_IORead(rle->io, rle->buf, sizeof(rle->buf));
+
+ if (rle->buf_fill <= 0)
+ return -1;
+
+ rle->buf_pos = 1;
+ return rle->buf[0];
+}
+
+/*
+ * RLE I/O stream
+ *
+ * - reads exactly size bytes unless read from underlying I/O has failed
+ *
+ * - the size is expected to be multiple of bytes_per_line, the specification
+ * forbids for RLE to span across pixel lines, but there are images that does
+ * so. This code only prints a warning in this case.
+ */
+static ssize_t rle_read(GP_IO *self, void *buf, size_t size)
+{
+ struct rle *priv = GP_IO_PRIV(self);
+ unsigned int read = 0;
+ uint8_t *bbuf = buf;
+ int b;
+
+ for (;;) {
+ while (priv->cnt > 0 && read < size) {
+ bbuf[read++] = priv->val;
+ priv->cnt--;
+ }
+
+ if (read >= size) {
+ priv->pos += read;
+ if (priv->cnt)
+ GP_WARN("Nonzero repeat count (%u) %02x at %zi",
+ priv->cnt, priv->val, priv->pos);
+ //priv->cnt = 0;
+ return read;
+ }
+
+ b = rle_getc(priv);
+
+ if (b < 0)
+ return priv->buf_fill;
+
+ if ((b & 0xc0) == 0xc0) {
+ priv->cnt = b & 0x3f;
+ priv->val = rle_getc(priv);
+ if (priv->val < 0)
+ return priv->buf_fill;
+ } else {
+ priv->cnt = 1;
+ priv->val = b;
+ }
+ }
+}
+
+/*
+ * Only seeks forward to skip padding also works for GP_IOTell().
+ */
+static off_t rle_seek(GP_IO *self, off_t off, enum GP_IOWhence whence)
+{
+ uint8_t b;
+ struct rle *priv = GP_IO_PRIV(self);
+
+ if (whence != GP_IO_SEEK_CUR || off < 0)
+ return EINVAL;
+
+ while (off--)
+ rle_read(self, &b, 1);
+
+ return priv->pos;
+}
+
+static int rle_close(GP_IO *self)
+{
+ free(self);
+ return 0;
+}
+
+static GP_IO *rle(GP_IO *io)
+{
+ GP_IO *rle = malloc(sizeof(GP_IO) + sizeof(struct rle));
+
+ if (!rle)
+ return NULL;
+
+ struct rle *priv = GP_IO_PRIV(rle);
+
+ priv->cnt = 0;
+ priv->buf_fill = 0;
+ priv->buf_pos = 0;
+ priv->io = io;
+
+ rle->Read = rle_read;
+ rle->Write = NULL;
+ rle->Seek = rle_seek;
+ rle->Close = rle_close;
+
+ return rle;
+}
+
/* Creator ZSoft: 0x0a
* Version: 0x00, 0x02, 0x03, 0x04, 0x05
* RLE: 0x01
@@ -88,69 +215,6 @@ struct pcx_header {
uint8_t palette[48];
};
-static int get_byte(GP_IO *io)
-{
- uint8_t buf;
-
- if (GP_IORead(io, &buf, 1) != 1)
- return -1;
-
- return buf;
-}
-
-static int readline(GP_IO *io, uint8_t *buf, unsigned int size, unsigned int padd)
-{
- int b, val = 0, cnt = 0;
- unsigned int read = 0;
-
- for (;;) {
- while (cnt > 0 && read < size) {
- buf[read++] = val;
- cnt--;
- }
-
- if (read >= size) {
- goto end;
- }
-
- b = get_byte(io);
-
- if (b == -1) {
- GP_WARN("End of file reached unexpectedly");
- return 0;
- }
-
- if ((b & 0xc0) == 0xc0) {
- cnt = b & 0x3f;
- val = get_byte(io);
- } else {
- cnt = 1;
- val = b;
- }
- }
-
-end:
- /*
- * Data may be padded, read the excess bytes
- */
- while (padd--) {
- if (cnt) {
- cnt--;
- } else {
- b = get_byte(io);
- if ((b & 0xc0) == 0xc0) {
- cnt = b & 0x3f;
- get_byte(io);
- }
- }
- }
-
- if (cnt)
- GP_WARN("Nonzero repeat count at the line end (%u)", cnt);
-
- return 0;
-}
-
#include "core/GP_BitSwap.h"
static int read_g1(GP_IO *io, struct pcx_header *header,
@@ -164,20 +228,26 @@ static int read_g1(GP_IO *io, struct pcx_header *header,
return EINVAL;
}
+ GP_IO *rle_io = rle(io);
+ if (!rle_io)
+ return errno;
+
for (y = 0; y < res->h; y++) {
uint8_t *addr = GP_PIXEL_ADDR(res, 0, y);
-
- readline(io, addr, res->bytes_per_row, padd);
+ GP_IORead(rle_io, addr, res->bytes_per_row);
+ GP_IOSeek(rle_io, GP_IO_SEEK_CUR, padd);
//TODO: FIX Endians
GP_BitSwapRow_B1(addr, res->bytes_per_row);
if (GP_ProgressCallbackReport(callback, y, res->h, res->w)) {
GP_DEBUG(1, "Operation aborted");
+ GP_IOClose(rle_io);
return ECANCELED;
}
}
+ GP_IOClose(rle_io);
return 0;
}
@@ -188,8 +258,14 @@ static int read_rgb888(GP_IO *io, struct pcx_header *header,
unsigned int bpr = header->bytes_per_line;
uint8_t b[3 * bpr];
+ GP_IO *rle_io = rle(io);
+ if (!rle_io)
+ return errno;
+
for (y = 0; y < res->h; y++) {
- readline(io, b, sizeof(b), 0);
+ //readline(io, b, sizeof(b), 0);
+
+ GP_IORead(rle_io, b, sizeof(b));
for (x = 0; x < res->w; x++) {
GP_Pixel pix = GP_Pixel_CREATE_RGB888(b[x],
@@ -200,10 +276,12 @@ static int read_rgb888(GP_IO *io, struct pcx_header *header,
if (GP_ProgressCallbackReport(callback, y, res->h, res->w)) {
GP_DEBUG(1, "Operation aborted");
+ GP_IOClose(rle_io);
return ECANCELED;
}
}
+ GP_IOClose(rle_io);
return 0;
}
@@ -236,8 +314,12 @@ static int read_16_palette(GP_IO *io, struct pcx_header *header,
return EINVAL;
}
+ GP_IO *rle_io = rle(io);
+ if (!rle_io)
+ return errno;
+
for (y = 0; y < res->h; y++) {
- readline(io, b, sizeof(b), 0);
+ GP_IORead(rle_io, b, sizeof(b));
i = 0;
@@ -252,55 +334,67 @@ static int read_16_palette(GP_IO *io, struct pcx_header *header,
if (GP_ProgressCallbackReport(callback, y, res->h, res->w)) {
GP_DEBUG(1, "Operation aborted");
+ GP_IOClose(rle_io);
return ECANCELED;
}
}
+ GP_IOClose(rle_io);
return 0;
}
+#define PALETTE_SIZE (3 * 256 + 1)
+
static int read_256_palette(GP_IO *io, struct pcx_header *header,
GP_Context *res, GP_ProgressCallback *callback)
{
uint32_t x, y;
unsigned int i;
+ uint8_t buf[GP_MAX(PALETTE_SIZE, header->bytes_per_line)];
GP_Pixel palette[256];
- uint8_t b[header->bytes_per_line];
if (GP_IOSeek(io, -769, GP_IO_SEEK_END) == (off_t)-1) {
GP_DEBUG(1, "Failed to seek to palette: %s", strerror(errno));
return EIO;
}
- if (get_byte(io) != 0x0c) {
- GP_DEBUG(1, "Wrong palette marker");
+ if (GP_IOFill(io, buf, PALETTE_SIZE)) {
+ GP_DEBUG(1, "Failed to read palette: %s", strerror(errno));
return EIO;
}
- for (i = 0; i < 256; i++) {
- palette[i] = get_byte(io) << 16;
- palette[i] |= get_byte(io) << 8;
- palette[i] |= get_byte(io);
+ if (buf[0] != 0x0c) {
+ GP_DEBUG(1, "Wrong palette marker");
+ return EIO;
}
+ for (i = 0; i < 256; i++)
+ palette[i] = (buf[3*i+1]<<16) | (buf[3*i+2])<<8 | buf[3*i+3];
+
if (GP_IOSeek(io, 128, GP_IO_SEEK_SET) == (off_t)-1) {
GP_DEBUG(1, "Failed to seek to image data: %s",
strerror(errno));
return EIO;
}
+ GP_IO *rle_io = rle(io);
+ if (!rle_io)
+ return errno;
+
for (y = 0; y < res->h; y++) {
- readline(io, b, sizeof(b), 0);
+ GP_IORead(rle_io, buf, header->bytes_per_line);
for (x = 0; x < res->w; x++)
- GP_PutPixel_Raw_24BPP(res, x, y, palette[b[x]]);
+ GP_PutPixel_Raw_24BPP(res, x, y, palette[buf[x]]);
if (GP_ProgressCallbackReport(callback, y, res->h, res->w)) {
GP_DEBUG(1, "Operation aborted");
+ GP_IOClose(rle_io);
return ECANCELED;
}
}
+ GP_IOClose(rle_io);
return 0;
}
-----------------------------------------------------------------------
Summary of changes:
libs/loaders/GP_PCX.c | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)
repo.or.cz automatic notification. Contact project admin jiri.bluebear.dluhos(a)gmail.com
if you want to unsubscribe, or site admin admin(a)repo.or.cz if you receive
no reply.
--
gfxprim.git ("A simple 2D graphics library with emphasis on correctness and well-defined operation.")
1
0
02 Mar '14
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project gfxprim.git.
The branch, master has been updated
via 972b83d7f74f4c22839536d0604183c717f545dc (commit)
via 71dc80d8bbbdc5af75aed1896288e2d7a34cdead (commit)
from 42571d6c7b8ffe8318c1ecfa32dbba3fc3c9c28b (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
http://repo.or.cz/w/gfxprim.git/commit/972b83d7f74f4c22839536d0604183c717f5…
commit 972b83d7f74f4c22839536d0604183c717f545dc
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Sun Mar 2 21:29:00 2014 +0100
PCX: Implement PCX RLE I/O stream.
The loaders now internally uses RLE I/O stream.
TODO: Check errors from GP_IORead() in inner loops
More tests
Signed-off-by: Cyril Hrubis <metan(a)ucw.cz>
diff --git a/include/loaders/GP_PCX.h b/include/loaders/GP_PCX.h
index 0d7d6e22..f5ce05c1 100644
--- a/include/loaders/GP_PCX.h
+++ b/include/loaders/GP_PCX.h
@@ -33,7 +33,6 @@
#include "core/GP_ProgressCallback.h"
#include "loaders/GP_IO.h"
-
/*
* Reads a PCX from an IO stream.
*
diff --git a/libs/loaders/GP_PCX.c b/libs/loaders/GP_PCX.c
index 698f82eb..61806583 100644
--- a/libs/loaders/GP_PCX.c
+++ b/libs/loaders/GP_PCX.c
@@ -37,6 +37,132 @@
#include "GP_PCX.h"
+/*
+ * PCX RLE I/O Stream
+ */
+struct rle {
+ /* RLE internal state */
+ int cnt;
+ int val;
+
+ /* Read counter */
+ off_t pos;
+
+ /* Source I/O stream */
+ GP_IO *io;
+
+ /* Read buffer */
+ ssize_t buf_fill;
+ ssize_t buf_pos;
+ uint8_t buf[128];
+};
+
+static int rle_getc(struct rle *rle)
+{
+ if (rle->buf_pos < rle->buf_fill)
+ return rle->buf[rle->buf_pos++];
+
+ rle->buf_fill = GP_IORead(rle->io, rle->buf, sizeof(rle->buf));
+
+ if (rle->buf_fill <= 0)
+ return -1;
+
+ rle->buf_pos = 1;
+ return rle->buf[0];
+}
+
+/*
+ * RLE I/O stream
+ *
+ * - reads exactly size bytes unless read from underlying I/O has failed
+ *
+ * - the size is expected to be multiple of bytes_per_line, the specification
+ * forbids for RLE to span across pixel lines, but there are images that does
+ * so. This code only prints a warning in this case.
+ */
+static ssize_t rle_read(GP_IO *self, void *buf, size_t size)
+{
+ struct rle *priv = GP_IO_PRIV(self);
+ unsigned int read = 0;
+ uint8_t *bbuf = buf;
+ int b;
+
+ for (;;) {
+ while (priv->cnt > 0 && read < size) {
+ bbuf[read++] = priv->val;
+ priv->cnt--;
+ }
+
+ if (read >= size) {
+ priv->pos += read;
+ if (priv->cnt)
+ GP_WARN("Nonzero repeat count (%u) %02x at %zi",
+ priv->cnt, priv->val, priv->pos);
+ //priv->cnt = 0;
+ return read;
+ }
+
+ b = rle_getc(priv);
+
+ if (b < 0)
+ return priv->buf_fill;
+
+ if ((b & 0xc0) == 0xc0) {
+ priv->cnt = b & 0x3f;
+ priv->val = rle_getc(priv);
+ if (priv->val < 0)
+ return priv->buf_fill;
+ } else {
+ priv->cnt = 1;
+ priv->val = b;
+ }
+ }
+}
+
+/*
+ * Only seeks forward to skip padding also works for GP_IOTell().
+ */
+static off_t rle_seek(GP_IO *self, off_t off, enum GP_IOWhence whence)
+{
+ uint8_t b;
+ struct rle *priv = GP_IO_PRIV(self);
+
+ if (whence != GP_IO_SEEK_CUR || off < 0)
+ return EINVAL;
+
+ while (off--)
+ rle_read(self, &b, 1);
+
+ return priv->pos;
+}
+
+static int rle_close(GP_IO *self)
+{
+ free(self);
+ return 0;
+}
+
+GP_IO *rle(GP_IO *io)
+{
+ GP_IO *rle = malloc(sizeof(GP_IO) + sizeof(struct rle));
+
+ if (!rle)
+ return NULL;
+
+ struct rle *priv = GP_IO_PRIV(rle);
+
+ priv->cnt = 0;
+ priv->buf_fill = 0;
+ priv->io = io;
+
+ rle->Read = rle_read;
+ rle->Write = NULL;
+ rle->Seek = rle_seek;
+ rle->Close = rle_close;
+
+ return rle;
+}
+
/* Creator ZSoft: 0x0a
* Version: 0x00, 0x02, 0x03, 0x04, 0x05
* RLE: 0x01
@@ -88,69 +214,6 @@ struct pcx_header {
uint8_t palette[48];
};
-static int get_byte(GP_IO *io)
-{
- uint8_t buf;
-
- if (GP_IORead(io, &buf, 1) != 1)
- return -1;
-
- return buf;
-}
-
-static int readline(GP_IO *io, uint8_t *buf, unsigned int size, unsigned int padd)
-{
- int b, val = 0, cnt = 0;
- unsigned int read = 0;
-
- for (;;) {
- while (cnt > 0 && read < size) {
- buf[read++] = val;
- cnt--;
- }
-
- if (read >= size) {
- goto end;
- }
-
- b = get_byte(io);
-
- if (b == -1) {
- GP_WARN("End of file reached unexpectedly");
- return 0;
- }
-
- if ((b & 0xc0) == 0xc0) {
- cnt = b & 0x3f;
- val = get_byte(io);
- } else {
- cnt = 1;
- val = b;
- }
- }
-
-end:
- /*
- * Data may be padded, read the excess bytes
- */
- while (padd--) {
- if (cnt) {
- cnt--;
- } else {
- b = get_byte(io);
- if ((b & 0xc0) == 0xc0) {
- cnt = b & 0x3f;
- get_byte(io);
- }
- }
- }
-
- if (cnt)
- GP_WARN("Nonzero repeat count at the line end (%u)", cnt);
-
- return 0;
-}
-
#include "core/GP_BitSwap.h"
static int read_g1(GP_IO *io, struct pcx_header *header,
@@ -164,20 +227,26 @@ static int read_g1(GP_IO *io, struct pcx_header *header,
return EINVAL;
}
+ GP_IO *rle_io = rle(io);
+ if (!rle_io)
+ return errno;
+
for (y = 0; y < res->h; y++) {
uint8_t *addr = GP_PIXEL_ADDR(res, 0, y);
-
- readline(io, addr, res->bytes_per_row, padd);
+ GP_IORead(rle_io, addr, res->bytes_per_row);
+ GP_IOSeek(rle_io, GP_IO_SEEK_CUR, padd);
//TODO: FIX Endians
GP_BitSwapRow_B1(addr, res->bytes_per_row);
if (GP_ProgressCallbackReport(callback, y, res->h, res->w)) {
GP_DEBUG(1, "Operation aborted");
+ GP_IOClose(rle_io);
return ECANCELED;
}
}
+ GP_IOClose(rle_io);
return 0;
}
@@ -188,8 +257,14 @@ static int read_rgb888(GP_IO *io, struct pcx_header *header,
unsigned int bpr = header->bytes_per_line;
uint8_t b[3 * bpr];
+ GP_IO *rle_io = rle(io);
+ if (!rle_io)
+ return errno;
+
for (y = 0; y < res->h; y++) {
- readline(io, b, sizeof(b), 0);
+ //readline(io, b, sizeof(b), 0);
+
+ GP_IORead(rle_io, b, sizeof(b));
for (x = 0; x < res->w; x++) {
GP_Pixel pix = GP_Pixel_CREATE_RGB888(b[x],
@@ -200,10 +275,12 @@ static int read_rgb888(GP_IO *io, struct pcx_header *header,
if (GP_ProgressCallbackReport(callback, y, res->h, res->w)) {
GP_DEBUG(1, "Operation aborted");
+ GP_IOClose(rle_io);
return ECANCELED;
}
}
+ GP_IOClose(rle_io);
return 0;
}
@@ -236,8 +313,12 @@ static int read_16_palette(GP_IO *io, struct pcx_header *header,
return EINVAL;
}
+ GP_IO *rle_io = rle(io);
+ if (!rle_io)
+ return errno;
+
for (y = 0; y < res->h; y++) {
- readline(io, b, sizeof(b), 0);
+ GP_IORead(rle_io, b, sizeof(b));
i = 0;
@@ -252,55 +333,67 @@ static int read_16_palette(GP_IO *io, struct pcx_header *header,
if (GP_ProgressCallbackReport(callback, y, res->h, res->w)) {
GP_DEBUG(1, "Operation aborted");
+ GP_IOClose(rle_io);
return ECANCELED;
}
}
+ GP_IOClose(rle_io);
return 0;
}
+#define PALETTE_SIZE (3 * 256 + 1)
+
static int read_256_palette(GP_IO *io, struct pcx_header *header,
GP_Context *res, GP_ProgressCallback *callback)
{
uint32_t x, y;
unsigned int i;
+ uint8_t buf[GP_MAX(PALETTE_SIZE, header->bytes_per_line)];
GP_Pixel palette[256];
- uint8_t b[header->bytes_per_line];
if (GP_IOSeek(io, -769, GP_IO_SEEK_END) == (off_t)-1) {
GP_DEBUG(1, "Failed to seek to palette: %s", strerror(errno));
return EIO;
}
- if (get_byte(io) != 0x0c) {
- GP_DEBUG(1, "Wrong palette marker");
+ if (GP_IOFill(io, buf, PALETTE_SIZE)) {
+ GP_DEBUG(1, "Failed to read palette: %s", strerror(errno));
return EIO;
}
- for (i = 0; i < 256; i++) {
- palette[i] = get_byte(io) << 16;
- palette[i] |= get_byte(io) << 8;
- palette[i] |= get_byte(io);
+ if (buf[0] != 0x0c) {
+ GP_DEBUG(1, "Wrong palette marker");
+ return EIO;
}
+ for (i = 0; i < 256; i++)
+ palette[i] = (buf[3*i+1]<<16) | (buf[3*i+2])<<8 | buf[3*i+3];
+
if (GP_IOSeek(io, 128, GP_IO_SEEK_SET) == (off_t)-1) {
GP_DEBUG(1, "Failed to seek to image data: %s",
strerror(errno));
return EIO;
}
+ GP_IO *rle_io = rle(io);
+ if (!rle_io)
+ return errno;
+
for (y = 0; y < res->h; y++) {
- readline(io, b, sizeof(b), 0);
+ GP_IORead(rle_io, buf, header->bytes_per_line);
for (x = 0; x < res->w; x++)
- GP_PutPixel_Raw_24BPP(res, x, y, palette[b[x]]);
+ GP_PutPixel_Raw_24BPP(res, x, y, palette[buf[x]]);
if (GP_ProgressCallbackReport(callback, y, res->h, res->w)) {
GP_DEBUG(1, "Operation aborted");
+ GP_IOClose(rle_io);
return ECANCELED;
}
}
+ GP_IOClose(rle_io);
return 0;
}
http://repo.or.cz/w/gfxprim.git/commit/71dc80d8bbbdc5af75aed1896288e2d7a34c…
commit 71dc80d8bbbdc5af75aed1896288e2d7a34cdead
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Sun Mar 2 18:45:02 2014 +0100
doc: loaders: Add PSD + cleanup.
Signed-off-by: Cyril Hrubis <metan(a)ucw.cz>
diff --git a/demos/spiv/spiv.1 b/demos/spiv/spiv.1
index fb23f1f5..bca63dd6 100644
--- a/demos/spiv/spiv.1
+++ b/demos/spiv/spiv.1
@@ -11,9 +11,9 @@ is a fast, lightweight and minimalistic image viewer build on the
top of the GFXprim library.
.PP
Spiv supports wide range of image formats, currently supported are
-JPEG, PNG, GIF, BMP, TIFF, PSP, PNM, PCX, JPEG2000 and CBZ (as well
-general ZIP archives with images), and more will come in the
-near future.
+JPEG, PNG, GIF, BMP, TIFF, PSP, PSD, PNM, PCX, JPEG2000 and CBZ
+(as well general ZIP archives with images), and more will come in
+the near future.
.PP
Spiv supports variety of video backends (via GFXprim backends)
currently these are X11, Linux Framebuffer, SDL and AAlib. Spiv also
diff --git a/demos/spiv/spiv_help.c b/demos/spiv/spiv_help.c
index 186b1c53..cecd1ecb 100644
--- a/demos/spiv/spiv_help.c
+++ b/demos/spiv/spiv_help.c
@@ -164,9 +164,9 @@ const char *man_head =
"top of the GFXprim library.n"
".PPn"
"Spiv supports wide range of image formats, currently supported aren"
- "JPEG, PNG, GIF, BMP, TIFF, PSP, PNM, PCX, JPEG2000 and CBZ (as welln"
- "general ZIP archives with images), and more will come in then"
- "near future.n"
+ "JPEG, PNG, GIF, BMP, TIFF, PSP, PSD, PNM, PCX, JPEG2000 and CBZn"
+ "(as well general ZIP archives with images), and more will come inn"
+ "the near future.n"
".PPn"
"Spiv supports variety of video backends (via GFXprim backends)n"
"currently these are X11, Linux Framebuffer, SDL and AAlib. Spiv alson"
diff --git a/doc/about.txt b/doc/about.txt
index 018d71f9..f632eaaf 100644
--- a/doc/about.txt
+++ b/doc/about.txt
@@ -99,6 +99,11 @@ images into various standard formats (PNG, JPEG, GIF, TIFF, BMP, PNM, etc...).
[green]#Composite image only for newer formats than 3.0# |
[black]*No*
+| PSD |
+ Adobe Photoshop Image |
+ [green]#Thumbnail or Merged image (16 bit RGB and CMYK not supported yet)#|
+ [black]*No*
+
| PBM PGM PPM PNM |
Netpbm portable bitmap |
[green]#All but < 8bit binary grayscale# |
diff --git a/doc/loaders.txt b/doc/loaders.txt
index 1734718a..af588cb9 100644
--- a/doc/loaders.txt
+++ b/doc/loaders.txt
@@ -507,6 +507,57 @@ int GP_MatchPSP(const void *buf);
Matches a 'PSP' file signature. Returns non-zero if found.
+PSD Loader
+~~~~~~~~~~
+
+The 'PSD' loader can load a merged image (if present) or a thumbnail from an
+Adobe Photoshop Image. Currently 16bit RGB and 16bit CMYK is not supported and
+the loader will fallback to the thumbnail in this case (which is always 8bit
+RGB).
+
+[source,c]
+-------------------------------------------------------------------------------
+#include <loaders/GP_PSD.h>
+/* or */
+#include <GP.h>
+
+GP_Context *GP_ReadPSD(GP_IO *io, GP_ProgressCallback *callback);
+-------------------------------------------------------------------------------
+
+Reads a 'PSP' image from readable 'GP_IO'. The link:loaders_io.html[IO stream]
+is expected to start exactly at the 'PSD' file signature.
+
+Returns newly allocated context (containing decompressed image) or in case of
+failure 'NULL' and 'errno' is set.
+
+[source,c]
+-------------------------------------------------------------------------------
+#include <loaders/GP_PSD.h>
+/* or */
+#include <GP.h>
+
+GP_Context *GP_LoadPSD(const char *src_path, GP_ProgressCallback *callback);
+-------------------------------------------------------------------------------
+
+Loads a merged image (if present) from a 'PSD' file.
+
+Fallbacks to thumbnail if merged image is not present or has unsupported pixel
+type.
+
+Returns 'NULL' (TODO ERRNO) if merged image is not present/supported and
+thumbnail is not present either.
+
+[source,c]
+-------------------------------------------------------------------------------
+#include <loaders/GP_PSD.h>
+/* or */
+#include <GP.h>
+
+int GP_MatchPSD(const void *buf);
+-------------------------------------------------------------------------------
+
+Matches a 'PSD' file signature. Returns non-zero if found.
+
PNM Loaders
~~~~~~~~~~~
diff --git a/doc/loaders_python.txt b/doc/loaders_python.txt
index ae2207e7..6ffaaa6a 100644
--- a/doc/loaders_python.txt
+++ b/doc/loaders_python.txt
@@ -23,6 +23,7 @@ import gfxprim.loaders as loaders
img = loaders.LoadPPM(path, callback=None)
img = loaders.LoadPCX(path, callback=None)
img = loaders.LoadPSP(path, callback=None)
+ img = loaders.LoadPSD(path, callback=None)
img = loaders.LoadTIFF(path, callback=None)
-------------------------------------------------------------------------------
@@ -32,17 +33,20 @@ First one is general purpose loader function that automatically detects the
file format. The format is detected from file extension first and if this
fails files signature is used.
-May raise 'OSError' with errno set to 'EPERM', 'EISDIR', 'ENOENT' or any other
-'errno' set by 'open(2)', 'read(2)', 'seek(2)'.
+|===============================================================================
+| May raise 'OSError' with errno set to 'EPERM', 'EISDIR', 'ENOENT' or any other
+ 'errno' set by 'open(2)', 'read(2)', 'seek(2)'.
-May raise 'OSError' with errno set to 'ENOSYS' on unsupported or not recognized
-format.
+| May raise 'OSError' with errno set to 'ENOSYS' on unsupported or not recognized
+ format or if specific loader was disabled upon compilation.
-May raise 'OSError' with errno set to 'EIO' when file is damaged.
+| May raise 'OSError' with errno set to 'EIO' or 'EINVAL' when file is damaged.
-May raise 'OSError' with errno set to 'ECANCELED' when action was aborted from
-callback. See progress callback
-link:core_python.html#Progress_Callback[documentation] for more.
+| May raise 'OSError' with errno set to 'ECANCELED' when action was aborted from
+ callback. See link:core_python.html#Progress_Callback[progress callback] for
+ more.
+
+|===============================================================================
[source,python]
@@ -65,16 +69,16 @@ Save image to a file.
For the Save() method the file format is derived from the extension.
-May raise 'OSError' with errno set to 'EPERM', 'EISDIR', 'ENOENT' or any other
-'errno' set by 'open(2)', 'write(2)', 'seek(2)'.
-
-May raise 'OSError' with errno set to 'ENOSYS' on unsupported pixel type for
-a given format.
-
-May raise 'OSError' with errno set to 'EIO' when filesystem is full.
-
-May raise 'OSError' with errno set to 'ECANCELED' when action was interrupted
-by callback.
+|===============================================================================
+| May raise 'OSError' with errno set to 'EPERM', 'EISDIR', 'ENOENT', 'ENOSPC'
+ or any other 'errno' set by 'open(2)', 'write(2)', 'seek(2)'.
+| May raise 'OSError' with errno set to 'ENOSYS' if pixel type is not supported
+ by the format or if the save method is not implemented (possibly disabled upon
+ compilation).
+| May raise 'OSError' with errno set to 'ECANCELED' when action was interrupted
+ by callback. See link:core_python.html#Progress_Callback[progress callback]
+ for more.
+|===============================================================================
[source,python]
-------------------------------------------------------------------------------
diff --git a/doc/spiv.txt b/doc/spiv.txt
index 0fd031b1..4f678b82 100644
--- a/doc/spiv.txt
+++ b/doc/spiv.txt
@@ -6,8 +6,8 @@ Spiv is a fast, lightweight and minimalistic image viewer build on the top of
the GFXprim library.
Spiv supports wide range of image formats, currently supported are JPEG, PNG,
-GIF, BMP, TIFF, PSP, PNM, PCX, JPEG2000 and CBZ (as well general ZIP archives
-with images), and more will come in the near future.
+GIF, BMP, TIFF, PSP, PSD, PNM, PCX, JPEG2000 and CBZ (as well general ZIP
+archives with images), and more will come in the near future.
Spiv implements image caches with LRU (last recently used) algorithm which
speeds up subsequent image operations (rotations, going back and forth).
diff --git a/include/loaders/GP_PSD.h b/include/loaders/GP_PSD.h
index 8ab5b619..d8cd2213 100644
--- a/include/loaders/GP_PSD.h
+++ b/include/loaders/GP_PSD.h
@@ -22,7 +22,7 @@
/*
- PSD thumbnail image loader.
+ PSD image loader.
*/
@@ -34,7 +34,11 @@
#include "loaders/GP_IO.h"
/*
- * Reads a PSD thumbnail from an IO stream.
+ * Reads a PSD from an IO stream.
+ *
+ * The loaders tries to read merged image (if present) and fallback to
+ * thumbnail. It may return NULL with errno untouched if neither merged image
+ * nor thumbnail was present (which seem to be really uncommon).
*
* Returns newly allocated context cotaining the loaded image or in case of
* failure NULL and errno is set.
-----------------------------------------------------------------------
Summary of changes:
demos/spiv/spiv.1 | 6 +-
demos/spiv/spiv_help.c | 6 +-
doc/about.txt | 5 +
doc/loaders.txt | 51 ++++++++++
doc/loaders_python.txt | 40 ++++----
doc/spiv.txt | 4 +-
include/loaders/GP_PCX.h | 1 -
include/loaders/GP_PSD.h | 8 +-
libs/loaders/GP_PCX.c | 245 +++++++++++++++++++++++++++++++--------------
9 files changed, 261 insertions(+), 105 deletions(-)
repo.or.cz automatic notification. Contact project admin jiri.bluebear.dluhos(a)gmail.com
if you want to unsubscribe, or site admin admin(a)repo.or.cz if you receive
no reply.
--
gfxprim.git ("A simple 2D graphics library with emphasis on correctness and well-defined operation.")
1
0
16 Feb '14
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project gfxprim.git.
The branch, master has been updated
discards 18234b50ce20e3bcbbf149ff08e8dbc08bbdc510 (commit)
via 42571d6c7b8ffe8318c1ecfa32dbba3fc3c9c28b (commit)
This update added new revisions after undoing existing revisions. That is
to say, the old revision is not a strict subset of the new revision. This
situation occurs when you --force push a change and generate a repository
containing something like this:
* -- * -- B -- O -- O -- O (18234b50ce20e3bcbbf149ff08e8dbc08bbdc510)
N -- N -- N (42571d6c7b8ffe8318c1ecfa32dbba3fc3c9c28b)
When this happens we assume that you've already had alert emails for all
of the O revisions, and so we here report only the revisions in the N
branch from the common base, B.
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
http://repo.or.cz/w/gfxprim.git/commit/42571d6c7b8ffe8318c1ecfa32dbba3fc3c9…
commit 42571d6c7b8ffe8318c1ecfa32dbba3fc3c9c28b
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Sun Feb 16 19:13:57 2014 +0100
loaders: PSD: Work on combined image loading.
Works for 8-bit RGB, RGBA and CMYK for now.
Signed-off-by: Cyril Hrubis <metan(a)ucw.cz>
diff --git a/libs/loaders/GP_PSD.c b/libs/loaders/GP_PSD.c
index 785f4f55..c53e9b50 100644
--- a/libs/loaders/GP_PSD.c
+++ b/libs/loaders/GP_PSD.c
@@ -35,6 +35,7 @@
#include "core/GP_Debug.h"
#include "core/GP_Common.h"
+#include "core/GP_GetPutPixel.h"
#include "GP_JPG.h"
#include "GP_PSD.h"
@@ -351,7 +352,6 @@ static unsigned int psd_next_img_res_block(GP_IO *io, GP_Context **res,
prev = GP_IOTell(io);
*res = psd_thumbnail50(io, res_size, callback);
after = GP_IOTell(io);
- GP_DEBUG(1, "PREV %li after %li diff %li size %u", prev, after, after - prev, seek_size);
seek_size -= (after - prev);
break;
case PSD_VERSION_INFO:
@@ -405,15 +405,264 @@ static const char *psd_color_mode_name(uint16_t color_mode)
}
}
-GP_Context *GP_ReadPSD(GP_IO *io, GP_ProgressCallback *callback)
-{
- int err;
+enum compress_method {
+ PSD_COMPRESS_RAW = 0,
+ PSD_COMPRESS_RLE = 1,
+ PSD_COMPRESS_ZIP_NP = 2,
+ PSD_COMPRESS_ZIP_WP = 3,
+};
+
+struct psd_header {
uint32_t w;
uint32_t h;
uint16_t depth;
uint16_t channels;
uint16_t color_mode;
+};
+
+static const char *compress_method_type(uint16_t compress)
+{
+ switch (compress) {
+ case PSD_COMPRESS_RAW:
+ return "Raw";
+ case PSD_COMPRESS_RLE:
+ return "RLE";
+ case PSD_COMPRESS_ZIP_NP:
+ return "ZIP (no prediction)";
+ case PSD_COMPRESS_ZIP_WP:
+ return "ZIP (with prediction)";
+ default:
+ return "Unknown";
+ }
+}
+
+static int get_byte(GP_IO *io)
+{
+ uint8_t buf;
+
+ if (GP_IORead(io, &buf, 1) != 1) {
+ GP_WARN("END OF FILE REACHED");
+ return -1;
+ }
+
+ return buf;
+}
+
+struct rle {
+ int8_t op;
+ int size;
+ uint8_t val;
+};
+
+static void read_rle(GP_IO *io, struct rle *rle,
+ uint8_t *buf, unsigned int size)
+{
+ unsigned int read = 0;
+
+ while (read < size) {
+ switch (rle->op) {
+ case -128:
+ rle->op = get_byte(io);
+// fprintf(stderr, "Read command %in", rle->op);
+ break;
+ case 0 ... 127:
+ rle->size = rle->op + 1;
+// fprintf(stderr, "VERBATIM %un", rle->size);
+ while (rle->size-- && read < size)
+ buf[read++] = get_byte(io);
+ if (rle->size < 0)
+ rle->op = -128;
+ break;
+ case -127 ... -1:
+ rle->size = 1 - rle->op;
+ rle->val = get_byte(io);
+
+// fprintf(stderr, "REPEAT %u x %in", rle->size, rle->val);
+
+ while (rle->size-- && read < size)
+ buf[read++] = rle->val;
+ if (rle->size < 0)
+ rle->op = -128;
+ break;
+ }
+ }
+}
+
+/*
+ * UnPackBits RLE
+ *
+ * Data are in planar mode RRRRR... GGGGG... BBBBB... etc.
+ *
+ * TODO: Use buffered I/O
+ */
+static int psd_load_rle_rgb(GP_IO *io, GP_Context *res,
+ GP_ProgressCallback *callback)
+{
+ unsigned int x, y, c, p;
+ unsigned int chans = res->pixel_type == GP_PIXEL_RGB888 ? 3 : 4;
+ uint8_t b[res->w], *bp;
+ struct rle rle = {.op = -128};
+
+ /*
+ * Skip line byte counts
+ *
+ * Two bytes per channel per row
+ */
+ if (GP_IOSeek(io, 2 * chans * res->h, GP_IO_SEEK_CUR) == (off_t)-1) {
+ GP_DEBUG(1, "Failed to skip Line Bytes Counts");
+ return 1;
+ }
+
+ for (c = 0; c < chans; c++) {
+ switch (c) {
+ case 0:
+ p = 2;
+ break;
+ case 2:
+ p = 0;
+ break;
+ default:
+ p = c;
+ }
+
+ for (y = 0; y < res->h; y++) {
+ bp = GP_PIXEL_ADDR(res, 0, y);
+ read_rle(io, &rle, b, sizeof(b));
+
+ for (x = 0; x < res->w; x++)
+ bp[x * chans + p] = b[x];
+
+ if (GP_ProgressCallbackReport(callback, res->h * c + y,
+ res->h * chans, res->w)) {
+ GP_DEBUG(1, "Operation aborted");
+ return ECANCELED;
+ }
+ }
+ }
+
+ GP_ProgressCallbackDone(callback);
+
+ return 0;
+}
+
+static int psd_load_rle_cmyk(GP_IO *io, GP_Context *res,
+ GP_ProgressCallback *callback)
+{
+ unsigned int x, y, c;
+ uint8_t b[res->w], *bp;
+ struct rle rle = {.op = -128};
+
+ /*
+ * Skip line byte counts
+ *
+ * Two bytes per channel per row
+ */
+ if (GP_IOSeek(io, 2 * 4 * res->h, GP_IO_SEEK_CUR) == (off_t)-1) {
+ GP_DEBUG(1, "Failed to skip Line Bytes Counts");
+ return 1;
+ }
+
+ for (c = 0; c < 4; c++) {
+ for (y = 0; y < res->h; y++) {
+ bp = GP_PIXEL_ADDR(res, 0, y);
+ read_rle(io, &rle, b, sizeof(b));
+
+ for (x = 0; x < res->w; x++)
+ bp[x * 4 + c] = 255 - b[x];
+
+ if (GP_ProgressCallbackReport(callback, res->h * c + y,
+ 4 * res->h, res->w)) {
+ GP_DEBUG(1, "Operation aborted");
+ return ECANCELED;
+ }
+ }
+ }
+
+ GP_ProgressCallbackDone(callback);
+
+ return 0;
+}
+
+static GP_Context *psd_combined_image(GP_IO *io,
+ struct psd_header *header,
+ GP_ProgressCallback *callback)
+{
+ uint16_t compress;
+ GP_PixelType pixel_type = GP_PIXEL_UNKNOWN;
+
+ if (GP_IOReadB2(io, &compress)) {
+ GP_DEBUG(1, "Failed to read Combined Image compression");
+ return NULL;
+ }
+
+ GP_DEBUG(1, "Combined image compression %s (%"PRIu16")",
+ compress_method_type(compress), compress);
+
+
+ if (compress != PSD_COMPRESS_RLE) {
+ GP_DEBUG(1, "Unsupported compression");
+ errno = ENOSYS;
+ return NULL;
+ }
+
+ if (header->color_mode == PSD_RGB) {
+ switch (header->channels) {
+ case 3:
+ switch (header->depth) {
+ case 8:
+ pixel_type = GP_PIXEL_RGB888;
+ break;
+ }
+ break;
+ case 4:
+ switch (header->depth) {
+ case 8:
+ pixel_type = GP_PIXEL_RGBA8888;
+ break;
+ }
+ break;
+ }
+ }
+
+ if (header->color_mode == PSD_CMYK && header->channels == 4) {
+ switch (header->channels) {
+ case 4:
+ pixel_type = GP_PIXEL_CMYK8888;
+ break;
+ }
+ }
+
+ if (pixel_type == GP_PIXEL_UNKNOWN) {
+ GP_DEBUG(1, "Unsupported color_mode/channels/bpp combination");
+ errno = ENOSYS;
+ return NULL;
+ }
+
+ GP_Context *res = GP_ContextAlloc(header->w, header->h, pixel_type);
+
+ if (!res)
+ return NULL;
+
+ int ret;
+
+ if (pixel_type == GP_PIXEL_CMYK8888)
+ ret = psd_load_rle_cmyk(io, res, callback);
+ else
+ ret = psd_load_rle_rgb(io, res, callback);
+
+ if (ret) {
+ GP_ContextFree(res);
+ return NULL;
+ }
+
+ return res;
+}
+
+GP_Context *GP_ReadPSD(GP_IO *io, GP_ProgressCallback *callback)
+{
+ int err;
uint32_t len, size, read_size = 0;
+ struct psd_header header;
uint16_t psd_header[] = {
'8', 'B', 'P', 'S',
@@ -428,8 +677,8 @@ GP_Context *GP_ReadPSD(GP_IO *io, GP_ProgressCallback *callback)
GP_IO_END
};
- if (GP_IOReadF(io, psd_header, &channels, &h, &w, &depth,
- &color_mode, &len) != 13) {
+ if (GP_IOReadF(io, psd_header, &header.channels, &header.h, &header.w,
+ &header.depth, &header.color_mode, &len) != 13) {
GP_DEBUG(1, "Failed to read file header");
err = EIO;
goto err0;
@@ -437,18 +686,21 @@ GP_Context *GP_ReadPSD(GP_IO *io, GP_ProgressCallback *callback)
GP_DEBUG(1, "Have PSD %"PRIu32"x%"PRIu32" channels=%"PRIu16","
" bpp=%"PRIu16" color_mode=%s (%"PRIu16") "
- " color_mode_data_len=%"PRIu32, w, h, channels,
- depth, psd_color_mode_name(color_mode), color_mode, len);
+ " color_mode_data_len=%"PRIu32, header.w, header.h,
+ header.channels, header.depth,
+ psd_color_mode_name(header.color_mode), header.color_mode, len);
- switch (color_mode) {
+ switch (header.color_mode) {
case PSD_INDEXED:
case PSD_DUOTONE:
break;
default:
- if (len)
+ if (len) {
GP_WARN("Color mode_mode_data_len != 0 (is %"PRIu32")"
"for %s (%"PRIu16")", len,
- psd_color_mode_name(color_mode), color_mode);
+ psd_color_mode_name(header.color_mode),
+ header.color_mode);
+ }
}
/* Seek after the color mode data */
@@ -464,20 +716,38 @@ GP_Context *GP_ReadPSD(GP_IO *io, GP_ProgressCallback *callback)
GP_DEBUG(1, "Image Resource Section length is %u", len);
- GP_Context *res = NULL;
+ GP_Context *thumbnail = NULL;
do {
- size = psd_next_img_res_block(io, &res, callback);
+ size = psd_next_img_res_block(io, &thumbnail, callback);
if (size == 0)
- return res;
+ return thumbnail;
read_size += size;
- // GP_DEBUG(1, "Read size %u", read_size);
} while (read_size < len);
- if (res)
- return res;
+ /* Skip Layer and Mask information */
+ if (GP_IOReadB4(io, &size)) {
+ GP_DEBUG(1, "Failed to read Layer and Mask Section size");
+ goto end;
+ }
+
+ if (GP_IOSeek(io, size, GP_IO_SEEK_CUR) == (off_t)-1) {
+ GP_DEBUG(1, "Failed to seek to Image Data Section");
+ goto end;
+ }
+
+ GP_Context *combined = psd_combined_image(io, &header, callback);
+
+ if (combined) {
+ GP_ContextFree(thumbnail);
+ return combined;
+ }
+
+end:
+ if (thumbnail)
+ return thumbnail;
errno = ENOSYS;
return NULL;
-----------------------------------------------------------------------
Summary of changes:
libs/loaders/GP_PSD.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
repo.or.cz automatic notification. Contact project admin jiri.bluebear.dluhos(a)gmail.com
if you want to unsubscribe, or site admin admin(a)repo.or.cz if you receive
no reply.
--
gfxprim.git ("A simple 2D graphics library with emphasis on correctness and well-defined operation.")
1
0
16 Feb '14
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project gfxprim.git.
The branch, master has been updated
via 18234b50ce20e3bcbbf149ff08e8dbc08bbdc510 (commit)
via a1f541ecab7bf6966e6c6a8c22ff25d76739c1a0 (commit)
via a9e9ee0865c393f72255f800a89fd773c4c651ed (commit)
from 8acf1ad51701082ab6217611cfb4ea7e7c7cf57d (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
http://repo.or.cz/w/gfxprim.git/commit/18234b50ce20e3bcbbf149ff08e8dbc08bbd…
commit 18234b50ce20e3bcbbf149ff08e8dbc08bbdc510
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Sun Feb 16 19:13:57 2014 +0100
loaders: PSD: Work on combined image loading.
Works for 8-bit RGB, RGBA and CMYK for now.
Signed-off-by: Cyril Hrubis <metan(a)ucw.cz>
diff --git a/libs/loaders/GP_PSD.c b/libs/loaders/GP_PSD.c
index 785f4f55..c42b5022 100644
--- a/libs/loaders/GP_PSD.c
+++ b/libs/loaders/GP_PSD.c
@@ -35,6 +35,7 @@
#include "core/GP_Debug.h"
#include "core/GP_Common.h"
+#include "core/GP_GetPutPixel.h"
#include "GP_JPG.h"
#include "GP_PSD.h"
@@ -351,7 +352,6 @@ static unsigned int psd_next_img_res_block(GP_IO *io, GP_Context **res,
prev = GP_IOTell(io);
*res = psd_thumbnail50(io, res_size, callback);
after = GP_IOTell(io);
- GP_DEBUG(1, "PREV %li after %li diff %li size %u", prev, after, after - prev, seek_size);
seek_size -= (after - prev);
break;
case PSD_VERSION_INFO:
@@ -405,15 +405,264 @@ static const char *psd_color_mode_name(uint16_t color_mode)
}
}
-GP_Context *GP_ReadPSD(GP_IO *io, GP_ProgressCallback *callback)
-{
- int err;
+enum compress_method {
+ PSD_COMPRESS_RAW = 0,
+ PSD_COMPRESS_RLE = 1,
+ PSD_COMPRESS_ZIP_NP = 2,
+ PSD_COMPRESS_ZIP_WP = 3,
+};
+
+struct psd_header {
uint32_t w;
uint32_t h;
uint16_t depth;
uint16_t channels;
uint16_t color_mode;
+};
+
+static const char *compress_method_type(uint16_t compress)
+{
+ switch (compress) {
+ case PSD_COMPRESS_RAW:
+ return "Raw";
+ case PSD_COMPRESS_RLE:
+ return "RLE";
+ case PSD_COMPRESS_ZIP_NP:
+ return "ZIP (no prediction)";
+ case PSD_COMPRESS_ZIP_WP:
+ return "ZIP (with prediction)";
+ default:
+ return "Unknown";
+ }
+}
+
+static int get_byte(GP_IO *io)
+{
+ uint8_t buf;
+
+ if (GP_IORead(io, &buf, 1) != 1) {
+ GP_WARN("END OF FILE REACHED");
+ return -1;
+ }
+
+ return buf;
+}
+
+struct rle {
+ int8_t op;
+ int size;
+ uint8_t val;
+};
+
+static void read_rle(GP_IO *io, struct rle *rle,
+ uint8_t *buf, unsigned int size)
+{
+ unsigned int read = 0;
+
+ while (read < size) {
+ switch (rle->op) {
+ case -128:
+ rle->op = get_byte(io);
+// fprintf(stderr, "Read command %in", rle->op);
+ break;
+ case 0 ... 127:
+ rle->size = rle->op + 1;
+// fprintf(stderr, "VERBATIM %un", rle->size);
+ while (rle->size-- && read < size)
+ buf[read++] = get_byte(io);
+ if (rle->size < 0)
+ rle->op = -128;
+ break;
+ case -127 ... -1:
+ rle->size = 1 - rle->op;
+ rle->val = get_byte(io);
+
+// fprintf(stderr, "REPEAT %u x %in", rle->size, rle->val);
+
+ while (rle->size-- && read < size)
+ buf[read++] = rle->val;
+ if (rle->size < 0)
+ rle->op = -128;
+ break;
+ }
+ }
+}
+
+/*
+ * UnPackBits RLE
+ *
+ * Data are in planar mode RRRRR... GGGGG... BBBBB... etc.
+ *
+ * TODO: Use buffered I/O
+ */
+static int psd_load_rle_rgb(GP_IO *io, GP_Context *res,
+ GP_ProgressCallback *callback)
+{
+ unsigned int x, y, c, p;
+ unsigned int chans = res->pixel_type == GP_PIXEL_RGB888 ? 3 : 4;
+ uint8_t b[res->w], *bp;
+ struct rle rle = {.op = -128};
+
+ /*
+ * Skip line byte counts
+ *
+ * Two bytes per channel per row
+ */
+ if (GP_IOSeek(io, 2 * chans * res->h, GP_IO_SEEK_CUR) == (off_t)-1) {
+ GP_DEBUG(1, "Failed to skip Line Bytes Counts");
+ return 1;
+ }
+
+ for (c = 0; c < chans; c++) {
+ switch (c) {
+ case 0:
+ p = 2;
+ break;
+ case 2:
+ p = 0;
+ break;
+ default:
+ p = c;
+ }
+
+ for (y = 0; y < res->h; y++) {
+ bp = GP_PIXEL_ADDR(res, 0, y);
+ read_rle(io, &rle, b, sizeof(b));
+
+ for (x = 0; x < res->w; x++)
+ bp[x * chans + p] = 255 - b[x];
+
+ if (GP_ProgressCallbackReport(callback, res->h * c + y,
+ res->h * chans, res->w)) {
+ GP_DEBUG(1, "Operation aborted");
+ return ECANCELED;
+ }
+ }
+ }
+
+ GP_ProgressCallbackDone(callback);
+
+ return 0;
+}
+
+static int psd_load_rle_cmyk(GP_IO *io, GP_Context *res,
+ GP_ProgressCallback *callback)
+{
+ unsigned int x, y, c;
+ uint8_t b[res->w], *bp;
+ struct rle rle = {.op = -128};
+
+ /*
+ * Skip line byte counts
+ *
+ * Two bytes per channel per row
+ */
+ if (GP_IOSeek(io, 2 * 4 * res->h, GP_IO_SEEK_CUR) == (off_t)-1) {
+ GP_DEBUG(1, "Failed to skip Line Bytes Counts");
+ return 1;
+ }
+
+ for (c = 0; c < 4; c++) {
+ for (y = 0; y < res->h; y++) {
+ bp = GP_PIXEL_ADDR(res, 0, y);
+ read_rle(io, &rle, b, sizeof(b));
+
+ for (x = 0; x < res->w; x++)
+ bp[x * 4 + c] = 255 - b[x];
+
+ if (GP_ProgressCallbackReport(callback, res->h * c + y,
+ 4 * res->h, res->w)) {
+ GP_DEBUG(1, "Operation aborted");
+ return ECANCELED;
+ }
+ }
+ }
+
+ GP_ProgressCallbackDone(callback);
+
+ return 0;
+}
+
+static GP_Context *psd_combined_image(GP_IO *io,
+ struct psd_header *header,
+ GP_ProgressCallback *callback)
+{
+ uint16_t compress;
+ GP_PixelType pixel_type = GP_PIXEL_UNKNOWN;
+
+ if (GP_IOReadB2(io, &compress)) {
+ GP_DEBUG(1, "Failed to read Combined Image compression");
+ return NULL;
+ }
+
+ GP_DEBUG(1, "Combined image compression %s (%"PRIu16")",
+ compress_method_type(compress), compress);
+
+
+ if (compress != PSD_COMPRESS_RLE) {
+ GP_DEBUG(1, "Unsupported compression");
+ errno = ENOSYS;
+ return NULL;
+ }
+
+ if (header->color_mode == PSD_RGB) {
+ switch (header->channels) {
+ case 3:
+ switch (header->depth) {
+ case 8:
+ pixel_type = GP_PIXEL_RGB888;
+ break;
+ }
+ break;
+ case 4:
+ switch (header->depth) {
+ case 8:
+ pixel_type = GP_PIXEL_RGBA8888;
+ break;
+ }
+ break;
+ }
+ }
+
+ if (header->color_mode == PSD_CMYK && header->channels == 4) {
+ switch (header->channels) {
+ case 4:
+ pixel_type = GP_PIXEL_CMYK8888;
+ break;
+ }
+ }
+
+ if (pixel_type == GP_PIXEL_UNKNOWN) {
+ GP_DEBUG(1, "Unsupported color_mode/channels/bpp combination");
+ errno = ENOSYS;
+ return NULL;
+ }
+
+ GP_Context *res = GP_ContextAlloc(header->w, header->h, pixel_type);
+
+ if (!res)
+ return NULL;
+
+ int ret;
+
+ if (pixel_type == GP_PIXEL_CMYK8888)
+ ret = psd_load_rle_cmyk(io, res, callback);
+ else
+ ret = psd_load_rle_rgb(io, res, callback);
+
+ if (ret) {
+ GP_ContextFree(res);
+ return NULL;
+ }
+
+ return res;
+}
+
+GP_Context *GP_ReadPSD(GP_IO *io, GP_ProgressCallback *callback)
+{
+ int err;
uint32_t len, size, read_size = 0;
+ struct psd_header header;
uint16_t psd_header[] = {
'8', 'B', 'P', 'S',
@@ -428,8 +677,8 @@ GP_Context *GP_ReadPSD(GP_IO *io, GP_ProgressCallback *callback)
GP_IO_END
};
- if (GP_IOReadF(io, psd_header, &channels, &h, &w, &depth,
- &color_mode, &len) != 13) {
+ if (GP_IOReadF(io, psd_header, &header.channels, &header.h, &header.w,
+ &header.depth, &header.color_mode, &len) != 13) {
GP_DEBUG(1, "Failed to read file header");
err = EIO;
goto err0;
@@ -437,18 +686,21 @@ GP_Context *GP_ReadPSD(GP_IO *io, GP_ProgressCallback *callback)
GP_DEBUG(1, "Have PSD %"PRIu32"x%"PRIu32" channels=%"PRIu16","
" bpp=%"PRIu16" color_mode=%s (%"PRIu16") "
- " color_mode_data_len=%"PRIu32, w, h, channels,
- depth, psd_color_mode_name(color_mode), color_mode, len);
+ " color_mode_data_len=%"PRIu32, header.w, header.h,
+ header.channels, header.depth,
+ psd_color_mode_name(header.color_mode), header.color_mode, len);
- switch (color_mode) {
+ switch (header.color_mode) {
case PSD_INDEXED:
case PSD_DUOTONE:
break;
default:
- if (len)
+ if (len) {
GP_WARN("Color mode_mode_data_len != 0 (is %"PRIu32")"
"for %s (%"PRIu16")", len,
- psd_color_mode_name(color_mode), color_mode);
+ psd_color_mode_name(header.color_mode),
+ header.color_mode);
+ }
}
/* Seek after the color mode data */
@@ -464,20 +716,38 @@ GP_Context *GP_ReadPSD(GP_IO *io, GP_ProgressCallback *callback)
GP_DEBUG(1, "Image Resource Section length is %u", len);
- GP_Context *res = NULL;
+ GP_Context *thumbnail = NULL;
do {
- size = psd_next_img_res_block(io, &res, callback);
+ size = psd_next_img_res_block(io, &thumbnail, callback);
if (size == 0)
- return res;
+ return thumbnail;
read_size += size;
- // GP_DEBUG(1, "Read size %u", read_size);
} while (read_size < len);
- if (res)
- return res;
+ /* Skip Layer and Mask information */
+ if (GP_IOReadB4(io, &size)) {
+ GP_DEBUG(1, "Failed to read Layer and Mask Section size");
+ goto end;
+ }
+
+ if (GP_IOSeek(io, size, GP_IO_SEEK_CUR) == (off_t)-1) {
+ GP_DEBUG(1, "Failed to seek to Image Data Section");
+ goto end;
+ }
+
+ GP_Context *combined = psd_combined_image(io, &header, callback);
+
+ if (combined) {
+ GP_ContextFree(thumbnail);
+ return combined;
+ }
+
+end:
+ if (thumbnail)
+ return thumbnail;
errno = ENOSYS;
return NULL;
http://repo.or.cz/w/gfxprim.git/commit/a1f541ecab7bf6966e6c6a8c22ff25d76739…
commit a1f541ecab7bf6966e6c6a8c22ff25d76739c1a0
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Sun Feb 16 19:12:57 2014 +0100
build: Update loader symbols.
Signed-off-by: Cyril Hrubis <metan(a)ucw.cz>
diff --git a/build/syms/Loaders_symbols.txt b/build/syms/Loaders_symbols.txt
index a65f6c78..dfbb1e54 100644
--- a/build/syms/Loaders_symbols.txt
+++ b/build/syms/Loaders_symbols.txt
@@ -60,6 +60,10 @@ GP_ReadPCX
GP_LoadPCX
GP_MatchPCX
+GP_ReadPSD
+GP_LoadPSD
+GP_MatchPSD
+
GP_SaveTmpFile
GP_LoadTmpFile
@@ -98,7 +102,10 @@ GP_LineConvertGet
GP_IOFile
GP_IOMem
+GP_IOSubIO
GP_IOMark
GP_IOSize
GP_IOFill
GP_IOReadF
+GP_IOReadB2
+GP_IOReadB4
http://repo.or.cz/w/gfxprim.git/commit/a9e9ee0865c393f72255f800a89fd773c4c6…
commit a9e9ee0865c393f72255f800a89fd773c4c651ed
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Sun Feb 16 19:11:03 2014 +0100
loaders: IO: Add GP_IOReadB2
Signed-off-by: Cyril Hrubis <metan(a)ucw.cz>
diff --git a/include/loaders/GP_IO.h b/include/loaders/GP_IO.h
index 22878c83..6947e3b3 100644
--- a/include/loaders/GP_IO.h
+++ b/include/loaders/GP_IO.h
@@ -178,6 +178,8 @@ int GP_IOReadF(GP_IO *self, uint16_t *types, ...);
*/
int GP_IOReadB4(GP_IO *io, uint32_t *val);
+int GP_IOReadB2(GP_IO *io, uint16_t *val);
+
enum GP_IOFileMode {
GP_IO_RDONLY = 0x00,
GP_IO_WRONLY = 0x01,
diff --git a/libs/loaders/GP_IO.c b/libs/loaders/GP_IO.c
index e036bb7c..0b77bd5c 100644
--- a/libs/loaders/GP_IO.c
+++ b/libs/loaders/GP_IO.c
@@ -621,3 +621,13 @@ int GP_IOReadB4(GP_IO *io, uint32_t *val)
return GP_IOReadF(io, desc, val) != 1;
}
+
+int GP_IOReadB2(GP_IO *io, uint16_t *val)
+{
+ uint16_t desc[] = {
+ GP_IO_B2,
+ GP_IO_END
+ };
+
+ return GP_IOReadF(io, desc, val) != 1;
+}
-----------------------------------------------------------------------
Summary of changes:
build/syms/Loaders_symbols.txt | 7 +
include/loaders/GP_IO.h | 2 +
libs/loaders/GP_IO.c | 10 ++
libs/loaders/GP_PSD.c | 304 +++++++++++++++++++++++++++++++++++++---
4 files changed, 306 insertions(+), 17 deletions(-)
repo.or.cz automatic notification. Contact project admin jiri.bluebear.dluhos(a)gmail.com
if you want to unsubscribe, or site admin admin(a)repo.or.cz if you receive
no reply.
--
gfxprim.git ("A simple 2D graphics library with emphasis on correctness and well-defined operation.")
1
0
16 Feb '14
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project gfxprim.git.
The branch, master has been updated
via 8acf1ad51701082ab6217611cfb4ea7e7c7cf57d (commit)
via aac23dd1d24763f03c109e751d0305fa08d38248 (commit)
from af257881668f5639c0e0167e6674e34f979b9a18 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
http://repo.or.cz/w/gfxprim.git/commit/8acf1ad51701082ab6217611cfb4ea7e7c7c…
commit 8acf1ad51701082ab6217611cfb4ea7e7c7cf57d
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Sun Feb 16 18:06:24 2014 +0100
loaders: PSD: More work on the PSD loaders.
Signed-off-by: Cyril Hrubis <metan(a)ucw.cz>
diff --git a/libs/loaders/GP_PSD.c b/libs/loaders/GP_PSD.c
index 3b74a9c9..785f4f55 100644
--- a/libs/loaders/GP_PSD.c
+++ b/libs/loaders/GP_PSD.c
@@ -47,10 +47,141 @@ int GP_MatchPSD(const void *buf)
}
enum psd_img_res_id {
- PSD_THUMBNAIL_RES40 = 1033,
- PSD_THUMBNAIL_RES50 = 1036,
+ PSD_RESOLUTION_INFO = 1005,
+ PSD_ALPHA_CHANNELS_NAMES = 1006,
+ PSD_DISPLAY_INFO0 = 1007,
+ PSD_BACKGROUND_COLOR = 1010,
+ PSD_PRINT_FLAGS = 1011,
+ PSD_COLOR_HALFTONING_INFO = 1013,
+ PSD_COLOR_TRANSFER_FUNC = 1016,
+ PSD_LAYER_STATE_INFO = 1024,
+ PSD_WORKING_PATH = 1025,
+ PSD_LAYERS_GROUP_INFO = 1026,
+ PSD_IPTC_NAA_REC = 1028,
+ PSD_GRID_AND_GUIDES = 1032,
+ PSD_THUMBNAIL_RES40 = 1033,
+ PSD_COPYRIGHT_FLAG = 1034,
+ PSD_THUMBNAIL_RES50 = 1036,
+ PSD_GLOBAL_ANGLE = 1037,
+ PSD_ICC_PROFILE = 1039,
+ PSD_ICC_UNTAGGED_PROFILE = 1041,
+ PSD_ID_SEED = 1044,
+ PSD_UNICODE_ALPHA_NAMES = 1045,
+ PSD_GLOBAL_ALTITUDE = 1049,
+ PSD_SLICES = 1050,
+ PSD_ALPHA_IDENTIFIERS = 1053,
+ PSD_URL_LIST = 1054,
+ PSD_VERSION_INFO = 1057,
+ PSD_EXIF1 = 1058,
+ PSD_EXIF3 = 1059,
+ PSD_XML_METADATA = 1060,
+ PSD_CAPTION_DIGETST = 1061,
+ PSD_PRINT_SCALE = 1062,
+ PSD_PIXEL_ASPECT_RATIO = 1064,
+ PSD_LAYER_SELECTION_IDS = 1069,
+ PSD_PRINT_INFO_CS2 = 1071,
+ PSD_LAYER_GROUPS = 1072,
+ PSD_TIMELINE_INFO = 1075,
+ PSD_SHEET_DISCLOSURE = 1076,
+ PSD_DISPLAY_INFO = 1077,
+ PSD_ONION_SKINS = 1078,
+ PSD_PRINT_INFO_CS5 = 1082,
+ PSD_PRINT_STYLE = 1083,
+ PSD_PRINT_FLAGS_INFO = 10000,
};
+static const char *psd_img_res_id_name(uint16_t id)
+{
+ switch (id) {
+ case PSD_RESOLUTION_INFO:
+ return "Resolution Info";
+ case PSD_ALPHA_CHANNELS_NAMES:
+ return "Alpha Channels Names";
+ case PSD_DISPLAY_INFO0:
+ return "Display Info (Obsolete)";
+ case PSD_BACKGROUND_COLOR:
+ return "Background Color";
+ case PSD_PRINT_FLAGS:
+ return "Print Flags";
+ case PSD_COLOR_HALFTONING_INFO:
+ return "Color Halftoning Info";
+ case PSD_COLOR_TRANSFER_FUNC:
+ return "Color Transfer Function";
+ case PSD_LAYER_STATE_INFO:
+ return "Layer State Info";
+ case PSD_WORKING_PATH:
+ return "Working Path";
+ case PSD_LAYERS_GROUP_INFO:
+ return "Layers Group Info";
+ case PSD_IPTC_NAA_REC:
+ return "IPTC-NAA Record";
+ case PSD_GRID_AND_GUIDES:
+ return "Grid and Guides";
+ case PSD_THUMBNAIL_RES40:
+ return "Thumbnail 4.0";
+ case PSD_COPYRIGHT_FLAG:
+ return "Copyright Flag";
+ case PSD_THUMBNAIL_RES50:
+ return "Thumbnail 5.0+";
+ case PSD_GLOBAL_ANGLE:
+ return "Global Angle";
+ case PSD_ICC_PROFILE:
+ return "ICC Profile";
+ case PSD_ICC_UNTAGGED_PROFILE:
+ return "ICC Untagged Profile";
+ case PSD_ID_SEED:
+ return "ID Seed";
+ case PSD_UNICODE_ALPHA_NAMES:
+ return "Unicode Alpha Names";
+ case PSD_GLOBAL_ALTITUDE:
+ return "Global Altitude";
+ case PSD_SLICES:
+ return "Slices";
+ case PSD_ALPHA_IDENTIFIERS:
+ return "Alpha Identifiers";
+ case PSD_URL_LIST:
+ return "URL List";
+ case PSD_VERSION_INFO:
+ return "Version Info";
+ case PSD_EXIF1:
+ return "Exif data 1";
+ case PSD_EXIF3:
+ return "Exif data 3";
+ case PSD_XML_METADATA:
+ return "XML Metadata";
+ case PSD_CAPTION_DIGETST:
+ return "Caption Digest";
+ case PSD_PRINT_SCALE:
+ return "Print Scale";
+ case PSD_PIXEL_ASPECT_RATIO:
+ return "Pixel Aspect Ratio";
+ case PSD_LAYER_SELECTION_IDS:
+ return "Selectin IDs";
+ case PSD_PRINT_INFO_CS2:
+ return "Print Info CS2";
+ case PSD_LAYER_GROUPS:
+ return "Layer Groups";
+ case PSD_TIMELINE_INFO:
+ return "Timeline Info";
+ case PSD_SHEET_DISCLOSURE:
+ return "Sheet Disclosure";
+ case PSD_DISPLAY_INFO:
+ return "Display Info";
+ case PSD_ONION_SKINS:
+ return "Onion Skins";
+ case PSD_PRINT_INFO_CS5:
+ return "Print Info CS5";
+ case PSD_PRINT_STYLE:
+ return "Print Scale";
+ case 4000 ... 4999:
+ return "Plugin Resource";
+ case PSD_PRINT_FLAGS_INFO:
+ return "Print Flags Information";
+ default:
+ return "Unknown";
+ }
+}
+
enum thumbnail_fmt {
PSD_RAW_RGB = 0,
PSD_JPG_RGB = 1,
@@ -68,10 +199,15 @@ static const char *thumbnail_fmt_name(uint16_t fmt)
}
}
-static GP_Context *psd_thumbnail50(GP_IO *io, GP_ProgressCallback *callback)
+#define THUMBNAIL50_HSIZE 28
+
+static GP_Context *psd_thumbnail50(GP_IO *io, size_t size,
+ GP_ProgressCallback *callback)
{
uint32_t fmt, w, h;
uint16_t bpp, nr_planes;
+ GP_Context *res;
+ int err;
uint16_t res_thumbnail_header[] = {
GP_IO_B4, /* Format */
@@ -95,7 +231,7 @@ static GP_Context *psd_thumbnail50(GP_IO *io, GP_ProgressCallback *callback)
return NULL;
}
- GP_DEBUG(1, "%"PRIu32"x%"PRIu32" format=%s (%"PRIu16") bpp=%"PRIu16
+ GP_DEBUG(3, "%"PRIu32"x%"PRIu32" format=%s (%"PRIu16") bpp=%"PRIu16
" nr_planes=%"PRIu16, w, h, thumbnail_fmt_name(fmt), fmt,
bpp, nr_planes);
@@ -104,14 +240,89 @@ static GP_Context *psd_thumbnail50(GP_IO *io, GP_ProgressCallback *callback)
return NULL;
}
- return GP_ReadJPG(io, callback);
+ if (size < THUMBNAIL50_HSIZE) {
+ GP_WARN("Negative thumbnail resource size");
+ errno = EINVAL;
+ return NULL;
+ }
+
+ GP_IO *sub_io = GP_IOSubIO(io, size - THUMBNAIL50_HSIZE);
+
+ if (!sub_io)
+ return NULL;
+
+ res = GP_ReadJPG(sub_io, callback);
+ err = errno;
+ GP_IOClose(sub_io);
+ errno = err;
+
+ return res;
+}
+
+static unsigned int read_unicode_string(GP_IO *io, char *str,
+ unsigned int size)
+{
+ uint8_t buf[size * 2];
+ unsigned int i;
+
+ if (GP_IOFill(io, buf, size * 2)) {
+ GP_DEBUG(1, "Failed to read unicode string");
+ return 0;
+ }
+
+ for (i = 0; i < size; i++) {
+ if (buf[i * 2])
+ str[i] = '?';
+ else
+ str[i] = buf[i * 2 + 1];
+ }
+
+ str[size] = 0;
+
+ return size * 2;
+}
+
+static void psd_read_version_info(GP_IO *io)
+{
+ unsigned int size = 13;
+ uint32_t version, str_size;
+
+ uint16_t version_data[] = {
+ GP_IO_B4, /* Version */
+ GP_IO_I1, /* hasRealMergedData ??? */
+ GP_IO_B4, /* Unicode version string size */
+ GP_IO_END
+ };
+
+ if (GP_IOReadF(io, version_data, &version, &str_size) != 3) {
+ GP_DEBUG(1, "Failed to read version header");
+ return;
+ }
+
+ //TODO: Check str size is small
+ char str[str_size + 1];
+
+ size += read_unicode_string(io, str, str_size);
+
+ if (GP_IOReadB4(io, &str_size)) {
+ GP_DEBUG(1, "Failed to read string size");
+ return;
+ }
+
+ char reader[str_size + 1];
+
+ size += read_unicode_string(io, reader, str_size);
+
+ GP_DEBUG(3, "Version %"PRIu32" writer='%s' reader='%s'",
+ version, str, reader);
}
static unsigned int psd_next_img_res_block(GP_IO *io, GP_Context **res,
GP_ProgressCallback *callback)
{
uint16_t res_id;
- uint32_t res_size;
+ uint32_t res_size, seek_size;
+ off_t prev, after;
uint16_t res_block_header[] = {
'8', 'B', 'I', 'M', /* Image resource block signature */
@@ -127,26 +338,36 @@ static unsigned int psd_next_img_res_block(GP_IO *io, GP_Context **res,
return 0;
}
- GP_DEBUG(1, "Image resource id=%"PRIu16" size=%"PRIu32,
- res_id, res_size);
+ GP_DEBUG(2, "Image resource id=%-5"PRIu16" size=%-8"PRIu32" (%s)",
+ res_id, res_size, psd_img_res_id_name(res_id));
+
+ seek_size = res_size = GP_ALIGN2(res_size);
switch (res_id) {
case PSD_THUMBNAIL_RES40:
GP_DEBUG(1, "Unsupported thumbnail version 4.0");
break;
case PSD_THUMBNAIL_RES50:
- *res = psd_thumbnail50(io, callback);
- return 0;
+ prev = GP_IOTell(io);
+ *res = psd_thumbnail50(io, res_size, callback);
+ after = GP_IOTell(io);
+ GP_DEBUG(1, "PREV %li after %li diff %li size %u", prev, after, after - prev, seek_size);
+ seek_size -= (after - prev);
+ break;
+ case PSD_VERSION_INFO:
+ prev = GP_IOTell(io);
+ psd_read_version_info(io);
+ after = GP_IOTell(io);
+ seek_size -= (after - prev);
+ break;
}
- res_size = GP_ALIGN2(res_size);
-
- if (GP_IOSeek(io, res_size, GP_IO_SEEK_CUR) == (off_t)-1) {
+ if (GP_IOSeek(io, seek_size, GP_IO_SEEK_CUR) == (off_t)-1) {
GP_DEBUG(1, "Failed skip image resource");
return 0;
}
- return res_size + 10;
+ return res_size + 12;
}
enum psd_color_mode {
@@ -241,19 +462,23 @@ GP_Context *GP_ReadPSD(GP_IO *io, GP_ProgressCallback *callback)
return NULL;
}
- GP_DEBUG(1, "Image Resource Section length is %x", len);
+ GP_DEBUG(1, "Image Resource Section length is %u", len);
GP_Context *res = NULL;
do {
size = psd_next_img_res_block(io, &res, callback);
- if (!size)
+ if (size == 0)
return res;
read_size += size;
+ // GP_DEBUG(1, "Read size %u", read_size);
} while (read_size < len);
+ if (res)
+ return res;
+
errno = ENOSYS;
return NULL;
err0:
http://repo.or.cz/w/gfxprim.git/commit/aac23dd1d24763f03c109e751d0305fa08d3…
commit aac23dd1d24763f03c109e751d0305fa08d38248
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Sun Feb 16 18:03:12 2014 +0100
loaders: Add SubIO().
SubIO is an interface to create an I/O (given a parent I/O) that is
restricted to a continuous I/O subinterval.
TODO: Docs + tests.
Signed-off-by: Cyril Hrubis <metan(a)ucw.cz>
diff --git a/include/loaders/GP_IO.h b/include/loaders/GP_IO.h
index c10befe3..22878c83 100644
--- a/include/loaders/GP_IO.h
+++ b/include/loaders/GP_IO.h
@@ -196,4 +196,17 @@ GP_IO *GP_IOFile(const char *path, enum GP_IOFileMode mode);
*/
GP_IO *GP_IOMem(void *buf, size_t size, void (*free)(void *));
+/*
+ * Create a sub I/O from an I/O.
+ *
+ * The sub I/O starts at current offset in the parent I/O (which is also point
+ * where GP_IOTell() for the new I/O will return zero) and continues for
+ * maximally size bytes in the parent I/O. Reads at the end of the Sub I/O will
+ * be truncated to the.
+ *
+ * WARNING: If you combine reading/writing in the Sub I/O and parent I/O the
+ * result is undefined.
+ */
+GP_IO *GP_IOSubIO(GP_IO *pio, size_t size);
+
#endif /* LOADERS_GP_IO_H */
diff --git a/libs/loaders/GP_IO.c b/libs/loaders/GP_IO.c
index 46009893..e036bb7c 100644
--- a/libs/loaders/GP_IO.c
+++ b/libs/loaders/GP_IO.c
@@ -194,6 +194,7 @@ static off_t mem_seek(GP_IO *io, off_t off, enum GP_IOWhence whence)
break;
default:
GP_WARN("Invalid whence");
+ errno = EINVAL;
return (off_t)-1;
}
@@ -244,6 +245,134 @@ GP_IO *GP_IOMem(void *buf, size_t size, void (*free)(void *))
return io;
}
+struct sub_io {
+ /* Points to parent IO */
+ off_t start;
+ off_t end;
+ off_t cur;
+
+ GP_IO *io;
+};
+
+static ssize_t sub_read(GP_IO *io, void *buf, size_t size)
+{
+ struct sub_io *sub_io = GP_IO_PRIV(io);
+
+ if (sub_io->cur > sub_io->end) {
+ GP_BUG("Current offset (%zi) is after the end (%zi)",
+ sub_io->cur, sub_io->end);
+ errno = EINVAL;
+ return 0;
+ }
+
+ size_t io_size = sub_io->end - sub_io->cur;
+
+ size = GP_MIN(size, io_size);
+
+ if (size == 0)
+ return 0;
+
+ ssize_t ret = GP_IORead(sub_io->io, buf, size);
+
+ if (ret < 0)
+ return ret;
+
+ sub_io->cur += ret;
+ return ret;
+}
+
+static off_t sub_seek(GP_IO *io, off_t off, enum GP_IOWhence whence)
+{
+ struct sub_io *sub_io = GP_IO_PRIV(io);
+ off_t io_size, ret, poff;
+
+ switch (whence) {
+ case GP_IO_SEEK_CUR:
+ //TODO: Overflow
+ poff = sub_io->cur + off;
+
+ if (poff < sub_io->start || poff > sub_io->end) {
+ errno = EINVAL;
+ return (off_t)-1;
+ }
+
+ ret = GP_IOSeek(sub_io->io, off, whence);
+ break;
+ case GP_IO_SEEK_SET:
+ io_size = sub_io->end - sub_io->start;
+
+ if (off > io_size || off < 0) {
+ errno = EINVAL;
+ return (off_t)-1;
+ }
+
+ ret = GP_IOSeek(sub_io->io, sub_io->start + off, whence);
+ break;
+ case GP_IO_SEEK_END:
+ io_size = sub_io->end - sub_io->start;
+
+ if (off + io_size < 0 || off > 0) {
+ errno = EINVAL;
+ return (off_t)-1;
+ }
+
+ ret = GP_IOSeek(sub_io->io, sub_io->end + off, whence);
+ break;
+ default:
+ GP_WARN("Invalid whence");
+ errno = EINVAL;
+ return (off_t)-1;
+ }
+
+ if (ret == (off_t)-1)
+ return (off_t)-1;
+
+ sub_io->cur = ret;
+
+ return sub_io->cur - sub_io->start;
+}
+
+static int sub_close(GP_IO *io)
+{
+ struct sub_io *sub_io = GP_IO_PRIV(io);
+
+ GP_DEBUG(1, "Closing SubIO (from %p)", sub_io->io);
+
+ free(io);
+
+ return 0;
+}
+
+GP_IO *GP_IOSubIO(GP_IO *pio, size_t size)
+{
+ GP_IO *io;
+ struct sub_io *sub_io;
+
+ GP_DEBUG(1, "Creating SubIO (from %p) size=%zu", pio, size);
+
+ io = malloc(sizeof(GP_IO) + sizeof(*sub_io));
+
+ if (!io) {
+ GP_DEBUG(1, "Malloc failed :(");
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ io->Read = sub_read;
+ io->Seek = sub_seek;
+ io->Close = sub_close;
+ io->Write = NULL;
+
+ sub_io = GP_IO_PRIV(io);
+ sub_io->cur = sub_io->start = GP_IOTell(pio);
+
+ //TODO: Overflow
+ sub_io->end = sub_io->start + size;
+ sub_io->io = pio;
+
+ return io;
+}
+
int GP_IOMark(GP_IO *self, enum GP_IOMarkTypes type)
{
off_t ret;
-----------------------------------------------------------------------
Summary of changes:
include/loaders/GP_IO.h | 13 +++
libs/loaders/GP_IO.c | 129 ++++++++++++++++++++++++
libs/loaders/GP_PSD.c | 257 ++++++++++++++++++++++++++++++++++++++++++++---
3 files changed, 383 insertions(+), 16 deletions(-)
repo.or.cz automatic notification. Contact project admin jiri.bluebear.dluhos(a)gmail.com
if you want to unsubscribe, or site admin admin(a)repo.or.cz if you receive
no reply.
--
gfxprim.git ("A simple 2D graphics library with emphasis on correctness and well-defined operation.")
1
0
16 Feb '14
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project gfxprim.git.
The branch, master has been updated
via af257881668f5639c0e0167e6674e34f979b9a18 (commit)
via c39571abe960d7892e9eb06735bfbb49d74352ef (commit)
via 27ff06feef1cd3abdbca1ee6267f9e2febe43d6e (commit)
via 70edd6e78312f8357776c81f6b5124a96233b5b2 (commit)
from 4a428416a87a6b7b1290c8e89d3fc8cfc83fe188 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
http://repo.or.cz/w/gfxprim.git/commit/af257881668f5639c0e0167e6674e34f979b…
commit af257881668f5639c0e0167e6674e34f979b9a18
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Sun Feb 16 00:01:07 2014 +0100
loaders: Add PSD thumbnail loader
Signed-off-by: Cyril Hrubis <metan(a)ucw.cz>
diff --git a/include/loaders/GP_IO.h b/include/loaders/GP_IO.h
index fa1046f8..c10befe3 100644
--- a/include/loaders/GP_IO.h
+++ b/include/loaders/GP_IO.h
@@ -155,6 +155,16 @@ enum GP_IOReadFTypes {
GP_IO_I2 = GP_IO_IGN | 2,
GP_IO_I3 = GP_IO_IGN | 3,
GP_IO_I4 = GP_IO_IGN | 4,
+ /*
+ * Photoshop Pascal string
+ *
+ * first byte stores size and string is padded to even number bytes.
+ *
+ * The lower half stores passed buffer size.
+ *
+ * TODO: Unfinished
+ */
+ GP_IO_PPSTR = 0x0800,
/* End of the types array */
GP_IO_END = 0xff00,
};
@@ -163,6 +173,11 @@ enum GP_IOReadFTypes {
int GP_IOReadF(GP_IO *self, uint16_t *types, ...);
+/*
+ * GP_IOReadF wrappers for convinient reading of single value
+ */
+int GP_IOReadB4(GP_IO *io, uint32_t *val);
+
enum GP_IOFileMode {
GP_IO_RDONLY = 0x00,
GP_IO_WRONLY = 0x01,
diff --git a/include/loaders/GP_Loaders.h b/include/loaders/GP_Loaders.h
index 7ed1727c..a80eb6e2 100644
--- a/include/loaders/GP_Loaders.h
+++ b/include/loaders/GP_Loaders.h
@@ -19,7 +19,7 @@
* Copyright (C) 2009-2010 Jiri "BlueBear" Dluhos *
* <jiri.bluebear.dluhos(a)gmail.com> *
* *
- * Copyright (C) 2009-2013 Cyril Hrubis <metan(a)ucw.cz> *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
* *
*****************************************************************************/
@@ -44,6 +44,7 @@
#include "loaders/GP_TIFF.h"
#include "loaders/GP_PCX.h"
#include "loaders/GP_PSP.h"
+#include "loaders/GP_PSD.h"
#include "loaders/GP_TmpFile.h"
diff --git a/include/loaders/GP_Loaders.h b/include/loaders/GP_PSD.h
similarity index 66%
copy from include/loaders/GP_Loaders.h
copy to include/loaders/GP_PSD.h
index 7ed1727c..8ab5b619 100644
--- a/include/loaders/GP_Loaders.h
+++ b/include/loaders/GP_PSD.h
@@ -16,42 +16,39 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02110-1301 USA *
* *
- * Copyright (C) 2009-2010 Jiri "BlueBear" Dluhos *
- * <jiri.bluebear.dluhos(a)gmail.com> *
- * *
- * Copyright (C) 2009-2013 Cyril Hrubis <metan(a)ucw.cz> *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
* *
*****************************************************************************/
/*
- Core include file for loaders API.
+ PSD thumbnail image loader.
*/
-#ifndef LOADERS_GP_LOADERS_H
-#define LOADERS_GP_LOADERS_H
+#ifndef LOADERS_GP_PSD_H
+#define LOADERS_GP_PSD_H
#include "core/GP_Context.h"
#include "core/GP_ProgressCallback.h"
-
-#include "loaders/GP_PNM.h"
-#include "loaders/GP_BMP.h"
-#include "loaders/GP_PNG.h"
-#include "loaders/GP_JPG.h"
-#include "loaders/GP_JP2.h"
-#include "loaders/GP_GIF.h"
-#include "loaders/GP_TIFF.h"
-#include "loaders/GP_PCX.h"
-#include "loaders/GP_PSP.h"
-
-#include "loaders/GP_TmpFile.h"
-
-#include "loaders/GP_MetaData.h"
-
-#include "loaders/GP_Loader.h"
-
-#include "loaders/GP_Container.h"
-#include "loaders/GP_ZIP.h"
-
-#endif /* LOADERS_GP_LOADERS_H */
+#include "loaders/GP_IO.h"
+
+/*
+ * Reads a PSD thumbnail from an IO stream.
+ *
+ * Returns newly allocated context cotaining the loaded image or in case of
+ * failure NULL and errno is set.
+ */
+GP_Context *GP_ReadPSD(GP_IO *io, GP_ProgressCallback *callback);
+
+/*
+ * Loads a PSD image from a file.
+ */
+GP_Context *GP_LoadPSD(const char *src_path, GP_ProgressCallback *callback);
+
+/*
+ * Match PSD signature.
+ */
+int GP_MatchPSD(const void *buf);
+
+#endif /* LOADERS_GP_PSD_H */
diff --git a/libs/loaders/GP_IO.c b/libs/loaders/GP_IO.c
index 9a5d9492..46009893 100644
--- a/libs/loaders/GP_IO.c
+++ b/libs/loaders/GP_IO.c
@@ -314,33 +314,44 @@ int GP_IOFill(GP_IO *io, void *buf, size_t size)
#define TYPE(x) ((x) & GP_IO_TYPE_MASK)
#define VAL(x) ((x) & ~GP_IO_TYPE_MASK)
-static unsigned int readf_size(uint16_t *types)
+static void readf_size(uint16_t *types,
+ unsigned int *min_size, unsigned int *max_size)
{
- unsigned int size = 0;
+ unsigned int min = 0;
+ unsigned int max = 0;
while (*types != GP_IO_END) {
switch (TYPE(*types)) {
case GP_IO_CONST:
case GP_IO_BYTE:
- size++;
+ min++;
+ max++;
break;
case GP_IO_L2:
case GP_IO_B2:
- size += 2;
+ min += 2;
+ max += 2;
break;
case GP_IO_L4:
case GP_IO_B4:
- size += 4;
+ min += 4;
+ max += 4;
break;
case GP_IO_ARRAY:
case GP_IO_IGN:
- size+=VAL(*types);
+ min += VAL(*types);
+ max += VAL(*types);
+ break;
+ case GP_IO_PPSTR:
+ min += 2;
+ max += 255;
break;
}
types++;
}
- return size;
+ *min_size = min;
+ *max_size = max;
}
static int needs_swap(uint16_t type)
@@ -358,19 +369,36 @@ static int needs_swap(uint16_t type)
#endif
}
+static void write_str(uint16_t type, uint8_t *dest,
+ uint8_t *src, unsigned int size)
+{
+ unsigned int dest_size = VAL(type);
+ unsigned int i;
+
+ if (!dest_size)
+ return;
+
+ for (i = 0; i < dest_size - 1 && i < size; i++)
+ dest[i] = src[i];
+
+ dest[i] = '0';
+}
+
int GP_IOReadF(GP_IO *self, uint16_t *types, ...)
{
- unsigned int size = readf_size(types);
+ unsigned int read_size, buf_size, size;
int ret;
va_list va;
uint8_t *ptr;
- if (size == 0)
+ readf_size(types, &read_size, &buf_size);
+
+ if (!read_size)
return 0;
- uint8_t buffer[size], *buf = buffer;
+ uint8_t buffer[buf_size], *buf = buffer;
- if (GP_IOFill(self, buf, size))
+ if (GP_IOFill(self, buf, read_size))
return -1;
ret = 0;
@@ -427,6 +455,23 @@ int GP_IOReadF(GP_IO *self, uint16_t *types, ...)
case GP_IO_IGN:
buf += VAL(*types);
break;
+ case GP_IO_PPSTR:
+ ptr = va_arg(va, void*);
+ size = *buf;
+
+ /* empty string */
+ if (!size) {
+ write_str(*types, ptr, NULL, 0);
+ buf += 2;
+ } else {
+ /* fill up another part of the buffer */
+ if (GP_IOFill(self, buf + read_size, size))
+ return -1;
+ read_size += size;
+ write_str(*types, ptr, buf + 1, size);
+ buf += GP_ALIGN2(size + 1);
+ }
+ break;
}
types++;
@@ -437,3 +482,13 @@ end:
va_end(va);
return ret;
}
+
+int GP_IOReadB4(GP_IO *io, uint32_t *val)
+{
+ uint16_t desc[] = {
+ GP_IO_B4,
+ GP_IO_END
+ };
+
+ return GP_IOReadF(io, desc, val) != 1;
+}
diff --git a/libs/loaders/GP_Loader.c b/libs/loaders/GP_Loader.c
index e1f78a5d..d88bf5f6 100644
--- a/libs/loaders/GP_Loader.c
+++ b/libs/loaders/GP_Loader.c
@@ -39,13 +39,23 @@
#include "loaders/GP_Loaders.h"
#include "loaders/GP_Loader.h"
+static GP_Loader psd_loader = {
+ .Read = GP_ReadPSD,
+ .Load = GP_LoadPSD,
+ .Save = NULL,
+ .Match = GP_MatchPSD,
+ .fmt_name = "Adobe Photoshop Image",
+ .next = NULL,
+ .extensions = {"psd", NULL},
+};
+
static GP_Loader psp_loader = {
.Read = GP_ReadPSP,
.Load = GP_LoadPSP,
.Save = NULL,
.Match = GP_MatchPSP,
.fmt_name = "Paint Shop Pro Image",
- .next = NULL,
+ .next = &psd_loader,
.extensions = {"psp", "pspimage", NULL},
};
diff --git a/libs/loaders/GP_PSD.c b/libs/loaders/GP_PSD.c
new file mode 100644
index 00000000..3b74a9c9
--- /dev/null
+++ b/libs/loaders/GP_PSD.c
@@ -0,0 +1,281 @@
+/*****************************************************************************
+ * This file is part of gfxprim library. *
+ * *
+ * Gfxprim is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU Lesser General Public *
+ * License as published by the Free Software Foundation; either *
+ * version 2.1 of the License, or (at your option) any later version. *
+ * *
+ * Gfxprim 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 *
+ * Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with gfxprim; if not, write to the Free Software *
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
+ * Boston, MA 02110-1301 USA *
+ * *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
+ * *
+ *****************************************************************************/
+
+/*
+
+ Photoshop PSD thumbnail image loader.
+
+ Written using documentation available freely on the internet.
+
+ */
+
+#include <stdint.h>
+#include <inttypes.h>
+#include <string.h>
+#include <errno.h>
+
+#include "core/GP_Debug.h"
+#include "core/GP_Common.h"
+#include "GP_JPG.h"
+#include "GP_PSD.h"
+
+#define PSD_SIGNATURE "8BPSx00x01"
+#define PSD_SIGNATURE_LEN 6
+
+int GP_MatchPSD(const void *buf)
+{
+ return !memcmp(buf, PSD_SIGNATURE, PSD_SIGNATURE_LEN);
+}
+
+enum psd_img_res_id {
+ PSD_THUMBNAIL_RES40 = 1033,
+ PSD_THUMBNAIL_RES50 = 1036,
+};
+
+enum thumbnail_fmt {
+ PSD_RAW_RGB = 0,
+ PSD_JPG_RGB = 1,
+};
+
+static const char *thumbnail_fmt_name(uint16_t fmt)
+{
+ switch (fmt) {
+ case PSD_RAW_RGB:
+ return "Raw RGB";
+ case PSD_JPG_RGB:
+ return "JPEG RGB";
+ default:
+ return "Unknown";
+ }
+}
+
+static GP_Context *psd_thumbnail50(GP_IO *io, GP_ProgressCallback *callback)
+{
+ uint32_t fmt, w, h;
+ uint16_t bpp, nr_planes;
+
+ uint16_t res_thumbnail_header[] = {
+ GP_IO_B4, /* Format */
+ GP_IO_B4, /* Width */
+ GP_IO_B4, /* Height */
+ /*
+ * Widthbytes:
+ * Padded row bytes = (width * bits per pixel + 31) / 32 * 4
+ */
+ GP_IO_I4,
+ GP_IO_I4, /* Total size: widthbytes * height * planes */
+ GP_IO_I4, /* Size after compression */
+ GP_IO_B2, /* Bits per pixel = 24 */
+ GP_IO_B2, /* Number of planes = 1 */
+ GP_IO_END,
+ };
+
+ if (GP_IOReadF(io, res_thumbnail_header, &fmt, &w, &h,
+ &bpp, &nr_planes) != 8) {
+ GP_DEBUG(1, "Failed to read image thumbnail header");
+ return NULL;
+ }
+
+ GP_DEBUG(1, "%"PRIu32"x%"PRIu32" format=%s (%"PRIu16") bpp=%"PRIu16
+ " nr_planes=%"PRIu16, w, h, thumbnail_fmt_name(fmt), fmt,
+ bpp, nr_planes);
+
+ if (fmt != PSD_JPG_RGB) {
+ GP_DEBUG(1, "Unsupported thumbnail format");
+ return NULL;
+ }
+
+ return GP_ReadJPG(io, callback);
+}
+
+static unsigned int psd_next_img_res_block(GP_IO *io, GP_Context **res,
+ GP_ProgressCallback *callback)
+{
+ uint16_t res_id;
+ uint32_t res_size;
+
+ uint16_t res_block_header[] = {
+ '8', 'B', 'I', 'M', /* Image resource block signature */
+ GP_IO_B2, /* Resource ID */
+ //TODO: photoshop pascall string, it's set to 00 00 in most cases though
+ GP_IO_I2,
+ GP_IO_B4, /* Resource block size */
+ GP_IO_END,
+ };
+
+ if (GP_IOReadF(io, res_block_header, &res_id, &res_size) != 7) {
+ GP_DEBUG(1, "Failed to read image resource header");
+ return 0;
+ }
+
+ GP_DEBUG(1, "Image resource id=%"PRIu16" size=%"PRIu32,
+ res_id, res_size);
+
+ switch (res_id) {
+ case PSD_THUMBNAIL_RES40:
+ GP_DEBUG(1, "Unsupported thumbnail version 4.0");
+ break;
+ case PSD_THUMBNAIL_RES50:
+ *res = psd_thumbnail50(io, callback);
+ return 0;
+ }
+
+ res_size = GP_ALIGN2(res_size);
+
+ if (GP_IOSeek(io, res_size, GP_IO_SEEK_CUR) == (off_t)-1) {
+ GP_DEBUG(1, "Failed skip image resource");
+ return 0;
+ }
+
+ return res_size + 10;
+}
+
+enum psd_color_mode {
+ PSD_BITMAP = 0x00,
+ PSD_GRAYSCALE = 0x01,
+ PSD_INDEXED = 0x02,
+ PSD_RGB = 0x03,
+ PSD_CMYK = 0x04,
+ PSD_MULTICHANNEL = 0x07,
+ PSD_DUOTONE = 0x08,
+ PSD_LAB = 0x09,
+};
+
+static const char *psd_color_mode_name(uint16_t color_mode)
+{
+ switch (color_mode) {
+ case PSD_BITMAP:
+ return "Bitmap";
+ case PSD_GRAYSCALE:
+ return "Grayscale";
+ case PSD_INDEXED:
+ return "Indexed";
+ case PSD_RGB:
+ return "RGB";
+ case PSD_CMYK:
+ return "CMYK";
+ case PSD_MULTICHANNEL:
+ return "Multichannel";
+ case PSD_DUOTONE:
+ return "Duotone";
+ case PSD_LAB:
+ return "Lab";
+ default:
+ return "Unknown";
+ }
+}
+
+GP_Context *GP_ReadPSD(GP_IO *io, GP_ProgressCallback *callback)
+{
+ int err;
+ uint32_t w;
+ uint32_t h;
+ uint16_t depth;
+ uint16_t channels;
+ uint16_t color_mode;
+ uint32_t len, size, read_size = 0;
+
+ uint16_t psd_header[] = {
+ '8', 'B', 'P', 'S',
+ 0x00, 0x01, /* Version always 1 */
+ GP_IO_IGN | 6, /* Reserved, should be 0 */
+ GP_IO_B2, /* Channels 1 to 56 */
+ GP_IO_B4, /* Height */
+ GP_IO_B4, /* Width */
+ GP_IO_B2, /* Depth (bits per channel) */
+ GP_IO_B2, /* Color mode */
+ GP_IO_B4, /* Color mode data lenght */
+ GP_IO_END
+ };
+
+ if (GP_IOReadF(io, psd_header, &channels, &h, &w, &depth,
+ &color_mode, &len) != 13) {
+ GP_DEBUG(1, "Failed to read file header");
+ err = EIO;
+ goto err0;
+ }
+
+ GP_DEBUG(1, "Have PSD %"PRIu32"x%"PRIu32" channels=%"PRIu16","
+ " bpp=%"PRIu16" color_mode=%s (%"PRIu16") "
+ " color_mode_data_len=%"PRIu32, w, h, channels,
+ depth, psd_color_mode_name(color_mode), color_mode, len);
+
+ switch (color_mode) {
+ case PSD_INDEXED:
+ case PSD_DUOTONE:
+ break;
+ default:
+ if (len)
+ GP_WARN("Color mode_mode_data_len != 0 (is %"PRIu32")"
+ "for %s (%"PRIu16")", len,
+ psd_color_mode_name(color_mode), color_mode);
+ }
+
+ /* Seek after the color mode data */
+ if (GP_IOSeek(io, len, GP_IO_SEEK_CUR) == (off_t)-1) {
+ GP_DEBUG(1, "Failed skip color mode data");
+ return NULL;
+ }
+
+ if (GP_IOReadB4(io, &len)) {
+ GP_DEBUG(1, "Failed to load Image Resource Section Lenght");
+ return NULL;
+ }
+
+ GP_DEBUG(1, "Image Resource Section length is %x", len);
+
+ GP_Context *res = NULL;
+
+ do {
+ size = psd_next_img_res_block(io, &res, callback);
+
+ if (!size)
+ return res;
+
+ read_size += size;
+ } while (read_size < len);
+
+ errno = ENOSYS;
+ return NULL;
+err0:
+ errno = err;
+ return NULL;
+}
+
+GP_Context *GP_LoadPSD(const char *src_path, GP_ProgressCallback *callback)
+{
+ GP_IO *io;
+ GP_Context *res;
+ int err;
+
+ io = GP_IOFile(src_path, GP_IO_RDONLY);
+ if (!io)
+ return NULL;
+
+ res = GP_ReadPSD(io, callback);
+
+ err = errno;
+ GP_IOClose(io);
+ errno = err;
+
+ return res;
+}
http://repo.or.cz/w/gfxprim.git/commit/c39571abe960d7892e9eb06735bfbb49d743…
commit c39571abe960d7892e9eb06735bfbb49d74352ef
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Sat Feb 15 23:49:02 2014 +0100
core: Add GP_ALIGN2() macro.
Signed-off-by: Cyril Hrubis <metan(a)ucw.cz>
diff --git a/include/core/GP_Common.h b/include/core/GP_Common.h
index 5de85469..57d4e131 100644
--- a/include/core/GP_Common.h
+++ b/include/core/GP_Common.h
@@ -71,6 +71,14 @@
})
/*
+ * Aligns value to be even
+ */
+#define GP_ALIGN2(a) ({ + typeof(a) _a = a; + _a + (_a%2); +})
+
+/*
* Swap a and b using an intermediate variable
*/
#define GP_SWAP(a, b) do {
http://repo.or.cz/w/gfxprim.git/commit/27ff06feef1cd3abdbca1ee6267f9e2febe4…
commit 27ff06feef1cd3abdbca1ee6267f9e2febe43d6e
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Wed Feb 12 22:59:58 2014 +0100
doc: asciidoc.css: underline links on mouse over.
Signed-off-by: Cyril Hrubis <metan(a)ucw.cz>
diff --git a/doc/asciidoc.css b/doc/asciidoc.css
index 11089def..9d4173ad 100644
--- a/doc/asciidoc.css
+++ b/doc/asciidoc.css
@@ -26,7 +26,7 @@ a, a:visited {
a:hover {
font-weight: bolder;
- text-decoration: none;
+ text-decoration: underline ! important;
color: OrangeRed ! important;
}
http://repo.or.cz/w/gfxprim.git/commit/70edd6e78312f8357776c81f6b5124a96233…
commit 70edd6e78312f8357776c81f6b5124a96233b5b2
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Sat Feb 8 00:52:49 2014 +0100
loaders: ZIP: Propagate errno from GP_ReadImage()
Propagate errno from GP_ReadImage() from zip_next_file() if loading was
canceled from callback.
Signed-off-by: Cyril Hrubis <metan(a)ucw.cz>
diff --git a/libs/loaders/GP_ZIP.c b/libs/loaders/GP_ZIP.c
index c0b417a1..ec80e963 100644
--- a/libs/loaders/GP_ZIP.c
+++ b/libs/loaders/GP_ZIP.c
@@ -379,6 +379,8 @@ static GP_Context *zip_next_file(struct zip_priv *priv,
GP_IOMark(priv->io, GP_IO_MARK);
ret = GP_ReadImage(priv->io, callback);
+ if (errno == ECANCELED)
+ err = errno;
GP_IOSeek(priv->io, priv->io->mark + header.comp_size, GP_IO_SEEK_SET);
@@ -391,6 +393,8 @@ static GP_Context *zip_next_file(struct zip_priv *priv,
}
GP_DEBUG(1, "Reading image");
ret = GP_ReadImage(io, callback);
+ if (errno == ECANCELED)
+ err = errno;
GP_IOClose(io);
goto out;
-----------------------------------------------------------------------
Summary of changes:
doc/asciidoc.css | 2 +-
include/core/GP_Common.h | 8 +
include/loaders/GP_IO.h | 15 ++
include/loaders/GP_Loaders.h | 3 +-
include/loaders/{GP_PCX.h => GP_PSD.h} | 21 +--
libs/loaders/GP_IO.c | 77 ++++++++--
libs/loaders/GP_Loader.c | 12 ++-
libs/loaders/GP_PSD.c | 281 ++++++++++++++++++++++++++++++++
libs/loaders/GP_ZIP.c | 4 +
9 files changed, 398 insertions(+), 25 deletions(-)
copy include/loaders/{GP_PCX.h => GP_PSD.h} (83%)
create mode 100644 libs/loaders/GP_PSD.c
repo.or.cz automatic notification. Contact project admin jiri.bluebear.dluhos(a)gmail.com
if you want to unsubscribe, or site admin admin(a)repo.or.cz if you receive
no reply.
--
gfxprim.git ("A simple 2D graphics library with emphasis on correctness and well-defined operation.")
1
0
05 Feb '14
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project gfxprim.git.
The branch, master has been updated
via 4a428416a87a6b7b1290c8e89d3fc8cfc83fe188 (commit)
from dd150fbb860e16f01cbdf28dc2c0f2d2d8425b20 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
http://repo.or.cz/w/gfxprim.git/commit/4a428416a87a6b7b1290c8e89d3fc8cfc83f…
commit 4a428416a87a6b7b1290c8e89d3fc8cfc83fe188
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Sun Feb 2 11:10:06 2014 +0100
loaders: PCX: Add test for 8bit palette, fix docs.
Signed-off-by: Cyril Hrubis <metan(a)ucw.cz>
diff --git a/doc/about.txt b/doc/about.txt
index 6065ed4d..018d71f9 100644
--- a/doc/about.txt
+++ b/doc/about.txt
@@ -99,7 +99,7 @@ images into various standard formats (PNG, JPEG, GIF, TIFF, BMP, PNM, etc...).
[green]#Composite image only for newer formats than 3.0# |
[black]*No*
-| PBM PGM PNM |
+| PBM PGM PPM PNM |
Netpbm portable bitmap |
[green]#All but < 8bit binary grayscale# |
[green]#All ASCII formats#
@@ -111,7 +111,7 @@ images into various standard formats (PNG, JPEG, GIF, TIFF, BMP, PNM, etc...).
| PCX |
ZSoft PCX |
- [green]#All v3.0# |
+ [green]*Yes* |
[black]*No*
| CBZ |
diff --git a/doc/spiv.txt b/doc/spiv.txt
index 0a0b6bac..0fd031b1 100644
--- a/doc/spiv.txt
+++ b/doc/spiv.txt
@@ -6,8 +6,8 @@ Spiv is a fast, lightweight and minimalistic image viewer build on the top of
the GFXprim library.
Spiv supports wide range of image formats, currently supported are JPEG, PNG,
-GIF, BMP, TIFF, PSP, PPM, JP2 and CBZ (as well general ZIP archives with
-images), and more will come in the near future.
+GIF, BMP, TIFF, PSP, PNM, PCX, JPEG2000 and CBZ (as well general ZIP archives
+with images), and more will come in the near future.
Spiv implements image caches with LRU (last recently used) algorithm which
speeds up subsequent image operations (rotations, going back and forth).
@@ -22,7 +22,7 @@ Floyd-Steinberg dithering (even, for example, from RGB888 to RGB565).
Spiv implements feh-like image actions, which are short shell scripts with
printf-like modifiers. The modifiers are substituted to current image path,
-name, etc. and executed by pressing function keys).
+name, etc. and executed by pressing function keys.
See 'spiv(1)' man page for more information.
diff --git a/tests/loaders/PCX.c b/tests/loaders/PCX.c
index d894c862..53d11e49 100644
--- a/tests/loaders/PCX.c
+++ b/tests/loaders/PCX.c
@@ -129,6 +129,14 @@ static struct testcase v2_8_4bpp_10x10_white = {
.pixel = 0xffffff,
};
+static struct testcase v3_0_8bpp_10x10_white = {
+ .path = "ver3_0_palette_8bpp_10x10_white.pcx",
+ .w = 10,
+ .h = 10,
+ .pixel_type = GP_PIXEL_RGB888,
+ .pixel = 0xffffff,
+};
+
static struct testcase v3_0_24bpp_10x10_white = {
.path = "ver3_0_palette_24bpp_10x10_white.pcx",
.w = 10,
@@ -164,6 +172,12 @@ const struct tst_suite tst_suite = {
.data = &v2_8_4bpp_10x10_white,
.flags = TST_TMPDIR | TST_CHECK_MALLOC},
+ {.name = "PCX Load ver3.0 8bpp 10x10 white",
+ .tst_fn = test_load_PCX,
+ .res_path = "data/pcx/valid/ver3_0_palette_8bpp_10x10_white.pcx",
+ .data = &v3_0_8bpp_10x10_white,
+ .flags = TST_TMPDIR | TST_CHECK_MALLOC},
+
{.name = "PCX Load ver3.0 24bpp 10x10 white",
.tst_fn = test_load_PCX,
.res_path = "data/pcx/valid/ver3_0_palette_24bpp_10x10_white.pcx",
diff --git a/tests/loaders/data/pcx/valid/ver3_0_palette_8bpp_10x10_white.pcx b/tests/loaders/data/pcx/valid/ver3_0_palette_8bpp_10x10_white.pcx
new file mode 100644
index 00000000..2f7e71ee
Binary files /dev/null and b/tests/loaders/data/pcx/valid/ver3_0_palette_8bpp_10x10_white.pcx differ
-----------------------------------------------------------------------
Summary of changes:
doc/about.txt | 4 ++--
doc/spiv.txt | 6 +++---
tests/loaders/PCX.c | 14 ++++++++++++++
.../pcx/valid/ver3_0_palette_8bpp_10x10_white.pcx | Bin 0 -> 917 bytes
4 files changed, 19 insertions(+), 5 deletions(-)
create mode 100644 tests/loaders/data/pcx/valid/ver3_0_palette_8bpp_10x10_white.pcx
repo.or.cz automatic notification. Contact project admin jiri.bluebear.dluhos(a)gmail.com
if you want to unsubscribe, or site admin admin(a)repo.or.cz if you receive
no reply.
--
gfxprim.git ("A simple 2D graphics library with emphasis on correctness and well-defined operation.")
1
0
02 Feb '14
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project gfxprim.git.
The branch, master has been updated
via dd150fbb860e16f01cbdf28dc2c0f2d2d8425b20 (commit)
via cf801775780f7eab314e2ba9a166edc9ccdd708d (commit)
from 690b25c07649dab4d217e1d0ecbf9c56a20fc48b (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
http://repo.or.cz/w/gfxprim.git/commit/dd150fbb860e16f01cbdf28dc2c0f2d2d842…
commit dd150fbb860e16f01cbdf28dc2c0f2d2d8425b20
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Mon Jan 27 22:27:52 2014 +0100
loaders: Initial PCX support + tests + doc.
TODO: Needs a buffered IO Stream
FIXME: More tests, (256 color palette)
does v2.5 with filed palette work?
Signed-off-by: Cyril Hrubis <metan(a)ucw.cz>
diff --git a/build/syms/Loaders_symbols.txt b/build/syms/Loaders_symbols.txt
index 7b40c8c..a65f6c7 100644
--- a/build/syms/Loaders_symbols.txt
+++ b/build/syms/Loaders_symbols.txt
@@ -56,6 +56,10 @@ GP_ReadJP2
GP_LoadJP2
GP_MatchJP2
+GP_ReadPCX
+GP_LoadPCX
+GP_MatchPCX
+
GP_SaveTmpFile
GP_LoadTmpFile
diff --git a/demos/spiv/spiv.1 b/demos/spiv/spiv.1
index 386706e..fb23f1f 100644
--- a/demos/spiv/spiv.1
+++ b/demos/spiv/spiv.1
@@ -11,8 +11,9 @@ is a fast, lightweight and minimalistic image viewer build on the
top of the GFXprim library.
.PP
Spiv supports wide range of image formats, currently supported are
-JPEG, PNG, GIF, BMP, TIFF, PSP, PPM, JP2 and CBZ (as well general
-ZIP archives with images), and more will come in the near future.
+JPEG, PNG, GIF, BMP, TIFF, PSP, PNM, PCX, JPEG2000 and CBZ (as well
+general ZIP archives with images), and more will come in the
+near future.
.PP
Spiv supports variety of video backends (via GFXprim backends)
currently these are X11, Linux Framebuffer, SDL and AAlib. Spiv also
@@ -300,7 +301,7 @@ spiv -e G1 -d images/
spiv -b 'X11:use_root' -t 10 images/
.PP
-.B Same as abowe but works in KDE
+.B Same as above but works in KDE
.nf
spiv -b 'X11:create_root' -t 10 images/
diff --git a/demos/spiv/spiv_help.c b/demos/spiv/spiv_help.c
index 3af2b03..186b1c5 100644
--- a/demos/spiv/spiv_help.c
+++ b/demos/spiv/spiv_help.c
@@ -98,7 +98,7 @@ static const struct examples examples[] = {
{"spiv -b 'X11:use_root' -t 10 images/",
"Runs slideshow using X root window as backend window"},
{"spiv -b 'X11:create_root' -t 10 images/",
- "Same as abowe but works in KDEn"}
+ "Same as above but works in KDEn"}
};
static const int examples_len = sizeof(examples) / sizeof(*examples);
@@ -164,8 +164,9 @@ const char *man_head =
"top of the GFXprim library.n"
".PPn"
"Spiv supports wide range of image formats, currently supported aren"
- "JPEG, PNG, GIF, BMP, TIFF, PSP, PPM, JP2 and CBZ (as well generaln"
- "ZIP archives with images), and more will come in the near future.n"
+ "JPEG, PNG, GIF, BMP, TIFF, PSP, PNM, PCX, JPEG2000 and CBZ (as welln"
+ "general ZIP archives with images), and more will come in then"
+ "near future.n"
".PPn"
"Spiv supports variety of video backends (via GFXprim backends)n"
"currently these are X11, Linux Framebuffer, SDL and AAlib. Spiv alson"
diff --git a/doc/about.txt b/doc/about.txt
index 7029823..6065ed4 100644
--- a/doc/about.txt
+++ b/doc/about.txt
@@ -109,6 +109,11 @@ images into various standard formats (PNG, JPEG, GIF, TIFF, BMP, PNM, etc...).
[green]#Experimental support for RGB images# |
[black]*No*
+| PCX |
+ ZSoft PCX |
+ [green]#All v3.0# |
+ [black]*No*
+
| CBZ |
Comic book archive |
[green]#Experimental support via ZIP Container# |
diff --git a/doc/loaders.txt b/doc/loaders.txt
index 5ac5743..1734718 100644
--- a/doc/loaders.txt
+++ b/doc/loaders.txt
@@ -600,3 +600,45 @@ signatures.
The 'PNM' matches all of the formats. i.e. 'PBM', 'PGM' and 'PPM'.
All functions return non-zero if found.
+
+PCX Loader
+~~~~~~~~~~
+
+The 'PCX' loader can load ZSoft PCX images.
+
+[source,c]
+-------------------------------------------------------------------------------
+#include <loaders/GP_PCX.h>
+/* or */
+#include <GP.h>
+
+GP_Context *GP_ReadPCX(GP_IO *io, GP_ProgressCallback *callback);
+-------------------------------------------------------------------------------
+
+Reads a 'PCX' image from readable 'GP_IO'. The link:loaders_io.html[IO stream]
+is expected to start exactly at the 'PCX' file signature.
+
+Returns newly allocated context (containing decompressed image) or in case of
+failure 'NULL' and 'errno' is set.
+
+[source,c]
+-------------------------------------------------------------------------------
+#include <loaders/GP_PCX.h>
+/* or */
+#include <GP.h>
+
+GP_Context *GP_LoadPCX(const char *src_path, GP_ProgressCallback *callback);
+-------------------------------------------------------------------------------
+
+Loads a 'PCX' image from a file.
+
+[source,c]
+-------------------------------------------------------------------------------
+#include <loaders/GP_PCX.h>
+/* or */
+#include <GP.h>
+
+int GP_MatchPCX(const void *buf);
+-------------------------------------------------------------------------------
+
+Matches a 'PCX' file signature. Returns non-zero if found.
diff --git a/doc/loaders_python.txt b/doc/loaders_python.txt
index 136b533..ae2207e 100644
--- a/doc/loaders_python.txt
+++ b/doc/loaders_python.txt
@@ -21,6 +21,7 @@ import gfxprim.loaders as loaders
img = loaders.LoadPNG(path, callback=None)
img = loaders.LoadPNM(path, callback=None)
img = loaders.LoadPPM(path, callback=None)
+ img = loaders.LoadPCX(path, callback=None)
img = loaders.LoadPSP(path, callback=None)
img = loaders.LoadTIFF(path, callback=None)
-------------------------------------------------------------------------------
diff --git a/include/loaders/GP_Loaders.h b/include/loaders/GP_Loaders.h
index 0ed72af..7ed1727 100644
--- a/include/loaders/GP_Loaders.h
+++ b/include/loaders/GP_Loaders.h
@@ -42,6 +42,7 @@
#include "loaders/GP_JP2.h"
#include "loaders/GP_GIF.h"
#include "loaders/GP_TIFF.h"
+#include "loaders/GP_PCX.h"
#include "loaders/GP_PSP.h"
#include "loaders/GP_TmpFile.h"
diff --git a/include/loaders/GP_Loaders.h b/include/loaders/GP_PCX.h
similarity index 67%
copy from include/loaders/GP_Loaders.h
copy to include/loaders/GP_PCX.h
index 0ed72af..0d7d6e2 100644
--- a/include/loaders/GP_Loaders.h
+++ b/include/loaders/GP_PCX.h
@@ -16,41 +16,40 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02110-1301 USA *
* *
- * Copyright (C) 2009-2010 Jiri "BlueBear" Dluhos *
- * <jiri.bluebear.dluhos(a)gmail.com> *
- * *
- * Copyright (C) 2009-2013 Cyril Hrubis <metan(a)ucw.cz> *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
* *
*****************************************************************************/
/*
- Core include file for loaders API.
+ PCX image support.
*/
-#ifndef LOADERS_GP_LOADERS_H
-#define LOADERS_GP_LOADERS_H
+#ifndef LOADERS_GP_PCX_H
+#define LOADERS_GP_PCX_H
#include "core/GP_Context.h"
#include "core/GP_ProgressCallback.h"
+#include "loaders/GP_IO.h"
-#include "loaders/GP_PNM.h"
-#include "loaders/GP_BMP.h"
-#include "loaders/GP_PNG.h"
-#include "loaders/GP_JPG.h"
-#include "loaders/GP_JP2.h"
-#include "loaders/GP_GIF.h"
-#include "loaders/GP_TIFF.h"
-#include "loaders/GP_PSP.h"
-
-#include "loaders/GP_TmpFile.h"
-#include "loaders/GP_MetaData.h"
+/*
+ * Reads a PCX from an IO stream.
+ *
+ * Returns newly allocated context cotaining the loaded image or in case of
+ * failure NULL and errno is set.
+ */
+GP_Context *GP_ReadPCX(GP_IO *io, GP_ProgressCallback *callback);
-#include "loaders/GP_Loader.h"
+/*
+ * Loads a PCX image from a file.
+ */
+GP_Context *GP_LoadPCX(const char *src_path, GP_ProgressCallback *callback);
-#include "loaders/GP_Container.h"
-#include "loaders/GP_ZIP.h"
+/*
+ * Match PCX signature.
+ */
+int GP_MatchPCX(const void *buf);
-#endif /* LOADERS_GP_LOADERS_H */
+#endif /* LOADERS_GP_PCX_H */
diff --git a/libs/loaders/GP_Loader.c b/libs/loaders/GP_Loader.c
index aa793ba..e1f78a5 100644
--- a/libs/loaders/GP_Loader.c
+++ b/libs/loaders/GP_Loader.c
@@ -49,13 +49,23 @@ static GP_Loader psp_loader = {
.extensions = {"psp", "pspimage", NULL},
};
+static GP_Loader pcx_loader = {
+ .Read = GP_ReadPCX,
+ .Load = GP_LoadPCX,
+ .Save = NULL,
+ .Match = GP_MatchPCX,
+ .fmt_name = "ZSoft PCX",
+ .next = &psp_loader,
+ .extensions = {"pcx", NULL},
+};
+
static GP_Loader pbm_loader = {
.Read = GP_ReadPBM,
.Load = GP_LoadPBM,
.Save = GP_SavePBM,
.Match = GP_MatchPBM,
.fmt_name = "Netpbm portable Bitmap",
- .next = &psp_loader,
+ .next = &pcx_loader,
.extensions = {"pbm", NULL},
};
diff --git a/libs/loaders/GP_PCX.c b/libs/loaders/GP_PCX.c
new file mode 100644
index 0000000..698f82e
--- /dev/null
+++ b/libs/loaders/GP_PCX.c
@@ -0,0 +1,473 @@
+/*****************************************************************************
+ * This file is part of gfxprim library. *
+ * *
+ * Gfxprim is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU Lesser General Public *
+ * License as published by the Free Software Foundation; either *
+ * version 2.1 of the License, or (at your option) any later version. *
+ * *
+ * Gfxprim 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 *
+ * Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with gfxprim; if not, write to the Free Software *
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
+ * Boston, MA 02110-1301 USA *
+ * *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
+ * *
+ *****************************************************************************/
+
+/*
+
+ PCX image support.
+
+ */
+
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <inttypes.h>
+
+#include "core/GP_Debug.h"
+#include "core/GP_GetPutPixel.h"
+
+#include "GP_PCX.h"
+
+/* Creator ZSoft: 0x0a
+ * Version: 0x00, 0x02, 0x03, 0x04, 0x05
+ * RLE: 0x01
+ * BPP: 0x01, 0x02, 0x04, 0x08
+ */
+int GP_MatchPCX(const void *buf)
+{
+ const uint8_t *b = buf;
+
+ if (b[0] != 0x0a)
+ return 0;
+
+ /* version */
+ switch (b[1]) {
+ case 0:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ break;
+ default:
+ return 0;
+ }
+
+ if (b[2] != 0x01)
+ return 0;
+
+ /* bpp 1, 2, 4 or 8 */
+ switch (b[3]) {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+struct pcx_header {
+ uint8_t ver;
+ uint8_t bpp;
+ uint16_t xs, ys, xe, ye;
+ uint16_t hres, vres;
+ uint8_t nplanes;
+ uint16_t pal_info;
+ uint16_t bytes_per_line;
+ /* 16 RGB tripplets palette */
+ uint8_t palette[48];
+};
+
+static int get_byte(GP_IO *io)
+{
+ uint8_t buf;
+
+ if (GP_IORead(io, &buf, 1) != 1)
+ return -1;
+
+ return buf;
+}
+
+static int readline(GP_IO *io, uint8_t *buf, unsigned int size, unsigned int padd)
+{
+ int b, val = 0, cnt = 0;
+ unsigned int read = 0;
+
+ for (;;) {
+ while (cnt > 0 && read < size) {
+ buf[read++] = val;
+ cnt--;
+ }
+
+ if (read >= size) {
+ goto end;
+ }
+
+ b = get_byte(io);
+
+ if (b == -1) {
+ GP_WARN("End of file reached unexpectedly");
+ return 0;
+ }
+
+ if ((b & 0xc0) == 0xc0) {
+ cnt = b & 0x3f;
+ val = get_byte(io);
+ } else {
+ cnt = 1;
+ val = b;
+ }
+ }
+
+end:
+ /*
+ * Data may be padded, read the excess bytes
+ */
+ while (padd--) {
+ if (cnt) {
+ cnt--;
+ } else {
+ b = get_byte(io);
+ if ((b & 0xc0) == 0xc0) {
+ cnt = b & 0x3f;
+ get_byte(io);
+ }
+ }
+ }
+
+ if (cnt)
+ GP_WARN("Nonzero repeat count at the line end (%u)", cnt);
+
+ return 0;
+}
+
+#include "core/GP_BitSwap.h"
+
+static int read_g1(GP_IO *io, struct pcx_header *header,
+ GP_Context *res, GP_ProgressCallback *callback)
+{
+ uint32_t y;
+ int padd = (int)header->bytes_per_line - (int)res->bytes_per_row;
+
+ if (padd < 0) {
+ GP_WARN("Invalid number of bytes per line");
+ return EINVAL;
+ }
+
+ for (y = 0; y < res->h; y++) {
+ uint8_t *addr = GP_PIXEL_ADDR(res, 0, y);
+
+ readline(io, addr, res->bytes_per_row, padd);
+
+ //TODO: FIX Endians
+ GP_BitSwapRow_B1(addr, res->bytes_per_row);
+
+ if (GP_ProgressCallbackReport(callback, y, res->h, res->w)) {
+ GP_DEBUG(1, "Operation aborted");
+ return ECANCELED;
+ }
+ }
+
+ return 0;
+}
+
+static int read_rgb888(GP_IO *io, struct pcx_header *header,
+ GP_Context *res, GP_ProgressCallback *callback)
+{
+ uint32_t x, y;
+ unsigned int bpr = header->bytes_per_line;
+ uint8_t b[3 * bpr];
+
+ for (y = 0; y < res->h; y++) {
+ readline(io, b, sizeof(b), 0);
+
+ for (x = 0; x < res->w; x++) {
+ GP_Pixel pix = GP_Pixel_CREATE_RGB888(b[x],
+ b[x+bpr],
+ b[x+2*bpr]);
+ GP_PutPixel_Raw_24BPP(res, x, y, pix);
+ }
+
+ if (GP_ProgressCallbackReport(callback, y, res->h, res->w)) {
+ GP_DEBUG(1, "Operation aborted");
+ return ECANCELED;
+ }
+ }
+
+ return 0;
+}
+
+static int read_16_palette(GP_IO *io, struct pcx_header *header,
+ GP_Context *res, GP_ProgressCallback *callback)
+{
+ uint32_t x, y;
+ unsigned int i;
+ uint8_t b[header->bytes_per_line];
+ GP_Pixel palette[16];
+ uint8_t idx=0, mask, mod;
+
+ for (i = 0; i < 16; i++) {
+ palette[i] = (GP_Pixel)header->palette[3*i] << 16;
+ palette[i] |= (GP_Pixel)header->palette[3*i+1] << 8;
+ palette[i] |= header->palette[3*i+2];
+ }
+
+ switch (header->bpp) {
+ case 2:
+ mask = 0x30;
+ mod = 4;
+ break;
+ case 4:
+ mask = 0xf0;
+ mod = 2;
+ break;
+ default:
+ GP_BUG("Invalid 16 color palette bpp %u", header->bpp);
+ return EINVAL;
+ }
+
+ for (y = 0; y < res->h; y++) {
+ readline(io, b, sizeof(b), 0);
+
+ i = 0;
+
+ for (x = 0; x < res->w; x++) {
+
+ if (!(x % mod))
+ idx = b[i++];
+
+ GP_PutPixel_Raw_24BPP(res, x, y, palette[(idx & mask) >> (8 - header->bpp)]);
+ idx <<= header->bpp;
+ }
+
+ if (GP_ProgressCallbackReport(callback, y, res->h, res->w)) {
+ GP_DEBUG(1, "Operation aborted");
+ return ECANCELED;
+ }
+ }
+
+ return 0;
+}
+
+static int read_256_palette(GP_IO *io, struct pcx_header *header,
+ GP_Context *res, GP_ProgressCallback *callback)
+{
+ uint32_t x, y;
+ unsigned int i;
+ GP_Pixel palette[256];
+ uint8_t b[header->bytes_per_line];
+
+ if (GP_IOSeek(io, -769, GP_IO_SEEK_END) == (off_t)-1) {
+ GP_DEBUG(1, "Failed to seek to palette: %s", strerror(errno));
+ return EIO;
+ }
+
+ if (get_byte(io) != 0x0c) {
+ GP_DEBUG(1, "Wrong palette marker");
+ return EIO;
+ }
+
+ for (i = 0; i < 256; i++) {
+ palette[i] = get_byte(io) << 16;
+ palette[i] |= get_byte(io) << 8;
+ palette[i] |= get_byte(io);
+ }
+
+ if (GP_IOSeek(io, 128, GP_IO_SEEK_SET) == (off_t)-1) {
+ GP_DEBUG(1, "Failed to seek to image data: %s",
+ strerror(errno));
+ return EIO;
+ }
+
+ for (y = 0; y < res->h; y++) {
+ readline(io, b, sizeof(b), 0);
+
+ for (x = 0; x < res->w; x++)
+ GP_PutPixel_Raw_24BPP(res, x, y, palette[b[x]]);
+
+ if (GP_ProgressCallbackReport(callback, y, res->h, res->w)) {
+ GP_DEBUG(1, "Operation aborted");
+ return ECANCELED;
+ }
+ }
+
+ return 0;
+}
+
+static GP_PixelType match_pixel_type(struct pcx_header *header)
+{
+ switch (header->nplanes) {
+ case 1:
+ switch (header->bpp) {
+ /* 1 bit grayscale */
+ case 1:
+ return GP_PIXEL_G1;
+ /* 16 color palette */
+ case 2:
+ case 4:
+ /* 256 color palette */
+ case 8:
+ return GP_PIXEL_RGB888;
+ }
+ break;
+ /* raw RGB */
+ case 3:
+ if (header->bpp == 8)
+ return GP_PIXEL_RGB888;
+ break;
+ }
+
+ return GP_PIXEL_UNKNOWN;
+}
+
+static int read_image(GP_IO *io, struct pcx_header *header,
+ GP_Context *res, GP_ProgressCallback *callback)
+{
+ switch (header->nplanes) {
+ case 1:
+ switch (header->bpp) {
+ case 1:
+ return read_g1(io, header, res, callback);
+ case 2:
+ case 4:
+ return read_16_palette(io, header, res, callback);
+ case 8:
+ return read_256_palette(io, header, res, callback);
+ }
+ break;
+ case 3:
+ if (header->bpp == 8)
+ return read_rgb888(io, header, res, callback);
+ break;
+ default:
+ break;
+ }
+
+ GP_BUG("Have pixel type %s but cannot load image data",
+ GP_PixelTypeName(res->pixel_type));
+ return ENOSYS;
+}
+
+GP_Context *GP_ReadPCX(GP_IO *io, GP_ProgressCallback *callback)
+{
+ GP_Context *res = NULL;
+ GP_PixelType pixel_type;
+ struct pcx_header header;
+ unsigned int w, h;
+ int err = 0;
+
+ uint16_t pcx_header[] = {
+ 0x0a, /* creator ZSoft */
+ GP_IO_BYTE, /* version */
+ 0x01, /* compression 1 == RLE */
+ GP_IO_BYTE, /* bpp */
+ GP_IO_L2, /* xs */
+ GP_IO_L2, /* ys */
+ GP_IO_L2, /* xe */
+ GP_IO_L2, /* ye */
+ GP_IO_L2, /* hres */
+ GP_IO_L2, /* vres */
+ GP_IO_ARRAY | 48, /* 16 bit RGB palette */
+ GP_IO_I1, /* reserved */
+ GP_IO_BYTE, /* number of planes */
+ GP_IO_L2, /* bytes per line */
+ GP_IO_L2, /* palette info */
+ GP_IO_IGN | 58, /* filler to 128 bytes */
+ GP_IO_END,
+ };
+
+ if (GP_IOReadF(io, pcx_header, &header.ver, &header.bpp,
+ &header.xs, &header.ys, &header.xe, &header.ye,
+ &header.hres, &header.vres,
+ header.palette, &header.nplanes,
+ &header.bytes_per_line, &header.pal_info) != 16) {
+ GP_DEBUG(1, "Failed to read header: %s", strerror(errno));
+ return NULL;
+ }
+
+ switch (header.ver) {
+ case 0x00:
+ case 0x02:
+ case 0x03:
+ case 0x04:
+ case 0x05:
+ break;
+ GP_DEBUG(1, "Unknown version %x", header.ver);
+ errno = EINVAL;
+ return NULL;
+ }
+
+ GP_DEBUG(1, "Have PCX image ver=%x bpp=%"PRIu8" %"PRIu16"x%"PRIu16
+ "-%"PRIu16"x%"PRIu16" bytes_per_line=%"PRIu16
+ " nplanes=%"PRIu16" hres=%"PRIu16" vres=%"PRIu16,
+ header.ver, header.bpp, header.xs,
+ header.ys, header.xe, header.ye,
+ header.bytes_per_line, header.nplanes,
+ header.hres, header.vres);
+
+ pixel_type = match_pixel_type(&header);
+
+ if (pixel_type == GP_PIXEL_UNKNOWN) {
+ GP_DEBUG(1, "Failed to match pixel type");
+ err = ENOSYS;
+ goto err0;
+ }
+
+ if (header.xs > header.xe || header.ys > header.ye) {
+ GP_WARN("Invalid size %"PRIu16"-%"PRIu16"x%"PRIu16"-%"PRIu16,
+ header.xe, header.xs, header.ye, header.xs);
+ err = EINVAL;
+ goto err0;
+ }
+
+ w = header.xe - header.xs + 1;
+ h = header.ye - header.ys + 1;
+
+ res = GP_ContextAlloc(w, h, pixel_type);
+
+ if (!res) {
+ GP_DEBUG(1, "Malloc failed :(");
+ err = ENOMEM;
+ goto err0;
+ }
+
+ if ((err = read_image(io, &header, res, callback)))
+ goto err1;
+
+ GP_ProgressCallbackDone(callback);
+ return res;
+err1:
+ GP_ContextFree(res);
+err0:
+ errno = err;
+ return NULL;
+}
+
+GP_Context *GP_LoadPCX(const char *src_path, GP_ProgressCallback *callback)
+{
+ GP_IO *io;
+ GP_Context *res;
+ int err;
+
+ io = GP_IOFile(src_path, GP_IO_RDONLY);
+ if (!io)
+ return NULL;
+
+ res = GP_ReadPCX(io, callback);
+
+ err = errno;
+ GP_IOClose(io);
+ errno = err;
+
+ return res;
+}
diff --git a/pylib/gfxprim/loaders/loaders.i b/pylib/gfxprim/loaders/loaders.i
index bab032c..2090b2a 100644
--- a/pylib/gfxprim/loaders/loaders.i
+++ b/pylib/gfxprim/loaders/loaders.i
@@ -69,3 +69,7 @@ LOADER_FUNC(PSP);
LOADER_FUNC(JP2);
%include "GP_JP2.h"
+
+LOADER_FUNC(PCX);
+
+%include "GP_PCX.h"
diff --git a/tests/loaders/.gitignore b/tests/loaders/.gitignore
index 047646e..f6863aa 100644
--- a/tests/loaders/.gitignore
+++ b/tests/loaders/.gitignore
@@ -5,6 +5,7 @@ PGM
PNG
PNM
PPM
+PCX
SaveAbort.gen
SaveLoad.gen
ZIP
diff --git a/tests/loaders/Makefile b/tests/loaders/Makefile
index 31eaea4..890e576 100644
--- a/tests/loaders/Makefile
+++ b/tests/loaders/Makefile
@@ -1,10 +1,11 @@
TOPDIR=../..
include $(TOPDIR)/pre.mk
-CSOURCES=loaders_suite.c PNG.c PBM.c PGM.c PPM.c ZIP.c GIF.c IO.c PNM.c
+CSOURCES=loaders_suite.c PNG.c PBM.c PGM.c PPM.c ZIP.c GIF.c IO.c PNM.c PCX.c
GENSOURCES=SaveLoad.gen.c SaveAbort.gen.c
-APPS=loaders_suite PNG PBM PGM PPM PNM SaveLoad.gen SaveAbort.gen ZIP GIF IO
+APPS=loaders_suite PNG PBM PGM PPM PNM SaveLoad.gen SaveAbort.gen ZIP GIF PCX+ IO
include ../tests.mk
diff --git a/tests/loaders/PCX.c b/tests/loaders/PCX.c
new file mode 100644
index 0000000..d894c86
--- /dev/null
+++ b/tests/loaders/PCX.c
@@ -0,0 +1,174 @@
+/*****************************************************************************
+ * This file is part of gfxprim library. *
+ * *
+ * Gfxprim is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU Lesser General Public *
+ * License as published by the Free Software Foundation; either *
+ * version 2.1 of the License, or (at your option) any later version. *
+ * *
+ * Gfxprim 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 *
+ * Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with gfxprim; if not, write to the Free Software *
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
+ * Boston, MA 02110-1301 USA *
+ * *
+ * Copyright (C) 2009-2014 Cyril Hrubis <metan(a)ucw.cz> *
+ * *
+ *****************************************************************************/
+
+#include <string.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+#include <core/GP_Context.h>
+#include <core/GP_GetPutPixel.h>
+#include <loaders/GP_PCX.h>
+
+#include "tst_test.h"
+
+struct testcase {
+ const char *path;
+ GP_Size w, h;
+ GP_PixelType pixel_type;
+ GP_Pixel pixel;
+};
+
+static int test_load_PCX(struct testcase *test)
+{
+ GP_Context *img;
+
+ errno = 0;
+
+ img = GP_LoadPCX(test->path, NULL);
+
+ if (img == NULL) {
+ switch (errno) {
+ case ENOSYS:
+ tst_msg("Not Implemented");
+ return TST_SKIPPED;
+ default:
+ tst_msg("Got %s", strerror(errno));
+ return TST_FAILED;
+ }
+ }
+
+ if (img->w != test->w || img->h != test->h) {
+ tst_msg("Wrong size have %ux%u expected %ux%u",
+ img->w, img->h, test->w, test->h);
+ GP_ContextFree(img);
+ return TST_FAILED;
+ }
+
+ if (img->pixel_type != test->pixel_type) {
+ tst_msg("Wrong pixel type have %s expected %s",
+ GP_PixelTypeName(img->pixel_type),
+ GP_PixelTypeName(test->pixel_type));
+ GP_ContextFree(img);
+ return TST_FAILED;
+ }
+
+ unsigned int x, y, fail = 0;
+
+ for (x = 0; x < img->w; x++) {
+ for (y = 0; y < img->w; y++) {
+ GP_Pixel p = GP_GetPixel(img, x, y);
+
+ if (p != test->pixel) {
+ if (!fail)
+ tst_msg("First failed at %u,%u %x %x",
+ x, y, p, test->pixel);
+ fail = 1;
+ }
+ }
+ }
+
+ if (!fail)
+ tst_msg("Context pixels are correct");
+
+ GP_ContextFree(img);
+
+ if (fail)
+ return TST_FAILED;
+
+ return TST_SUCCESS;
+}
+
+static struct testcase v3_0_1bpp_10x10_white = {
+ .path = "ver3_0_palette_1bpp_10x10_white.pcx",
+ .w = 10,
+ .h = 10,
+ .pixel_type = GP_PIXEL_G1,
+ .pixel = 0x000001,
+};
+
+static struct testcase v3_0_2bpp_10x10_white = {
+ .path = "ver3_0_palette_2bpp_10x10_white.pcx",
+ .w = 10,
+ .h = 10,
+ .pixel_type = GP_PIXEL_RGB888,
+ .pixel = 0xffffff,
+};
+
+static struct testcase v3_0_4bpp_10x10_white = {
+ .path = "ver3_0_palette_4bpp_10x10_white.pcx",
+ .w = 10,
+ .h = 10,
+ .pixel_type = GP_PIXEL_RGB888,
+ .pixel = 0xffffff,
+};
+
+static struct testcase v2_8_4bpp_10x10_white = {
+ .path = "ver2_8_palette_4bpp_10x10_white.pcx",
+ .w = 10,
+ .h = 10,
+ .pixel_type = GP_PIXEL_RGB888,
+ .pixel = 0xffffff,
+};
+
+static struct testcase v3_0_24bpp_10x10_white = {
+ .path = "ver3_0_palette_24bpp_10x10_white.pcx",
+ .w = 10,
+ .h = 10,
+ .pixel_type = GP_PIXEL_RGB888,
+ .pixel = 0xffffff,
+};
+
+const struct tst_suite tst_suite = {
+ .suite_name = "PCX",
+ .tests = {
+ {.name = "PCX Load ver3.0 1bpp 10x10 white",
+ .tst_fn = test_load_PCX,
+ .res_path = "data/pcx/valid/ver3_0_palette_1bpp_10x10_white.pcx",
+ .data = &v3_0_1bpp_10x10_white,
+ .flags = TST_TMPDIR | TST_CHECK_MALLOC},
+
+ {.name = "PCX Load ver3.0 2bpp 10x10 white",
+ .tst_fn = test_load_PCX,
+ .res_path = "data/pcx/valid/ver3_0_palette_2bpp_10x10_white.pcx",
+ .data = &v3_0_2bpp_10x10_white,
+ .flags = TST_TMPDIR | TST_CHECK_MALLOC},
+
+ {.name = "PCX Load ver3.0 4bpp 10x10 white",
+ .tst_fn = test_load_PCX,
+ .res_path = "data/pcx/valid/ver3_0_palette_4bpp_10x10_white.pcx",
+ .data = &v3_0_4bpp_10x10_white,
+ .flags = TST_TMPDIR | TST_CHECK_MALLOC},
+
+ {.name = "PCX Load ver2.8 4bpp 10x10 white",
+ .tst_fn = test_load_PCX,
+ .res_path = "data/pcx/valid/ver2_8_palette_4bpp_10x10_white.pcx",
+ .data = &v2_8_4bpp_10x10_white,
+ .flags = TST_TMPDIR | TST_CHECK_MALLOC},
+
+ {.name = "PCX Load ver3.0 24bpp 10x10 white",
+ .tst_fn = test_load_PCX,
+ .res_path = "data/pcx/valid/ver3_0_palette_24bpp_10x10_white.pcx",
+ .data = &v3_0_24bpp_10x10_white,
+ .flags = TST_TMPDIR | TST_CHECK_MALLOC},
+ {.name = NULL},
+ }
+};
diff --git a/tests/loaders/data/pcx/valid/ver2_8_palette_4bpp_10x10_white.pcx b/tests/loaders/data/pcx/valid/ver2_8_palette_4bpp_10x10_white.pcx
new file mode 100644
index 0000000..01b93b8
Binary files /dev/null and b/tests/loaders/data/pcx/valid/ver2_8_palette_4bpp_10x10_white.pcx differ
diff --git a/tests/loaders/data/pcx/valid/ver3_0_palette_1bpp_10x10_white.pcx b/tests/loaders/data/pcx/valid/ver3_0_palette_1bpp_10x10_white.pcx
new file mode 100644
index 0000000..9fe5a00
Binary files /dev/null and b/tests/loaders/data/pcx/valid/ver3_0_palette_1bpp_10x10_white.pcx differ
diff --git a/tests/loaders/data/pcx/valid/ver3_0_palette_24bpp_10x10_white.pcx b/tests/loaders/data/pcx/valid/ver3_0_palette_24bpp_10x10_white.pcx
new file mode 100644
index 0000000..9bc48fb
Binary files /dev/null and b/tests/loaders/data/pcx/valid/ver3_0_palette_24bpp_10x10_white.pcx differ
diff --git a/tests/loaders/data/pcx/valid/ver3_0_palette_2bpp_10x10_white.pcx b/tests/loaders/data/pcx/valid/ver3_0_palette_2bpp_10x10_white.pcx
new file mode 100644
index 0000000..080a9af
Binary files /dev/null and b/tests/loaders/data/pcx/valid/ver3_0_palette_2bpp_10x10_white.pcx differ
diff --git a/tests/loaders/data/pcx/valid/ver3_0_palette_4bpp_10x10_white.pcx b/tests/loaders/data/pcx/valid/ver3_0_palette_4bpp_10x10_white.pcx
new file mode 100644
index 0000000..da88d77
Binary files /dev/null and b/tests/loaders/data/pcx/valid/ver3_0_palette_4bpp_10x10_white.pcx differ
diff --git a/tests/loaders/test_list.txt b/tests/loaders/test_list.txt
index d4410cb..d36b2a3 100644
--- a/tests/loaders/test_list.txt
+++ b/tests/loaders/test_list.txt
@@ -1,12 +1,13 @@
# Loaders testsuite
loaders_suite
PNG
+GIF
PBM
PGM
PPM
PNM
+PCX
ZIP
-GIF
IO
SaveLoad.gen
SaveAbort.gen
http://repo.or.cz/w/gfxprim.git/commit/cf801775780f7eab314e2ba9a166edc9ccdd…
commit cf801775780f7eab314e2ba9a166edc9ccdd708d
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Mon Jan 27 22:26:21 2014 +0100
Loaders: GP_IOFill: Set errno on end of file.
Signed-off-by: Cyril Hrubis <metan(a)ucw.cz>
diff --git a/libs/loaders/GP_IO.c b/libs/loaders/GP_IO.c
index e09df1b..9a5d949 100644
--- a/libs/loaders/GP_IO.c
+++ b/libs/loaders/GP_IO.c
@@ -295,7 +295,12 @@ int GP_IOFill(GP_IO *io, void *buf, size_t size)
ret = GP_IORead(io, (char*)buf + read, size - read);
if (ret <= 0) {
- GP_DEBUG(1, "Failed to fill buffer");
+ /* end of file */
+ if (ret == 0)
+ errno = EIO;
+
+ GP_DEBUG(1, "Failed to fill buffer: %s",
+ strerror(errno));
return 1;
}
-----------------------------------------------------------------------
Summary of changes:
build/syms/Loaders_symbols.txt | 4 +
demos/spiv/spiv.1 | 7 +-
demos/spiv/spiv_help.c | 7 +-
doc/about.txt | 5 +
doc/loaders.txt | 42 ++
doc/loaders_python.txt | 1 +
include/loaders/GP_Loaders.h | 1 +
include/loaders/{GP_JP2.h => GP_PCX.h} | 21 +-
libs/loaders/GP_IO.c | 7 +-
libs/loaders/GP_Loader.c | 12 +-
libs/loaders/GP_PCX.c | 473 ++++++++++++++++++++
pylib/gfxprim/loaders/loaders.i | 4 +
tests/loaders/.gitignore | 1 +
tests/loaders/Makefile | 5 +-
tests/loaders/PCX.c | 174 +++++++
.../pcx/valid/ver2_8_palette_4bpp_10x10_white.pcx | Bin 0 -> 148 bytes
.../pcx/valid/ver3_0_palette_1bpp_10x10_white.pcx | Bin 0 -> 148 bytes
.../pcx/valid/ver3_0_palette_24bpp_10x10_white.pcx | Bin 0 -> 148 bytes
.../pcx/valid/ver3_0_palette_2bpp_10x10_white.pcx | Bin 0 -> 148 bytes
.../pcx/valid/ver3_0_palette_4bpp_10x10_white.pcx | Bin 0 -> 148 bytes
tests/loaders/test_list.txt | 3 +-
21 files changed, 746 insertions(+), 21 deletions(-)
copy include/loaders/{GP_JP2.h => GP_PCX.h} (81%)
create mode 100644 libs/loaders/GP_PCX.c
create mode 100644 tests/loaders/PCX.c
create mode 100644 tests/loaders/data/pcx/valid/ver2_8_palette_4bpp_10x10_white.pcx
create mode 100644 tests/loaders/data/pcx/valid/ver3_0_palette_1bpp_10x10_white.pcx
create mode 100644 tests/loaders/data/pcx/valid/ver3_0_palette_24bpp_10x10_white.pcx
create mode 100644 tests/loaders/data/pcx/valid/ver3_0_palette_2bpp_10x10_white.pcx
create mode 100644 tests/loaders/data/pcx/valid/ver3_0_palette_4bpp_10x10_white.pcx
repo.or.cz automatic notification. Contact project admin jiri.bluebear.dluhos(a)gmail.com
if you want to unsubscribe, or site admin admin(a)repo.or.cz if you receive
no reply.
--
gfxprim.git ("A simple 2D graphics library with emphasis on correctness and well-defined operation.")
1
0