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) {
123 g_set_error_literal (error,
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)
145 g_set_error_literal (error,
147 GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
148 _("RAS image has unknown type"));
152 if (State->Header.type > 2 || State->Header.maptype > 1) {
153 g_set_error_literal (error,
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) {
168 g_set_error_literal (error,
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) {
197 g_set_error_literal (error,
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 g_free(context->LineBuf);
285 g_free(context->HeaderBuf);
288 g_object_unref(context->pixbuf);
296 OneLine is called when enough data is received to process 1 line
300 static void OneLine32(struct ras_progressive_state *context)
306 Pixels = context->pixbuf->pixels + context->pixbuf->rowstride * context->Lines;
307 while (X < context->Header.width) {
308 /* The joys of having a BGR byteorder */
309 Pixels[X * 4 + 0] = context->LineBuf[X * 4 + 2];
310 Pixels[X * 4 + 1] = context->LineBuf[X * 4 + 1];
311 Pixels[X * 4 + 2] = context->LineBuf[X * 4 + 0];
312 Pixels[X * 4 + 3] = context->LineBuf[X * 4 + 3];
317 static void OneLine24(struct ras_progressive_state *context)
323 Pixels = context->pixbuf->pixels + context->pixbuf->rowstride * context->Lines;
324 while (X < context->Header.width) {
325 /* The joys of having a BGR byteorder */
326 Pixels[X * 3 + 0] = context->LineBuf[X * 3 + 2];
327 Pixels[X * 3 + 1] = context->LineBuf[X * 3 + 1];
328 Pixels[X * 3 + 2] = context->LineBuf[X * 3 + 0];
334 static void OneLine8(struct ras_progressive_state *context)
338 int offset = context->Header.maplength / 3;
341 Pixels = context->pixbuf->pixels + context->pixbuf->rowstride * context->Lines;
342 while (X < context->Header.width) {
343 /* The joys of having a BGR byteorder */
345 context->HeaderBuf[context->LineBuf[X] + 32];
347 context->HeaderBuf[context->LineBuf[X] + offset + 32];
349 context->HeaderBuf[context->LineBuf[X] + 2*offset + 32];
354 static void OneLine1(struct ras_progressive_state *context)
360 Pixels = context->pixbuf->pixels + context->pixbuf->rowstride * context->Lines;
361 while (X < context->Header.width) {
364 Bit = (context->LineBuf[X/8])>>(7-(X&7));
366 /* The joys of having a BGR byteorder */
368 context->HeaderBuf[Bit + 32];
370 context->HeaderBuf[Bit + 2 + 32];
372 context->HeaderBuf[Bit + 4 + 32];
378 static void OneLine(struct ras_progressive_state *context)
380 context->LineDone = 0;
381 if (context->Lines >= context->Header.height)
383 if (context->RasType == 32)
385 if (context->RasType == 24)
387 if (context->RasType == 8)
389 if (context->RasType == 1)
392 context->LineDone = 0;
395 if (context->updated_func != NULL) {
396 (*context->updated_func) (context->pixbuf,
399 context->Header.width,
407 DoCompressed (struct ras_progressive_state *context,
408 const guchar * buf, guint size,
413 for (i = 0; i < size; i++) {
414 switch (context->DecoderState) {
417 context->DecoderState = 1;
419 context->LineBuf[context->LineDone++] = buf[i];
423 context->LineBuf[context->LineDone++] = 0x80;
424 context->DecoderState = 0;
427 context->DecoderState = buf[i] + 1;
430 for (; context->DecoderState; context->DecoderState--) {
431 context->LineBuf[context->LineDone++] = buf[i];
432 if ((context->LineDone >= context->LineWidth) && (context->LineWidth > 0))
436 if ((context->LineDone >= context->LineWidth) && (context->LineWidth > 0))
443 * context - from image_begin_load
444 * buf - new image data
445 * size - length of new image data
447 * append image data onto incrementally built output image
450 gdk_pixbuf__ras_image_load_increment(gpointer data,
451 const guchar * buf, guint size,
454 struct ras_progressive_state *context =
455 (struct ras_progressive_state *) data;
460 if (context->HeaderDone < context->HeaderSize) { /* We still
461 have headerbytes to do */
463 context->HeaderSize - context->HeaderDone;
464 if (BytesToCopy > size)
467 memmove(context->HeaderBuf + context->HeaderDone,
472 context->HeaderDone += BytesToCopy;
474 } else if (context->Header.type == 2) {
475 if (!DoCompressed (context, buf, size, error)) {
482 context->LineWidth - context->LineDone;
483 if (BytesToCopy > size)
486 if (BytesToCopy > 0) {
487 memmove(context->LineBuf +
488 context->LineDone, buf,
493 context->LineDone += BytesToCopy;
495 if ((context->LineDone >= context->LineWidth) &&
496 (context->LineWidth > 0))
502 if (context->HeaderDone >= 32)
503 if (!RAS2State((struct rasterfile *) context->HeaderBuf,
515 #define MODULE_ENTRY(function) G_MODULE_EXPORT void function
517 #define MODULE_ENTRY(function) void _gdk_pixbuf__ras_ ## function
520 MODULE_ENTRY (fill_vtable) (GdkPixbufModule *module)
522 module->begin_load = gdk_pixbuf__ras_image_begin_load;
523 module->stop_load = gdk_pixbuf__ras_image_stop_load;
524 module->load_increment = gdk_pixbuf__ras_image_load_increment;
527 MODULE_ENTRY (fill_info) (GdkPixbufFormat *info)
529 static GdkPixbufModulePattern signature[] = {
530 { "\x59\xa6\x6a\x95", NULL, 100 },
533 static gchar * mime_types[] = {
534 "image/x-cmu-raster",
535 "image/x-sun-raster",
538 static gchar * extensions[] = {
544 info->signature = signature;
545 info->description = N_("The Sun raster image format");
546 info->mime_types = mime_types;
547 info->extensions = extensions;
548 info->flags = GDK_PIXBUF_FORMAT_THREADSAFE;
549 info->license = "LGPL";