summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar jan.dudek2008-09-07 22:36:44 +0000
committerGravatar jan.dudek2008-09-07 22:36:44 +0000
commita6f8b9b9eb1f46998d5159daa25381a4b36e9ac6 (patch)
tree4aea6f33d67fa79661c5ea46c0b63c5aa64974ff
parentfe254bd0fa276971b728f20b5dd037a972c82979 (diff)
downloadgdk-pixbuf-psd-a6f8b9b9eb1f46998d5159daa25381a4b36e9ac6.tar.gz
gdk-pixbuf-psd-a6f8b9b9eb1f46998d5159daa25381a4b36e9ac6.tar.bz2
initial commit
git-svn-id: http://gdk-pixbuf-psd.googlecode.com/svn/trunk@2 c5539ac3-5556-0410-9a1f-7faf0b045682
-rw-r--r--Makefile14
-rw-r--r--io-psd.c251
2 files changed, 265 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..4f667b4
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,14 @@
1# ok, our Makefile slightly sucks at the moment
2
3CC = gcc
4CFLAGS=-Wall -std=c99
5
6all:
7 $(CC) $(CFLAGS) io-psd.c -o libpixbufloader-psd.so \
8 `pkg-config --cflags gtk+-2.0` \
9 -shared -fpic -DGDK_PIXBUF_ENABLE_BACKEND
10
11# and then run the following as root:
12# gdk-pixbuf-query-loaders libpixbufloader-psd.so >> /etc/gtk-2.0/gdk-pixbuf.loaders
13
14
diff --git a/io-psd.c b/io-psd.c
new file mode 100644
index 0000000..664d42f
--- /dev/null
+++ b/io-psd.c
@@ -0,0 +1,251 @@
1/* -*- mode: C; c-file-style: "linux" -*- */
2/* GdkPixbuf library - PSD image loader
3 *
4 * Copyright (C) 2008 Jan Dudek
5 *
6 * Authors: Jan Dudek <jd@jandudek.com>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
21 */
22
23#include <stdlib.h>
24#include <stdio.h>
25#include <gdk-pixbuf/gdk-pixbuf-io.h>
26#include <glib/gstdio.h>
27
28
29typedef struct
30{
31 guchar signature[4]; /* file ID, always "8BPS" */
32 guint16 version; /* version number, always 1 */
33 guchar reserved[6];
34 guint8 channels; /* number of color channels (1-24) */
35 guint32 rows; /* height of image in pixels (1-30000) */
36 guint32 columns; /* width of image in pixels (1-30000) */
37 guint16 depth; /* number of bits per channel (1, 8, and 16) */
38 guint16 color_mode; /* color mode as defined below */
39} PsdHeader;
40
41typedef enum
42{
43 PSD_MODE_MONO = 0,
44 PSD_MODE_GRAYSCALE = 1,
45 PSD_MODE_INDEXED = 2,
46 PSD_MODE_RGB = 3,
47 PSD_MODE_CMYK = 4,
48 PSD_MODE_MULTICHANNEL = 7,
49 PSD_MODE_DUOTONE = 8,
50 PSD_MODE_LAB = 9,
51} PsdColorMode;
52
53typedef enum
54{
55 PSD_COMPRESSION_NONE = 0,
56 PSD_COMPRESSION_RLE = 1
57} PsdCompressionType;
58
59static guint16
60read_uint16 (FILE *fp)
61{
62 guint16 t;
63 t = fgetc(fp) << 8;
64 t |= fgetc(fp);
65 return t;
66}
67
68static guint32
69read_uint32 (FILE *fp)
70{
71 guint32 t;
72 t = fgetc(fp) << 24;
73 t |= fgetc(fp) << 16;
74 t |= fgetc(fp) << 8;
75 t |= fgetc(fp);
76 return t;
77}
78
79static PsdHeader
80psd_read_header (FILE *fp)
81{
82 PsdHeader hd;
83 int t;
84
85 fread(hd.signature, 1, 4, fp);
86 hd.version = read_uint16(fp);
87 fread(hd.reserved, 1, 6, fp);
88 hd.channels = read_uint16(fp);
89 hd.rows = read_uint32(fp);
90 hd.columns = read_uint32(fp);
91 hd.depth = read_uint16(fp);
92 hd.color_mode = read_uint16(fp);
93
94 // skip Color Mode Data Block
95 t = read_uint32(fp);
96 fseek(fp, t, SEEK_CUR);
97
98 // skip Image Resources Block
99 t = read_uint32(fp);
100 fseek(fp, t, SEEK_CUR);
101
102 // skip Layer and Mask Information Block
103 t = read_uint32(fp);
104 fseek(fp, t, SEEK_CUR);
105
106 return hd;
107}
108
109static GdkPixbuf*
110gdk_pixbuf__psd_image_load (FILE *fp,
111 GError **error)
112{
113 guint rowstride;
114 guint16 compression_type;
115 guchar *pixels;
116 GdkPixbuf *pixbuf;
117 guchar **buffers;
118
119 PsdHeader hd = psd_read_header(fp);
120 pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, hd.columns, hd.rows);
121
122 if (pixbuf == NULL) {
123 g_set_error (error, GDK_PIXBUF_ERROR,
124 GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
125 ("Insufficient memory to load PSD image file"));
126 return NULL;
127 }
128
129 pixels = gdk_pixbuf_get_pixels (pixbuf);
130 rowstride = gdk_pixbuf_get_rowstride (pixbuf);
131
132 compression_type = read_uint16(fp);
133
134 if (compression_type != PSD_COMPRESSION_NONE &&
135 compression_type != PSD_COMPRESSION_RLE) {
136 g_set_error (error, GDK_PIXBUF_ERROR,
137 GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
138 ("Unsupported compression type"));
139 return NULL;
140 }
141
142 if (hd.color_mode != PSD_MODE_RGB) {
143 g_set_error (error, GDK_PIXBUF_ERROR,
144 GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
145 ("Unsupported color mode"));
146 return NULL;
147 }
148
149 //g_message("mode=%d, channels=%d", hd.color_mode, hd.channels);
150
151 buffers = g_malloc(sizeof(guchar*) * hd.channels);
152
153 if (compression_type == PSD_COMPRESSION_RLE) {
154 guint16 *line_lengths = g_malloc(2 * hd.rows * hd.channels);
155
156 for (int i = 0; i < hd.rows * hd.channels; ++i) {
157 line_lengths[i] = read_uint16(fp);
158 }
159
160 for (int i = 0; i < hd.channels; ++i) {
161 buffers[i] = g_malloc(hd.rows * hd.columns);
162 gint position = 0;
163
164 for (int j = 0; j < hd.rows; ++j) {
165 guint16 bytes_read = 0;
166 while (bytes_read < line_lengths[i * hd.rows + j]) {
167 gchar byte = fgetc(fp);
168 ++bytes_read;
169
170 if (byte == -128) {
171 continue;
172 } else if (byte > -1) {
173 gint count = byte + 1;
174
175 // copy next count bytes
176 for (int k = 0; k < count; ++k) {
177 buffers[i][position] = fgetc(fp);
178 ++bytes_read;
179 ++position;
180 }
181 } else {
182 gint count = -byte + 1;
183
184 // copy next byte count times
185 guchar next_byte = fgetc(fp);
186 ++bytes_read;
187 for (int k = 0; k < count; ++k) {
188 buffers[i][position] = next_byte;
189 ++position;
190 }
191 }
192 }
193 }
194 }
195
196 g_free(line_lengths);
197 }
198
199 if (hd.color_mode == PSD_MODE_RGB) {
200 for (int i = 0; i < hd.rows; ++i) {
201 for (int j = 0; j < hd.columns; ++j) {
202 pixels[i * rowstride + 3 * j + 0] = buffers[0][i * hd.columns + j];
203 pixels[i * rowstride + 3 * j + 1] = buffers[1][i * hd.columns + j];
204 pixels[i * rowstride + 3 * j + 2] = buffers[2][i * hd.columns + j];
205 }
206 }
207 }
208 // TODO: other color modes, CMYK at least
209
210 return pixbuf;
211}
212
213void
214fill_vtable (GdkPixbufModule* module)
215{
216/* module->load = gdk_pixbuf__xbm_image_load;
217 module->begin_load = gdk_pixbuf__xbm_image_begin_load;
218 module->stop_load = gdk_pixbuf__xbm_image_stop_loads
219 module->load_increment = gdk_pixbuf__xbm_image_load_increment;*/
220 // TODO progressive loading
221
222 module->load = gdk_pixbuf__psd_image_load;
223}
224
225void
226fill_info (GdkPixbufFormat *info)
227{
228 static GdkPixbufModulePattern signature[] = {
229 { "8BPS", NULL, 100 },
230 { NULL, NULL, 0 }
231 };
232 static gchar * mime_types[] = {
233 "image/x-psd",
234 NULL
235 };
236 static gchar * extensions[] = {
237 "psd",
238 NULL
239 };
240
241 info->name = "psd";
242 info->signature = signature;
243 //info->description = N_("Adobe Photoshop format");
244 info->description = "Adobe Photoshop format";
245 info->mime_types = mime_types;
246 info->extensions = extensions;
247 info->flags = GDK_PIXBUF_FORMAT_THREADSAFE;
248 info->flags = 0;
249 info->license = "LGPL";
250}
251