1 /* GIMP - The GNU Image Manipulation Program
2 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3 *
4 * GIMP PSD Plug-in
5 * Copyright 2007 by John Marshall
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
21 #include "config.h"
22
23 #include <string.h>
24 #include <errno.h>
25
26 #include <glib/gstdio.h>
27 #include <libgimp/gimp.h>
28
29 #include "psd.h"
30 #include "psd-util.h"
31 #include "psd-image-res-load.h"
32 #include "psd-thumb-load.h"
33
34 #include "libgimp/stdplugins-intl.h"
35
36 /* Local function prototypes */
37 static gint read_header_block (PSDimage *img_a,
38 FILE *f,
39 GError **error);
40
41 static gint read_color_mode_block (PSDimage *img_a,
42 FILE *f,
43 GError **error);
44
45 static gint read_image_resource_block (PSDimage *img_a,
46 FILE *f,
47 GError **error);
48
49 static gint32 create_gimp_image (PSDimage *img_a,
50 const gchar *filename);
51
52 static gint add_image_resources (gint32 image_id,
53 PSDimage *img_a,
54 FILE *f,
55 GError **error);
56
57 /* Main file load function */
58 gint32
load_thumbnail_image(const gchar * filename,gint * width,gint * height,GError ** load_error)59 load_thumbnail_image (const gchar *filename,
60 gint *width,
61 gint *height,
62 GError **load_error)
63 {
64 FILE *f;
65 GStatBuf st;
66 PSDimage img_a;
67 gint32 image_id = -1;
68 GError *error = NULL;
69
70 /* ----- Open PSD file ----- */
71 if (g_stat (filename, &st) == -1)
72 return -1;
73
74 gimp_progress_init_printf (_("Opening thumbnail for '%s'"),
75 gimp_filename_to_utf8 (filename));
76
77 IFDBG(1) g_debug ("Open file %s", gimp_filename_to_utf8 (filename));
78 f = g_fopen (filename, "rb");
79 if (f == NULL)
80 {
81 g_set_error (load_error, G_FILE_ERROR, g_file_error_from_errno (errno),
82 _("Could not open '%s' for reading: %s"),
83 gimp_filename_to_utf8 (filename), g_strerror (errno));
84 return -1;
85 }
86
87 /* ----- Read the PSD file Header block ----- */
88 IFDBG(2) g_debug ("Read header block");
89 if (read_header_block (&img_a, f, &error) < 0)
90 goto load_error;
91 gimp_progress_update (0.2);
92
93 /* ----- Read the PSD file Color Mode block ----- */
94 IFDBG(2) g_debug ("Read color mode block");
95 if (read_color_mode_block (&img_a, f, &error) < 0)
96 goto load_error;
97 gimp_progress_update (0.4);
98
99 /* ----- Read the PSD file Image Resource block ----- */
100 IFDBG(2) g_debug ("Read image resource block");
101 if (read_image_resource_block (&img_a, f, &error) < 0)
102 goto load_error;
103 gimp_progress_update (0.6);
104
105 /* ----- Create GIMP image ----- */
106 IFDBG(2) g_debug ("Create GIMP image");
107 image_id = create_gimp_image (&img_a, filename);
108 if (image_id < 0)
109 goto load_error;
110
111 /* ----- Add image resources ----- */
112 IFDBG(2) g_debug ("Add image resources");
113 if (add_image_resources (image_id, &img_a, f, &error) < 1)
114 goto load_error;
115 gimp_progress_update (1.0);
116
117 gimp_image_clean_all (image_id);
118 gimp_image_undo_enable (image_id);
119 fclose (f);
120
121 *width = img_a.columns;
122 *height = img_a.rows;
123 return image_id;
124
125 /* ----- Process load errors ----- */
126 load_error:
127 if (error)
128 {
129 g_set_error (load_error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
130 _("Error loading PSD file: %s"), error->message);
131 g_error_free (error);
132 }
133
134 /* Delete partially loaded image */
135 if (image_id > 0)
136 gimp_image_delete (image_id);
137
138 /* Close file if Open */
139 if (! (f == NULL))
140 fclose (f);
141
142 return -1;
143 }
144
145
146 /* Local functions */
147
148 static gint
read_header_block(PSDimage * img_a,FILE * f,GError ** error)149 read_header_block (PSDimage *img_a,
150 FILE *f,
151 GError **error)
152 {
153 guint16 version;
154 gchar sig[4];
155 gchar buf[6];
156
157 if (fread (sig, 4, 1, f) < 1
158 || fread (&version, 2, 1, f) < 1
159 || fread (buf, 6, 1, f) < 1
160 || fread (&img_a->channels, 2, 1, f) < 1
161 || fread (&img_a->rows, 4, 1, f) < 1
162 || fread (&img_a->columns, 4, 1, f) < 1
163 || fread (&img_a->bps, 2, 1, f) < 1
164 || fread (&img_a->color_mode, 2, 1, f) < 1)
165 {
166 psd_set_error (feof (f), errno, error);
167 return -1;
168 }
169 version = GUINT16_FROM_BE (version);
170 img_a->channels = GUINT16_FROM_BE (img_a->channels);
171 img_a->rows = GUINT32_FROM_BE (img_a->rows);
172 img_a->columns = GUINT32_FROM_BE (img_a->columns);
173 img_a->bps = GUINT16_FROM_BE (img_a->bps);
174 img_a->color_mode = GUINT16_FROM_BE (img_a->color_mode);
175
176 IFDBG(1) g_debug ("\n\n\tSig: %.4s\n\tVer: %d\n\tChannels: "
177 "%d\n\tSize: %dx%d\n\tBPS: %d\n\tMode: %d\n",
178 sig, version, img_a->channels,
179 img_a->columns, img_a->rows,
180 img_a->bps, img_a->color_mode);
181
182 if (memcmp (sig, "8BPS", 4) != 0)
183 return -1;
184
185 if (version != 1)
186 return -1;
187
188 if (img_a->channels > MAX_CHANNELS)
189 return -1;
190
191 if (img_a->rows < 1 || img_a->rows > GIMP_MAX_IMAGE_SIZE)
192 return -1;
193
194 if (img_a->columns < 1 || img_a->columns > GIMP_MAX_IMAGE_SIZE)
195 return -1;
196
197 return 0;
198 }
199
200 static gint
read_color_mode_block(PSDimage * img_a,FILE * f,GError ** error)201 read_color_mode_block (PSDimage *img_a,
202 FILE *f,
203 GError **error)
204 {
205 guint32 block_len;
206 guint32 block_start;
207 guint32 block_end;
208
209 if (fread (&block_len, 4, 1, f) < 1)
210 {
211 psd_set_error (feof (f), errno, error);
212 return -1;
213 }
214 block_len = GUINT32_FROM_BE (block_len);
215
216 block_start = ftell (f);
217 block_end = block_start + block_len;
218
219 if (fseek (f, block_end, SEEK_SET) < 0)
220 {
221 psd_set_error (feof (f), errno, error);
222 return -1;
223 }
224
225 return 0;
226 }
227
228 static gint
read_image_resource_block(PSDimage * img_a,FILE * f,GError ** error)229 read_image_resource_block (PSDimage *img_a,
230 FILE *f,
231 GError **error)
232 {
233 guint32 block_len;
234 guint32 block_end;
235
236 if (fread (&block_len, 4, 1, f) < 1)
237 {
238 psd_set_error (feof (f), errno, error);
239 return -1;
240 }
241 img_a->image_res_len = GUINT32_FROM_BE (block_len);
242
243 IFDBG(1) g_debug ("Image resource block size = %d", (int)img_a->image_res_len);
244
245 img_a->image_res_start = ftell (f);
246 block_end = img_a->image_res_start + img_a->image_res_len;
247
248 if (fseek (f, block_end, SEEK_SET) < 0)
249 {
250 psd_set_error (feof (f), errno, error);
251 return -1;
252 }
253
254 return 0;
255 }
256
257 static gint32
create_gimp_image(PSDimage * img_a,const gchar * filename)258 create_gimp_image (PSDimage *img_a,
259 const gchar *filename)
260 {
261 gint32 image_id = -1;
262
263 img_a->base_type = GIMP_RGB;
264
265 /* Create gimp image */
266 IFDBG(2) g_debug ("Create image");
267 image_id = gimp_image_new (img_a->columns, img_a->rows, img_a->base_type);
268
269 gimp_image_set_filename (image_id, filename);
270 gimp_image_undo_disable (image_id);
271
272 return image_id;
273 }
274
275 static gint
add_image_resources(gint32 image_id,PSDimage * img_a,FILE * f,GError ** error)276 add_image_resources (gint32 image_id,
277 PSDimage *img_a,
278 FILE *f,
279 GError **error)
280 {
281 PSDimageres res_a;
282 gint status;
283
284 if (fseek (f, img_a->image_res_start, SEEK_SET) < 0)
285 {
286 psd_set_error (feof (f), errno, error);
287 return -1;
288 }
289
290 while (ftell (f) < img_a->image_res_start + img_a->image_res_len)
291 {
292 if (get_image_resource_header (&res_a, f, error) < 0)
293 return -1;
294
295 if (res_a.data_start + res_a.data_len >
296 img_a->image_res_start + img_a->image_res_len)
297 return 0;
298
299 status = load_thumbnail_resource (&res_a, image_id, f, error);
300 /* Error */
301 if (status < 0)
302 return -1;
303 /* Thumbnail Loaded */
304 if (status > 0)
305 return 1;
306 }
307
308 return 0;
309 }
310