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 GdkPixbufModuleSizeFunc size_func;
72 GdkPixbufModulePreparedFunc prepared_func;
73 GdkPixbufModuleUpdatedFunc updated_func;
76 gint HeaderSize; /* The size of the header-part (incl colormap) */
77 guchar *HeaderBuf; /* The buffer for the header (incl colormap) */
78 gint HeaderDone; /* The nr of bytes actually in HeaderBuf */
80 gint LineWidth; /* The width of a line in bytes */
81 guchar *LineBuf; /* Buffer for 1 line */
82 gint LineDone; /* # of bytes in LineBuf */
83 gint Lines; /* # of finished lines */
85 gint RasType; /* 32 = BGRA
92 struct rasterfile Header; /* Decoded (BE->CPU) header */
95 GdkPixbuf *pixbuf; /* Our "target" */
99 gdk_pixbuf__ras_image_begin_load(GdkPixbufModuleSizeFunc size_func,
100 GdkPixbufModulePreparedFunc prepared_func,
101 GdkPixbufModuleUpdatedFunc updated_func,
104 static gboolean gdk_pixbuf__ras_image_stop_load(gpointer data, GError **error);
105 static gboolean gdk_pixbuf__ras_image_load_increment(gpointer data,
106 const guchar * buf, guint size,
109 static gboolean RAS2State(struct rasterfile *RAS,
110 struct ras_progressive_state *State,
113 State->Header.width = GUINT32_FROM_BE(RAS->width);
114 State->Header.height = GUINT32_FROM_BE(RAS->height);
115 State->Header.depth = GUINT32_FROM_BE(RAS->depth);
116 State->Header.type = GUINT32_FROM_BE(RAS->type);
117 State->Header.maptype = GUINT32_FROM_BE(RAS->maptype);
118 State->Header.maplength = GUINT32_FROM_BE(RAS->maplength);
120 if ((gint)State->Header.width <= 0 ||
121 (gint)State->Header.height <= 0 ||
122 State->Header.maplength > 768) {
125 GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
126 _("RAS image has bogus header data"));
130 State->RasType = State->Header.depth; /* This may be less trivial someday */
131 State->HeaderSize = 32 + State->Header.maplength;
133 if (State->RasType == 32)
134 State->LineWidth = State->Header.width * 4;
135 else if (State->RasType == 24)
136 State->LineWidth = State->Header.width * 3;
137 else if (State->RasType == 8)
138 State->LineWidth = State->Header.width * 1;
139 else if (State->RasType == 1) {
140 State->LineWidth = State->Header.width / 8;
141 if ((State->Header.width & 7) != 0)
147 GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
148 _("RAS image has unknown type"));
152 if (State->Header.type > 2 || State->Header.maptype > 1) {
155 GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
156 _("unsupported RAS image variation"));
160 /* Now pad the line to be a multiple of 16 bits */
161 if ((State->LineWidth & 1) != 0)
164 if (!State->LineBuf) {
165 State->LineBuf = g_try_malloc (State->LineWidth);
167 if (!State->LineBuf) {
170 GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
171 _("Not enough memory to load RAS image"));
177 if (!State->pixbuf) {
178 if (State->size_func) {
179 gint width = State->Header.width;
180 gint height = State->Header.height;
182 (*State->size_func) (&width, &height, State->user_data);
183 if (width == 0 || height == 0)
187 if (State->RasType == 32)
188 State->pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8,
189 (gint) State->Header.width,
190 (gint) State->Header.height);
192 State->pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8,
193 (gint) State->Header.width,
194 (gint) State->Header.height);
196 if (!State->pixbuf) {
199 GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
200 _("Not enough memory to load RAS image"));
204 if (State->prepared_func != NULL)
205 /* Notify the client that we are ready to go */
206 (*State->prepared_func) (State->pixbuf,
212 if ((State->Header.maplength == 0) && (State->RasType == 1)) {
213 State->HeaderBuf[32] = 255;
214 State->HeaderBuf[33] = 0;
215 State->HeaderBuf[34] = 255;
216 State->HeaderBuf[35] = 0;
217 State->HeaderBuf[36] = 255;
218 State->HeaderBuf[37] = 0;
225 * func - called when we have pixmap created (but no image data)
226 * user_data - passed as arg 1 to func
227 * return context (opaque to user)
231 gdk_pixbuf__ras_image_begin_load(GdkPixbufModuleSizeFunc size_func,
232 GdkPixbufModulePreparedFunc prepared_func,
233 GdkPixbufModuleUpdatedFunc updated_func,
237 struct ras_progressive_state *context;
239 context = g_new0(struct ras_progressive_state, 1);
240 context->size_func = size_func;
241 context->prepared_func = prepared_func;
242 context->updated_func = updated_func;
243 context->user_data = user_data;
245 context->HeaderSize = 32;
246 context->HeaderBuf = g_malloc(32 + 768); /* 32 for rasheader,
247 768 for the colormap */
248 context->HeaderDone = 0;
250 context->LineWidth = 0;
251 context->LineBuf = NULL;
252 context->LineDone = 0;
255 context->RasType = 0;
256 context->DecoderState = 0;
258 memset(&context->Header, 0, sizeof(struct rasterfile));
261 context->pixbuf = NULL;
264 return (gpointer) context;
268 * context - returned from image_begin_load
270 * free context, unref gdk_pixbuf
273 gdk_pixbuf__ras_image_stop_load(gpointer data, GError **error)
275 struct ras_progressive_state *context =
276 (struct ras_progressive_state *) data;
278 /* FIXME this thing needs to report errors if
279 * we have unused image data
282 g_return_val_if_fail(context != NULL, TRUE);
284 if (context->LineBuf != NULL)
285 g_free(context->LineBuf);
286 if (context->HeaderBuf != NULL)
287 g_free(context->HeaderBuf);
290 g_object_unref(context->pixbuf);
298 OneLine is called when enough data is received to process 1 line
302 static void OneLine32(struct ras_progressive_state *context)
308 Pixels = context->pixbuf->pixels + context->pixbuf->rowstride * context->Lines;
309 while (X < context->Header.width) {
310 /* The joys of having a BGR byteorder */
311 Pixels[X * 4 + 0] = context->LineBuf[X * 4 + 2];
312 Pixels[X * 4 + 1] = context->LineBuf[X * 4 + 1];
313 Pixels[X * 4 + 2] = context->LineBuf[X * 4 + 0];
314 Pixels[X * 4 + 3] = context->LineBuf[X * 4 + 3];
319 static void OneLine24(struct ras_progressive_state *context)
325 Pixels = context->pixbuf->pixels + context->pixbuf->rowstride * context->Lines;
326 while (X < context->Header.width) {
327 /* The joys of having a BGR byteorder */
328 Pixels[X * 3 + 0] = context->LineBuf[X * 3 + 2];
329 Pixels[X * 3 + 1] = context->LineBuf[X * 3 + 1];
330 Pixels[X * 3 + 2] = context->LineBuf[X * 3 + 0];
336 static void OneLine8(struct ras_progressive_state *context)
340 int offset = context->Header.maplength / 3;
343 Pixels = context->pixbuf->pixels + context->pixbuf->rowstride * context->Lines;
344 while (X < context->Header.width) {
345 /* The joys of having a BGR byteorder */
347 context->HeaderBuf[context->LineBuf[X] + 32];
349 context->HeaderBuf[context->LineBuf[X] + offset + 32];
351 context->HeaderBuf[context->LineBuf[X] + 2*offset + 32];
356 static void OneLine1(struct ras_progressive_state *context)
362 Pixels = context->pixbuf->pixels + context->pixbuf->rowstride * context->Lines;
363 while (X < context->Header.width) {
366 Bit = (context->LineBuf[X/8])>>(7-(X&7));
368 /* The joys of having a BGR byteorder */
370 context->HeaderBuf[Bit + 32];
372 context->HeaderBuf[Bit + 2 + 32];
374 context->HeaderBuf[Bit + 4 + 32];
380 static void OneLine(struct ras_progressive_state *context)
382 context->LineDone = 0;
383 if (context->Lines >= context->Header.height)
385 if (context->RasType == 32)
387 if (context->RasType == 24)
389 if (context->RasType == 8)
391 if (context->RasType == 1)
394 context->LineDone = 0;
397 if (context->updated_func != NULL) {
398 (*context->updated_func) (context->pixbuf,
401 context->Header.width,
409 DoCompressed (struct ras_progressive_state *context,
410 const guchar * buf, guint size,
415 for (i = 0; i < size; i++) {
416 switch (context->DecoderState) {
419 context->DecoderState = 1;
421 context->LineBuf[context->LineDone++] = buf[i];
425 context->LineBuf[context->LineDone++] = 0x80;
426 context->DecoderState = 0;
429 context->DecoderState = buf[i] + 1;
432 for (; context->DecoderState; context->DecoderState--) {
433 context->LineBuf[context->LineDone++] = buf[i];
434 if ((context->LineDone >= context->LineWidth) && (context->LineWidth > 0))
438 if ((context->LineDone >= context->LineWidth) && (context->LineWidth > 0))
445 * context - from image_begin_load
446 * buf - new image data
447 * size - length of new image data
449 * append image data onto incrementally built output image
452 gdk_pixbuf__ras_image_load_increment(gpointer data,
453 const guchar * buf, guint size,
456 struct ras_progressive_state *context =
457 (struct ras_progressive_state *) data;
462 if (context->HeaderDone < context->HeaderSize) { /* We still
463 have headerbytes to do */
465 context->HeaderSize - context->HeaderDone;
466 if (BytesToCopy > size)
469 memmove(context->HeaderBuf + context->HeaderDone,
474 context->HeaderDone += BytesToCopy;
476 } else if (context->Header.type == 2) {
477 if (!DoCompressed (context, buf, size, error)) {
484 context->LineWidth - context->LineDone;
485 if (BytesToCopy > size)
488 if (BytesToCopy > 0) {
489 memmove(context->LineBuf +
490 context->LineDone, buf,
495 context->LineDone += BytesToCopy;
497 if ((context->LineDone >= context->LineWidth) &&
498 (context->LineWidth > 0))
504 if (context->HeaderDone >= 32)
505 if (!RAS2State((struct rasterfile *) context->HeaderBuf,
517 #define MODULE_ENTRY(type,function) function
519 #define MODULE_ENTRY(type,function) _gdk_pixbuf__ ## type ## _ ## function
523 MODULE_ENTRY (ras, fill_vtable) (GdkPixbufModule *module)
525 module->begin_load = gdk_pixbuf__ras_image_begin_load;
526 module->stop_load = gdk_pixbuf__ras_image_stop_load;
527 module->load_increment = gdk_pixbuf__ras_image_load_increment;
531 MODULE_ENTRY (ras, fill_info) (GdkPixbufFormat *info)
533 static GdkPixbufModulePattern signature[] = {
534 { "\x59\xa6\x6a\x95", NULL, 100 },
537 static gchar * mime_types[] = {
538 "image/x-cmu-raster",
539 "image/x-sun-raster",
542 static gchar * extensions[] = {
548 info->signature = signature;
549 info->description = N_("The Sun raster image format");
550 info->mime_types = mime_types;
551 info->extensions = extensions;
552 info->flags = GDK_PIXBUF_FORMAT_THREADSAFE;
553 info->license = "LGPL";