1 /* -*- Mode: C; tab-width: 3; indent-tabs-mode: nil; c-basic-offset: 3 -*- */
2
3 /*
4 * GImageView
5 * Copyright (C) 2001 Takuro Ashie
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 2 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, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 *
21 * $Id: spi_image_loader.c,v 1.8 2004/09/21 08:44:27 makeinu Exp $
22 */
23
24 #include "spi_image_loader.h"
25
26 #ifdef ENABLE_SPI
27
28 #include <string.h>
29
30 #include "spi.h"
31 #include "gimv_plugin.h"
32 #include "prefs_spi.h"
33
34 static GimvImageLoaderPlugin gimv_spi_loader[] =
35 {
36 {
37 if_version: GIMV_IMAGE_LOADER_IF_VERSION,
38 id: "SPI",
39 priority_hint: GIMV_IMAGE_LOADER_PRIORITY_LOW,
40 check_type: NULL,
41 get_info: NULL,
42 loader: spi_load_image,
43 }
44 };
45
46 GIMV_PLUGIN_GET_IMPL(gimv_spi_loader, GIMV_PLUGIN_IMAGE_LOADER)
47
48 GimvPluginInfo gimv_plugin_info =
49 {
50 if_version: GIMV_PLUGIN_IF_VERSION,
51 name: N_("Susie Plugin Image Loader"),
52 version: "0.1.1",
53 author: N_("Takuro Ashie"),
54 description: NULL,
55 get_implement: gimv_plugin_get_impl,
56 get_prefs_ui: gimv_prefs_ui_spi_get_page,
57 };
58 static GimvPluginInfo *this;
59
60
61 gchar *
g_module_check_init(GModule * module)62 g_module_check_init (GModule *module)
63 {
64 g_module_symbol (module, "gimv_plugin_info", (gpointer) &this);
65 return NULL;
66 }
67
68 GimvPluginInfo *
gimv_spi_plugin_get_info(void)69 gimv_spi_plugin_get_info (void)
70 {
71 return this;
72 }
73
74
75 #if 1
76
77 #warning FIXME!! should be integrated to Bitmap loader.
78
79 #define BI_RGB 0
80 #define BI_RLE8 1
81 #define BI_RLE4 2
82 #define BI_BITFIELDS 3
83
84 #define ToL(buffer, off) (buffer[(off)] \
85 | buffer[(off) + 1] << 8 \
86 | buffer[(off) + 2] << 16 \
87 | buffer[(off) + 3] << 24)
88
89 typedef struct BmpBitFields_Tag
90 {
91 gint r_mask, r_shift, r_bits;
92 gint g_mask, g_shift, g_bits;
93 gint b_mask, b_shift, b_bits;
94 } BmpBitFields;
95
96
97 static void
find_bits(gint n,gint * lowest,gint * n_set)98 find_bits (gint n, gint *lowest, gint *n_set)
99 {
100 gint i;
101
102 *n_set = 0;
103
104 for (i = 31; i >= 0; i--) {
105 if (n & (1 << i)) {
106 *lowest = i;
107 (*n_set)++;
108 }
109 }
110 }
111
112
113 static gboolean
dib_read_bitmasks(guchar * buf,BmpBitFields * bf)114 dib_read_bitmasks (guchar *buf,
115 BmpBitFields *bf)
116 {
117 bf->r_mask = ToL (buf, 0);
118 bf->g_mask = ToL (buf, 4);
119 bf->b_mask = ToL (buf, 8);
120
121 find_bits (bf->r_mask, &bf->r_shift, &bf->r_bits);
122 find_bits (bf->g_mask, &bf->g_shift, &bf->g_bits);
123 find_bits (bf->b_mask, &bf->b_shift, &bf->b_bits);
124
125 if (bf->r_bits == 0 || bf->g_bits == 0 || bf->b_bits == 0) {
126 bf->r_mask = 0x7c00;
127 bf->r_shift = 10;
128 bf->g_mask = 0x03e0;
129 bf->g_shift = 5;
130 bf->b_mask = 0x001f;
131 bf->b_shift = 0;
132
133 bf->r_bits = bf->g_bits = bf->b_bits = 5;
134 }
135
136 return TRUE;
137 }
138
139
140 static gboolean
dib_read_color_map(guchar * rgb,guchar buffer[256][3],gint number,gint size,gint * grey)141 dib_read_color_map (guchar *rgb,
142 guchar buffer[256][3],
143 gint number,
144 gint size,
145 gint *grey)
146 {
147 gint i;
148
149 *grey = (number > 2);
150 for (i = 0; i < number ; i++) {
151 if (size == 4) {
152 buffer[i][0] = rgb[i * size + 2];
153 buffer[i][1] = rgb[i * size + 1];
154 buffer[i][2] = rgb[i * size];
155 } else {
156 buffer[i][0] = rgb[i * size + 1];
157 buffer[i][1] = rgb[i * size];
158 buffer[i][2] = rgb[i * size + 2];
159 }
160 *grey = ((*grey) && (rgb[0] == rgb[1]) && (rgb[1] == rgb[2]));
161 }
162 return TRUE;
163 }
164
165
166 static GimvImage *
dib_read_image(guchar * image,BITMAPINFOHEADER * bih,guchar cmap[256][3],BmpBitFields * bf,gint bytes_per_line,gint grey)167 dib_read_image (guchar *image,
168 BITMAPINFOHEADER *bih,
169 guchar cmap[256][3],
170 BmpBitFields *bf,
171 gint bytes_per_line,
172 gint grey)
173 {
174 GimvImage *gimv_image;
175 gint ystart = 0;
176 guchar *data, *src, *dest;
177
178 ystart = bih->biHeight - 1;
179
180 data = g_malloc (sizeof (guchar) * bih->biWidth * bih->biHeight * 3);
181
182 if (bih->biBitCount == 32) {
183 g_print ("32bit DIB image is not supported yet\n");
184
185 } else if (bih->biBitCount == 24) {
186 gint i, j;
187
188 for (j = ystart; j >= 0; j--) {
189 for (i = 0; i < bih->biWidth; i++) {
190 src = image + (i * 3) + (bytes_per_line * j);
191 dest = data + (i * 3) + (bih->biWidth * 3 * (bih->biHeight - 1 - j));
192 dest[0] = src[2];
193 dest[1] = src[1];
194 dest[2] = src[0];
195 }
196 }
197
198 } else if (bih->biBitCount == 16) {
199 gint xpos = 0, ypos = ystart;
200
201 while (ypos >= 0) {
202 src = image + (xpos * 2) + (bytes_per_line * ypos);
203 dest = data + (xpos++ * 3) + (bih->biWidth * ypos * 3);
204
205 dest[0] = (src[1] << 1) & 0xf8;
206 dest[1] = ((src[1] >> 5) & 0x04)
207 | ((src[1] << 6) & 0xc0)
208 | ((src[0] >> 2) & 0x38);
209 dest[2] = (src[0] << 3) & 0xf8;
210
211 if (xpos == bih->biWidth) {
212 ypos--;
213 xpos = 0;
214 }
215 }
216
217 } else {
218 gint xpos = 0, ypos = ystart, i, pix;
219
220 switch (bih->biCompression) {
221 case BI_RGB: /* uncompressed */
222 while (ypos >= 0) {
223 src = image + xpos + (bytes_per_line * ypos);
224 for (i = 1; (i <= (8 / bih->biBitCount)) && (xpos <= bih->biWidth); i++) {
225 dest = data + (xpos * 3) + (bih->biWidth * 3 * (bih->biHeight - 1 - ypos));
226 pix = (*src & (((1 << bih->biBitCount) - 1)
227 << (8 - (i * bih->biBitCount))))
228 >> (8 - (i * bih->biBitCount));
229 dest[0] = cmap[pix][0];
230 dest[1] = cmap[pix][1];
231 dest[2] = cmap[pix][2];
232
233 xpos++;
234 }
235 if (xpos >= bih->biWidth) {
236 ypos--;
237 xpos = 0;
238 }
239 }
240 break;
241
242 default: /* Compressed images */
243 g_print ("RLE compressed DIB image is not supported yet.\n");
244 break;
245 }
246 }
247
248 gimv_image = gimv_image_create_from_data (data,
249 bih->biWidth, bih->biHeight,
250 FALSE);
251
252 return gimv_image;
253 }
254
255
256 static GimvImage *
dib_load(BITMAPINFOHEADER * bih,guchar * image)257 dib_load(BITMAPINFOHEADER *bih, guchar *image)
258 {
259 gint maps = 4;
260 gint cmap_size, bytes_per_line, grey;
261 guchar *cmap_ptr, cmap[256][3];
262 BmpBitFields bf;
263 gboolean success;
264 GimvImage *gimv_image;
265
266 if (bih->biBitCount == 4)
267 cmap_size = 16;
268 else if (bih->biBitCount == 8)
269 cmap_size = 256;
270 else
271 cmap_size = 0;
272
273 if ((bih->biClrUsed == 0) && (bih->biBitCount < 24))
274 bih->biClrUsed = cmap_size;
275
276 if (bih->biBitCount == 32 || bih->biBitCount == 24 || bih->biBitCount == 16) {
277 bytes_per_line = bih->biSizeImage / bih->biHeight;
278 } else {
279 bytes_per_line = (bih->biSizeImage / bih->biHeight) * (8 / bih->biBitCount);
280 }
281
282 cmap_ptr = (guchar *) bih + sizeof(BITMAPINFOHEADER);
283
284 if (bih->biCompression == BI_BITFIELDS) {
285 /* BitFields compression */
286 success = dib_read_bitmasks (cmap_ptr, &bf);
287 if (!success) return NULL;
288 } else {
289 /* Get Colormap (1, 4, 8 bpp) */
290 success = dib_read_color_map (cmap_ptr, cmap, cmap_size, maps, &grey);
291 if (!success) return NULL;
292 }
293
294 /* read image!! */
295 gimv_image = dib_read_image (image, bih,
296 cmap, &bf,
297 bytes_per_line, grey);
298
299 return gimv_image;
300 }
301 #endif
302
303
304 static GimvImage *
spi_image_loader_load(SpiImportFilter * loader,const gchar * filename)305 spi_image_loader_load (SpiImportFilter *loader, const gchar *filename)
306 {
307 guchar buf[2048], *image;
308 gint result;
309 FILE *file;
310 PictureInfo info;
311 BITMAPINFOHEADER *bih;
312 gchar *description;
313 GimvImage *gimv_image;
314
315 g_return_val_if_fail (loader, NULL);
316 g_return_val_if_fail (filename, NULL);
317
318 description = ((SusiePlugin *) loader)->description;
319
320 file = fopen (filename, "rb");
321 if (!file) return NULL;
322
323 memset(buf, 0, 2048);
324 fread(buf, 2048, 1, file);
325
326 #if 0
327 cygwin_conv_to_win32_path (filename, filename_w32);
328 #endif
329
330 g_print ("trying to load image by spi...\n"
331 " File Name: %s\n"
332 " SPI : %s\n",
333 filename, description);
334 result = loader->get_pic_info ((char *) filename, 0, 0, &info);
335 if (result == SPI_SUCCESS)
336 g_print ("This image type is supported by spi: %s\n", description);
337 else
338 goto ERROR0;
339
340 result = loader->get_pic((char *) filename, 0, 0,
341 (HANDLE) &bih,
342 (HANDLE) &image,
343 NULL,
344 0);
345
346 if (result != SPI_SUCCESS)
347 goto ERROR0;
348
349 g_print ("succeeded to load!\n");
350
351 gimv_image = dib_load(bih, image);
352 if (gimv_image)
353 g_print ("succeeded to translate from DIB to GimvImage.\n\n");
354 else
355 g_print ("faild to translate from DIB to GimvImage.\n\n");
356
357 g_free (bih);
358 g_free (image);
359 fclose (file);
360
361 return gimv_image;
362
363 ERROR0:
364 fclose (file);
365 if (result >= 0 && result < spi_errormsg_num)
366 g_print ("spi error message: %s\n\n", spi_errormsg[result]);
367
368 return NULL;
369 }
370
371
372 GimvImage *
spi_load_image(GimvImageLoader * loader,gpointer data)373 spi_load_image (GimvImageLoader *loader, gpointer data)
374 {
375 const gchar *filename;
376 GList *list, *node;
377 GimvImage *image = NULL;
378
379 g_return_val_if_fail (loader, NULL);
380
381 filename = gimv_image_loader_get_path (loader);
382 if (!filename || !*filename) return NULL;
383
384 list = spi_get_import_filter_list ();
385
386 for (node = list; node; node = g_list_next (node)) {
387 SpiImportFilter *loader = node->data;
388
389 if (!loader) continue;
390
391 image = spi_image_loader_load (loader, filename);
392 if (image) break;
393 }
394
395 return image;
396 }
397
398 #endif
399