1 /* GdkPixbuf library - SUNRAS image loader
3 * Copyright (C) 1999 The Free Software Foundation
5 * Authors: Arjan van de Ven <arjan@fenrus.demon.nl>
6 * Federico Mena-Quintero <federico@gimp.org>
8 * Based on io-gif.c, io-tiff.c and io-png.c
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the
22 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 * Boston, MA 02111-1307, USA.
29 * Compressed rasterfiles don't work yet
39 #include "gdk-pixbuf-private.h"
40 #include "gdk-pixbuf-io.h"
45 Header structure for sunras files.
46 All values are in big-endian order on disk
48 Note: Every scanline is padded to be a multiple of 16 bits
63 This does a byte-order swap. Does glib have something like
67 /* Progressive loading */
69 struct ras_progressive_state {
70 ModulePreparedNotifyFunc prepared_func;
71 ModuleUpdatedNotifyFunc updated_func;
74 gint HeaderSize; /* The size of the header-part (incl colormap) */
75 guchar *HeaderBuf; /* The buffer for the header (incl colormap) */
76 gint HeaderDone; /* The nr of bytes actually in HeaderBuf */
78 gint LineWidth; /* The width of a line in bytes */
79 guchar *LineBuf; /* Buffer for 1 line */
80 gint LineDone; /* # of bytes in LineBuf */
81 gint Lines; /* # of finished lines */
83 gint RasType; /* 32 = BGRA
90 struct rasterfile Header; /* Decoded (BE->CPU) header */
93 GdkPixbuf *pixbuf; /* Our "target" */
97 gdk_pixbuf__ras_image_begin_load(ModulePreparedNotifyFunc prepared_func,
98 ModuleUpdatedNotifyFunc updated_func,
99 ModuleFrameDoneNotifyFunc frame_done_func,
100 ModuleAnimationDoneNotifyFunc anim_done_func,
103 static gboolean gdk_pixbuf__ras_image_stop_load(gpointer data, GError **error);
104 static gboolean gdk_pixbuf__ras_image_load_increment(gpointer data,
105 const guchar * buf, guint size,
110 /* Shared library entry point */
111 static GdkPixbuf *gdk_pixbuf__ras_image_load(FILE * f, GError **error)
115 struct ras_progressive_state *State;
119 State = gdk_pixbuf__ras_image_begin_load(NULL, NULL, NULL,
122 membuf = g_malloc(4096);
124 g_assert(membuf != NULL);
126 while (feof(f) == 0) {
127 length = fread(membuf, 1, 4096, f);
128 if (!gdk_pixbuf__ras_image_load_increment(State, membuf, length,
130 gdk_pixbuf__ras_image_stop_load (State, NULL);
135 if (State->pixbuf != NULL)
136 gdk_pixbuf_ref(State->pixbuf);
140 gdk_pixbuf__ras_image_stop_load(State, NULL);
144 static void RAS2State(struct rasterfile *RAS,
145 struct ras_progressive_state *State)
147 State->Header.width = GUINT32_FROM_BE(RAS->width);
148 State->Header.height = GUINT32_FROM_BE(RAS->height);
149 State->Header.depth = GUINT32_FROM_BE(RAS->depth);
150 State->Header.type = GUINT32_FROM_BE(RAS->type);
151 State->Header.maptype = GUINT32_FROM_BE(RAS->maptype);
152 State->Header.maplength = GUINT32_FROM_BE(RAS->maplength);
154 g_assert(State->Header.maplength <= 768); /* Otherwise, we are in trouble */
156 State->RasType = State->Header.depth; /* This may be less trivial someday */
157 State->HeaderSize = 32 + State->Header.maplength;
159 if (State->RasType == 32)
160 State->LineWidth = State->Header.width * 4;
161 if (State->RasType == 24)
162 State->LineWidth = State->Header.width * 3;
163 if (State->RasType == 8)
164 State->LineWidth = State->Header.width * 1;
165 if (State->RasType == 1) {
166 State->LineWidth = State->Header.width / 8;
167 if ((State->Header.width & 7) != 0)
171 /* Now padd the line to be a multiple of 16 bits */
172 if ((State->LineWidth & 1) != 0)
175 if (State->LineBuf == NULL)
176 State->LineBuf = g_malloc(State->LineWidth);
178 g_assert(State->LineBuf != NULL);
181 if (State->pixbuf == NULL) {
182 if (State->RasType == 32)
183 State->pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE,
192 gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8,
193 (gint) State->Header.width,
194 (gint) State->Header.height);
195 if (State->prepared_func != NULL)
196 /* Notify the client that we are ready to go */
197 (*State->prepared_func) (State->pixbuf,
202 if ((State->Header.maplength==0)&&(State->RasType==1)) {
203 State->HeaderBuf[32] = 255;
204 State->HeaderBuf[33] = 0;
205 State->HeaderBuf[34] = 255;
206 State->HeaderBuf[35] = 0;
207 State->HeaderBuf[36] = 255;
208 State->HeaderBuf[37] = 0;
214 * func - called when we have pixmap created (but no image data)
215 * user_data - passed as arg 1 to func
216 * return context (opaque to user)
220 gdk_pixbuf__ras_image_begin_load(ModulePreparedNotifyFunc prepared_func,
221 ModuleUpdatedNotifyFunc updated_func,
222 ModuleFrameDoneNotifyFunc frame_done_func,
223 ModuleAnimationDoneNotifyFunc anim_done_func,
227 struct ras_progressive_state *context;
229 context = g_new0(struct ras_progressive_state, 1);
230 context->prepared_func = prepared_func;
231 context->updated_func = updated_func;
232 context->user_data = user_data;
234 context->HeaderSize = 32;
235 context->HeaderBuf = g_malloc(32 + 768); /* 32 for rasheader,
236 768 for the colormap */
237 context->HeaderDone = 0;
239 context->LineWidth = 0;
240 context->LineBuf = NULL;
241 context->LineDone = 0;
244 context->RasType = 0;
246 memset(&context->Header, 0, sizeof(struct rasterfile));
249 context->pixbuf = NULL;
252 return (gpointer) context;
256 * context - returned from image_begin_load
258 * free context, unref gdk_pixbuf
261 gdk_pixbuf__ras_image_stop_load(gpointer data, GError **error)
263 struct ras_progressive_state *context =
264 (struct ras_progressive_state *) data;
266 /* FIXME this thing needs to report errors if
267 * we have unused image data
270 g_return_val_if_fail(context != NULL, TRUE);
272 if (context->LineBuf != NULL)
273 g_free(context->LineBuf);
274 if (context->HeaderBuf != NULL)
275 g_free(context->HeaderBuf);
278 gdk_pixbuf_unref(context->pixbuf);
286 OneLine is called when enough data is received to process 1 line
290 static void OneLine32(struct ras_progressive_state *context)
296 Pixels = context->pixbuf->pixels + context->pixbuf->rowstride * context->Lines;
297 while (X < context->Header.width) {
298 /* The joys of having a BGR byteorder */
299 Pixels[X * 4 + 0] = context->LineBuf[X * 4 + 2];
300 Pixels[X * 4 + 1] = context->LineBuf[X * 4 + 1];
301 Pixels[X * 4 + 2] = context->LineBuf[X * 4 + 0];
302 Pixels[X * 4 + 3] = context->LineBuf[X * 4 + 3];
307 static void OneLine24(struct ras_progressive_state *context)
313 Pixels = context->pixbuf->pixels + context->pixbuf->rowstride * context->Lines;
314 while (X < context->Header.width) {
315 /* The joys of having a BGR byteorder */
316 Pixels[X * 3 + 0] = context->LineBuf[X * 3 + 2];
317 Pixels[X * 3 + 1] = context->LineBuf[X * 3 + 1];
318 Pixels[X * 3 + 2] = context->LineBuf[X * 3 + 0];
324 static void OneLine8(struct ras_progressive_state *context)
330 Pixels = context->pixbuf->pixels + context->pixbuf->rowstride * context->Lines;
331 while (X < context->Header.width) {
332 /* The joys of having a BGR byteorder */
334 context->HeaderBuf[context->LineBuf[X] + 32];
336 context->HeaderBuf[context->LineBuf[X] + 256 + 32];
338 context->HeaderBuf[context->LineBuf[X] + 512 + 32];
343 static void OneLine1(struct ras_progressive_state *context)
349 Pixels = context->pixbuf->pixels + context->pixbuf->rowstride * context->Lines;
350 while (X < context->Header.width) {
353 Bit = (context->LineBuf[X/8])>>(7-(X&7));
355 /* The joys of having a BGR byteorder */
357 context->HeaderBuf[Bit + 32];
359 context->HeaderBuf[Bit + 2 + 32];
361 context->HeaderBuf[Bit + 4 + 32];
367 static void OneLine(struct ras_progressive_state *context)
369 if (context->RasType == 32)
371 if (context->RasType == 24)
373 if (context->RasType == 8)
375 if (context->RasType == 1)
378 context->LineDone = 0;
379 if (context->Lines > context->Header.height)
383 if (context->updated_func != NULL) {
384 (*context->updated_func) (context->pixbuf,
387 context->Header.width,
388 context->Header.height,
395 * context - from image_begin_load
396 * buf - new image data
397 * size - length of new image data
399 * append image data onto inrecrementally built output image
402 gdk_pixbuf__ras_image_load_increment(gpointer data,
403 const guchar * buf, guint size,
406 struct ras_progressive_state *context =
407 (struct ras_progressive_state *) data;
412 if (context->HeaderDone < context->HeaderSize) { /* We still
413 have headerbytes to do */
415 context->HeaderSize - context->HeaderDone;
416 if (BytesToCopy > size)
419 memmove(context->HeaderBuf + context->HeaderDone,
424 context->HeaderDone += BytesToCopy;
429 context->LineWidth - context->LineDone;
430 if (BytesToCopy > size)
433 if (BytesToCopy > 0) {
434 memmove(context->LineBuf +
435 context->LineDone, buf,
440 context->LineDone += BytesToCopy;
442 if ((context->LineDone >= context->LineWidth) &&
443 (context->LineWidth > 0))
449 if (context->HeaderDone >= 32)
450 RAS2State((struct rasterfile *) context->HeaderBuf,
460 gdk_pixbuf__ras_fill_vtable (GdkPixbufModule *module)
462 module->load = gdk_pixbuf__ras_image_load;
463 module->begin_load = gdk_pixbuf__ras_image_begin_load;
464 module->stop_load = gdk_pixbuf__ras_image_stop_load;
465 module->load_increment = gdk_pixbuf__ras_image_load_increment;