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
February 2014
- 1 participants
- 6 discussions
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