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