1 /* -*- mode: C; c-file-style: "linux" -*- */
2 /* GdkPixbuf library - SUNRAS image loader
4 * Copyright (C) 1999 The Free Software Foundation
6 * Authors: Arjan van de Ven <arjan@fenrus.demon.nl>
7 * Federico Mena-Quintero <federico@gimp.org>
9 * Based on io-gif.c, io-tiff.c and io-png.c
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the
23 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
24 * Boston, MA 02111-1307, USA.
30 * Compressed rasterfiles don't work yet
40 #include "gdk-pixbuf-private.h"
41 #include "gdk-pixbuf-io.h"
46 Header structure for sunras files.
47 All values are in big-endian order on disk
49 Note: Every scanline is padded to be a multiple of 16 bits
64 This does a byte-order swap. Does glib have something like
68 /* Progressive loading */
70 struct ras_progressive_state {
71 GdkPixbufModulePreparedFunc prepared_func;
72 GdkPixbufModuleUpdatedFunc updated_func;
75 gint HeaderSize; /* The size of the header-part (incl colormap) */
76 guchar *HeaderBuf; /* The buffer for the header (incl colormap) */
77 gint HeaderDone; /* The nr of bytes actually in HeaderBuf */
79 gint LineWidth; /* The width of a line in bytes */
80 guchar *LineBuf; /* Buffer for 1 line */
81 gint LineDone; /* # of bytes in LineBuf */
82 gint Lines; /* # of finished lines */
84 gint RasType; /* 32 = BGRA
91 struct rasterfile Header; /* Decoded (BE->CPU) header */
94 GdkPixbuf *pixbuf; /* Our "target" */
98 gdk_pixbuf__ras_image_begin_load(GdkPixbufModuleSizeFunc size_func,
99 GdkPixbufModulePreparedFunc prepared_func,
100 GdkPixbufModuleUpdatedFunc updated_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,
108 static gboolean RAS2State(struct rasterfile *RAS,
109 struct ras_progressive_state *State,
112 State->Header.width = GUINT32_FROM_BE(RAS->width);
113 State->Header.height = GUINT32_FROM_BE(RAS->height);
114 State->Header.depth = GUINT32_FROM_BE(RAS->depth);
115 State->Header.type = GUINT32_FROM_BE(RAS->type);
116 State->Header.maptype = GUINT32_FROM_BE(RAS->maptype);
117 State->Header.maplength = GUINT32_FROM_BE(RAS->maplength);
119 if ((gint)State->Header.width <= 0 ||
120 (gint)State->Header.height <= 0 ||
121 State->Header.maplength > 768) {
124 GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
125 _("RAS image has bogus header data"));
129 State->RasType = State->Header.depth; /* This may be less trivial someday */
130 State->HeaderSize = 32 + State->Header.maplength;
132 if (State->RasType == 32)
133 State->LineWidth = State->Header.width * 4;
134 else if (State->RasType == 24)
135 State->LineWidth = State->Header.width * 3;
136 else if (State->RasType == 8)
137 State->LineWidth = State->Header.width * 1;
138 else if (State->RasType == 1) {
139 State->LineWidth = State->Header.width / 8;
140 if ((State->Header.width & 7) != 0)
146 GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
147 _("RAS image has unknown type"));
151 if (State->Header.type > 2 || State->Header.maptype > 1) {
154 GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
155 _("unsupported RAS image variation"));
159 /* Now pad the line to be a multiple of 16 bits */
160 if ((State->LineWidth & 1) != 0)
163 if (!State->LineBuf) {
164 State->LineBuf = g_try_malloc (State->LineWidth);
166 if (!State->LineBuf) {
169 GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
170 _("Not enough memory to load RAS image"));
176 if (!State->pixbuf) {
177 if (State->RasType == 32)
178 State->pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8,
179 (gint) State->Header.width,
180 (gint) State->Header.height);
182 State->pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8,
183 (gint) State->Header.width,
184 (gint) State->Header.height);
186 if (!State->pixbuf) {
189 GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
190 _("Not enough memory to load RAS image"));
194 if (State->prepared_func != NULL)
195 /* Notify the client that we are ready to go */
196 (*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;
215 * func - called when we have pixmap created (but no image data)
216 * user_data - passed as arg 1 to func
217 * return context (opaque to user)
221 gdk_pixbuf__ras_image_begin_load(GdkPixbufModuleSizeFunc size_func,
222 GdkPixbufModulePreparedFunc prepared_func,
223 GdkPixbufModuleUpdatedFunc updated_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;
245 context->DecoderState = 0;
247 memset(&context->Header, 0, sizeof(struct rasterfile));
250 context->pixbuf = NULL;
253 return (gpointer) context;
257 * context - returned from image_begin_load
259 * free context, unref gdk_pixbuf
262 gdk_pixbuf__ras_image_stop_load(gpointer data, GError **error)
264 struct ras_progressive_state *context =
265 (struct ras_progressive_state *) data;
267 /* FIXME this thing needs to report errors if
268 * we have unused image data
271 g_return_val_if_fail(context != NULL, TRUE);
273 if (context->LineBuf != NULL)
274 g_free(context->LineBuf);
275 if (context->HeaderBuf != NULL)
276 g_free(context->HeaderBuf);
279 g_object_unref(context->pixbuf);
287 OneLine is called when enough data is received to process 1 line
291 static void OneLine32(struct ras_progressive_state *context)
297 Pixels = context->pixbuf->pixels + context->pixbuf->rowstride * context->Lines;
298 while (X < context->Header.width) {
299 /* The joys of having a BGR byteorder */
300 Pixels[X * 4 + 0] = context->LineBuf[X * 4 + 2];
301 Pixels[X * 4 + 1] = context->LineBuf[X * 4 + 1];
302 Pixels[X * 4 + 2] = context->LineBuf[X * 4 + 0];
303 Pixels[X * 4 + 3] = context->LineBuf[X * 4 + 3];
308 static void OneLine24(struct ras_progressive_state *context)
314 Pixels = context->pixbuf->pixels + context->pixbuf->rowstride * context->Lines;
315 while (X < context->Header.width) {
316 /* The joys of having a BGR byteorder */
317 Pixels[X * 3 + 0] = context->LineBuf[X * 3 + 2];
318 Pixels[X * 3 + 1] = context->LineBuf[X * 3 + 1];
319 Pixels[X * 3 + 2] = context->LineBuf[X * 3 + 0];
325 static void OneLine8(struct ras_progressive_state *context)
329 int offset = context->Header.maplength / 3;
332 Pixels = context->pixbuf->pixels + context->pixbuf->rowstride * context->Lines;
333 while (X < context->Header.width) {
334 /* The joys of having a BGR byteorder */
336 context->HeaderBuf[context->LineBuf[X] + 32];
338 context->HeaderBuf[context->LineBuf[X] + offset + 32];
340 context->HeaderBuf[context->LineBuf[X] + 2*offset + 32];
345 static void OneLine1(struct ras_progressive_state *context)
351 Pixels = context->pixbuf->pixels + context->pixbuf->rowstride * context->Lines;
352 while (X < context->Header.width) {
355 Bit = (context->LineBuf[X/8])>>(7-(X&7));
357 /* The joys of having a BGR byteorder */
359 context->HeaderBuf[Bit + 32];
361 context->HeaderBuf[Bit + 2 + 32];
363 context->HeaderBuf[Bit + 4 + 32];
369 static void OneLine(struct ras_progressive_state *context)
371 context->LineDone = 0;
372 if (context->Lines >= context->Header.height)
374 if (context->RasType == 32)
376 if (context->RasType == 24)
378 if (context->RasType == 8)
380 if (context->RasType == 1)
383 context->LineDone = 0;
386 if (context->updated_func != NULL) {
387 (*context->updated_func) (context->pixbuf,
390 context->Header.width,
398 DoCompressed (struct ras_progressive_state *context,
399 const guchar * buf, guint size,
404 for (i = 0; i < size; i++) {
405 switch (context->DecoderState) {
408 context->DecoderState = 1;
410 context->LineBuf[context->LineDone++] = buf[i];
414 context->LineBuf[context->LineDone++] = 0x80;
415 context->DecoderState = 0;
418 context->DecoderState = buf[i] + 1;
421 for (; context->DecoderState; context->DecoderState--) {
422 context->LineBuf[context->LineDone++] = buf[i];
423 if ((context->LineDone >= context->LineWidth) && (context->LineWidth > 0))
427 if ((context->LineDone >= context->LineWidth) && (context->LineWidth > 0))
434 * context - from image_begin_load
435 * buf - new image data
436 * size - length of new image data
438 * append image data onto incrementally built output image
441 gdk_pixbuf__ras_image_load_increment(gpointer data,
442 const guchar * buf, guint size,
445 struct ras_progressive_state *context =
446 (struct ras_progressive_state *) data;
451 if (context->HeaderDone < context->HeaderSize) { /* We still
452 have headerbytes to do */
454 context->HeaderSize - context->HeaderDone;
455 if (BytesToCopy > size)
458 memmove(context->HeaderBuf + context->HeaderDone,
463 context->HeaderDone += BytesToCopy;
465 } else if (context->Header.type == 2) {
466 if (!DoCompressed (context, buf, size, error)) {
473 context->LineWidth - context->LineDone;
474 if (BytesToCopy > size)
477 if (BytesToCopy > 0) {
478 memmove(context->LineBuf +
479 context->LineDone, buf,
484 context->LineDone += BytesToCopy;
486 if ((context->LineDone >= context->LineWidth) &&
487 (context->LineWidth > 0))
493 if (context->HeaderDone >= 32)
494 if (!RAS2State((struct rasterfile *) context->HeaderBuf,
506 MODULE_ENTRY (ras, fill_vtable) (GdkPixbufModule *module)
508 module->begin_load = gdk_pixbuf__ras_image_begin_load;
509 module->stop_load = gdk_pixbuf__ras_image_stop_load;
510 module->load_increment = gdk_pixbuf__ras_image_load_increment;
514 MODULE_ENTRY (ras, fill_info) (GdkPixbufFormat *info)
516 static GdkPixbufModulePattern signature[] = {
517 { "\x59\xa6\x6a\x95", NULL, 100 },
520 static gchar * mime_types[] = {
521 "image/x-cmu-raster",
522 "image/x-sun-raster",
525 static gchar * extensions[] = {
531 info->signature = signature;
532 info->description = N_("The Sun raster image format");
533 info->mime_types = mime_types;
534 info->extensions = extensions;