diff options
author | Jonathan Blandford <jrb@src.gnome.org> | 1999-11-17 21:02:33 +0000 |
---|---|---|
committer | Jonathan Blandford <jrb@src.gnome.org> | 1999-11-17 21:02:33 +0000 |
commit | 974e54fc9abb7b9748a3f88f05b4a265e1c7d8d2 (patch) | |
tree | 9a23d6a544fde8274f92db25b3cd724f747197bf /gdk-pixbuf/io-ras.c | |
parent | eec6970fe2c427075cfc00e2835a8f3152868e07 (diff) | |
download | gtk+-974e54fc9abb7b9748a3f88f05b4a265e1c7d8d2.tar.gz |
patch from arjan to work better with ras files.
Diffstat (limited to 'gdk-pixbuf/io-ras.c')
-rw-r--r-- | gdk-pixbuf/io-ras.c | 584 |
1 files changed, 291 insertions, 293 deletions
diff --git a/gdk-pixbuf/io-ras.c b/gdk-pixbuf/io-ras.c index c45f5bb475..7f44b2820c 100644 --- a/gdk-pixbuf/io-ras.c +++ b/gdk-pixbuf/io-ras.c @@ -22,19 +22,18 @@ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ - + /* Known bugs: - * "Indexed" (incl grayscale) sunras files don't work - ( 1999/11/10 - Fixed for non-progressive loading ) - * 1 bpp sunrasfiles don't work yet * Compressed rasterfiles don't work yet */ #include <config.h> #include <stdio.h> +#include <unistd.h> +#include <sys/mman.h> #include <glib.h> #include <gdk/gdk.h> #include <gtk/gtk.h> @@ -46,6 +45,8 @@ Known bugs: /* Header structure for sunras files. All values are in big-endian order on disk + + Note: Every scanline is padded to be a multiple of 16 bits */ struct rasterfile { @@ -82,205 +83,144 @@ static void free_buffer(gpointer user_data, gpointer data) free(data); } -/* -OneLineBGR_buf/file does what it says: Reads one line from file or buffer. -Note: It also changes BGR pixelorder to RGB as libart currently -doesn't support ART_PIX_BGR. -*/ -static void OneLineBGR_buf(guchar * buffer, guint Width, guchar * pixels, - guint bpp) -{ - guint X; - memcpy(pixels, buffer, (size_t) (Width * bpp)); - X = 0; - while (X < Width) { - guchar Blue; - Blue = pixels[X * bpp]; - pixels[X * bpp] = pixels[X * bpp + 2]; - pixels[X * bpp + 2] = Blue; - X++; - } -} +/* Progressive loading */ -static void OneLineBGR_file(FILE * f, guint Width, guchar * pixels, - guint bpp) -{ - size_t result; - guint X; - guchar DummyByte; +struct ras_progressive_state { + ModulePreparedNotifyFunc prepared_func; + ModuleUpdatedNotifyFunc updated_func; + gpointer user_data; - result = fread(pixels, 1, (size_t) (Width * bpp), f); + gint HeaderSize; /* The size of the header-part (incl colormap) */ + guchar *HeaderBuf; /* The buffer for the header (incl colormap) */ + gint HeaderDone; /* The nr of bytes actually in HeaderBuf */ - g_assert(result == (size_t) (Width * bpp)); - if (((Width * bpp) & 1) != 0) /* Not 16 bit aligned */ - (void) fread(&DummyByte, 1, 1, f); - X = 0; - while (X < Width) { - guchar Blue; - Blue = pixels[X * bpp]; - pixels[X * bpp] = pixels[X * bpp + 2]; - pixels[X * bpp + 2] = Blue; - X++; - } -} + gint LineWidth; /* The width of a line in bytes */ + guchar *LineBuf; /* Buffer for 1 line */ + gint LineDone; /* # of bytes in LineBuf */ + gint Lines; /* # of finished lines */ -static void OneLineMapped_file(FILE * f, guint Width, guchar * pixels, - guint bpp, guchar *Map) -{ - size_t result; - guint X; - guchar DummyByte; - guchar *buffer; - - - buffer =g_malloc((size_t) (Width * bpp)); - - g_assert(buffer!=NULL); + gint RasType; /* 32 = BGRA + 24 = BGR + 8 = 8 bit colormapped + 1 = 1 bit bitonal + */ - result = fread(buffer, 1, (size_t) (Width * bpp), f); - g_assert(result == (size_t) (Width * bpp)); - - if (((Width * bpp) & 1) != 0) /* Not 16 bit aligned */ - (void) fread(&DummyByte, 1, 1, f); - X = 0; - while (X < Width) { - pixels[X * 3] = Map[buffer[X]]; - pixels[X * 3+1] = Map[buffer[X]+256]; - pixels[X * 3+2] = Map[buffer[X]+512]; + struct rasterfile Header; /* Decoded (BE->CPU) header */ - X++; - } - g_free(buffer); -} -static void OneLineMapped_buf(guchar *buffer, guint Width, guchar * pixels, - guint bpp,guchar *Map) -{ - size_t result; - guint X; - - X = 0; - while (X < Width) { - pixels[X * 3] = Map[buffer[X]*3]; - pixels[X * 3+1] = Map[buffer[X]*3+1]; - pixels[X * 3+2] = Map[buffer[X]*3+2]; + GdkPixbuf *pixbuf; /* Our "target" */ +}; + +gpointer +image_begin_load(ModulePreparedNotifyFunc prepared_func, + ModuleUpdatedNotifyFunc updated_func, gpointer user_data); +void image_stop_load(gpointer data); +gboolean image_load_increment(gpointer data, guchar * buf, guint size); + - X++; - } -} /* Shared library entry point */ GdkPixbuf *image_load(FILE * f) { - guint bpp; - guint Y; - size_t i; - guchar *pixels; - guchar ColorMap[768]; - struct rasterfile Header; - - i = fread(&Header, 1, sizeof(Header), f); - g_assert(i == 32); + guchar *membuf; + size_t length; + struct ras_progressive_state *State; + int fd; - /* Fill default colormap */ - for (Y=0;Y<256;Y++) { - ColorMap[Y*3+0]=Y; - ColorMap[Y*3+1]=Y; - ColorMap[Y*3+2]=Y; - } - /* Correct the byteorder of the header here */ - Header.width = be32_to_cpu(Header.width); - Header.height = be32_to_cpu(Header.height); - Header.depth = be32_to_cpu(Header.depth); - Header.length = be32_to_cpu(Header.length); - Header.type = be32_to_cpu(Header.type); - Header.maptype = be32_to_cpu(Header.maptype); - Header.maplength = be32_to_cpu(Header.maplength); - - - bpp = 0; - if (Header.depth == 32) - bpp = 4; - if (Header.depth == 24) - bpp = 3; - if (Header.depth == 8) - bpp = 1; - - printf("mapl %i \n",Header.maplength); - if (Header.maplength>0) - i = fread(ColorMap,1,Header.maplength,f); - - - g_assert(bpp != 0); /* Only 24 and 32 bpp for now */ - - if (bpp==4) - pixels = (guchar *) g_malloc(Header.width * Header.height * 4); - else - pixels = (guchar *) g_malloc(Header.width * Header.height * 3); - if (!pixels) { - return NULL; - } - - /* - - Loop through the file, one line at a time. - Only BGR-style files are handled right now. + GdkPixbuf *pb; + + State = image_begin_load(NULL, NULL, NULL); + + membuf = g_malloc(4096); + + g_assert(membuf != NULL); + + while (feof(f) == 0) { + length = fread(membuf, 1, 4096, f); + image_load_increment(State, membuf, length); + } + g_free(membuf); + if (State->pixbuf != NULL) + gdk_pixbuf_ref(State->pixbuf); + + pb = State->pixbuf; + + image_stop_load(State); + return State->pixbuf; +} - */ - Y = 0; - while (Y < Header.height) { - if (bpp>1) - OneLineBGR_file(f, Header.width, - &pixels[Y * Header.width * bpp], bpp); - else - OneLineMapped_file(f, Header.width, - &pixels[Y * Header.width * 3], bpp,&ColorMap[0]); - Y++; +static void RAS2State(struct rasterfile *RAS, + struct ras_progressive_state *State) +{ + State->Header.width = be32_to_cpu(RAS->width); + State->Header.height = be32_to_cpu(RAS->height); + State->Header.depth = be32_to_cpu(RAS->depth); + State->Header.type = be32_to_cpu(RAS->type); + State->Header.maptype = be32_to_cpu(RAS->maptype); + State->Header.maplength = be32_to_cpu(RAS->maplength); + + g_assert(State->Header.maplength <= 768); /* Otherwise, we are in trouble */ + + State->RasType = State->Header.depth; /* This may be less trivial someday */ + State->HeaderSize = 32 + State->Header.maplength; + + if (State->RasType == 32) + State->LineWidth = State->Header.width * 4; + if (State->RasType == 24) + State->LineWidth = State->Header.width * 3; + if (State->RasType == 8) + State->LineWidth = State->Header.width * 1; + if (State->RasType == 1) { + State->LineWidth = State->Header.width / 8; + if ((State->Header.width & 7) != 0) + State->LineWidth++; } + /* Now padd the line to be a multiple of 16 bits */ + if ((State->LineWidth & 1) != 0) + State->LineWidth++; - if (bpp == 4) - return gdk_pixbuf_new_from_data(pixels, ART_PIX_RGB, TRUE, - (gint) Header.width, - (gint) Header.height, - (gint) (Header.width * - 4), free_buffer, - NULL); - else - return gdk_pixbuf_new_from_data(pixels, ART_PIX_RGB, FALSE, - (gint) Header.width, - (gint) Header.height, - (gint) (Header.width * - 3), free_buffer, - NULL); -} + if (State->LineBuf == NULL) + State->LineBuf = g_malloc(State->LineWidth); + g_assert(State->LineBuf != NULL); -/* Progressive loading */ - -struct ras_progressive_state { - ModulePreparedNotifyFunc prepared_func; - ModuleUpdatedNotifyFunc updated_func; - gpointer user_data; - - GdkPixbuf *pixbuf; /* Our "target" */ - guchar *PixelData; /* pointer to the next line */ - struct rasterfile Header; - guint bpp; - guint BytesPerLine; - guchar *linebuf; - guchar *ColorMap; - guint BytesInLB; - guint LinesDone; + if (State->pixbuf == NULL) { + if (State->RasType == 32) + State->pixbuf = gdk_pixbuf_new(ART_PIX_RGB, TRUE, + 8, + (gint) + State->Header.width, + (gint) + State->Header. + height); + else + State->pixbuf = + gdk_pixbuf_new(ART_PIX_RGB, FALSE, 8, + (gint) State->Header.width, + (gint) State->Header.height); + if (State->prepared_func != NULL) + /* Notify the client that we are ready to go */ + (*State->prepared_func) (State->pixbuf, + State->user_data); + } + + if ((State->Header.maplength==0)&&(State->RasType==1)) { + State->HeaderBuf[32] = 255; + State->HeaderBuf[33] = 0; + State->HeaderBuf[34] = 255; + State->HeaderBuf[35] = 0; + State->HeaderBuf[36] = 255; + State->HeaderBuf[37] = 0; + } - gboolean have_header; -}; +} /* * func - called when we have pixmap created (but no image data) @@ -295,18 +235,27 @@ image_begin_load(ModulePreparedNotifyFunc prepared_func, struct ras_progressive_state *context; context = g_new0(struct ras_progressive_state, 1); - context->prepared_func = prepared_func; context->updated_func = updated_func; context->user_data = user_data; + + context->HeaderSize = 32; + context->HeaderBuf = g_malloc(32 + 768); /* 32 for rasheader, + 768 for the colormap */ + context->HeaderDone = 0; + + context->LineWidth = 0; + context->LineBuf = NULL; + context->LineDone = 0; + context->Lines = 0; + + context->RasType = 0; + + memset(&context->Header, 0, sizeof(struct rasterfile)); + + context->pixbuf = NULL; - context->linebuf = NULL; - context->bpp = 0; - context->have_header = 0; - context->BytesInLB = 0; - context->BytesPerLine = 0; - context->LinesDone = 0; - context->ColorMap = NULL; + return (gpointer) context; } @@ -321,18 +270,132 @@ void image_stop_load(gpointer data) struct ras_progressive_state *context = (struct ras_progressive_state *) data; + g_return_if_fail(context != NULL); + if (context->LineBuf != NULL) + g_free(context->LineBuf); + if (context->HeaderBuf != NULL) + g_free(context->HeaderBuf); + if (context->pixbuf) gdk_pixbuf_unref(context->pixbuf); - if (context->linebuf) - g_free(context->linebuf); - if (context->ColorMap) - g_free(context->ColorMap); g_free(context); } +/* + OneLine is called when enough data is received to process 1 line + of pixels + */ + +static void OneLine32(struct ras_progressive_state *context) +{ + gint X; + guchar *Pixels; + + X = 0; + Pixels = context->pixbuf->art_pixbuf->pixels + + context->pixbuf->art_pixbuf->rowstride * context->Lines; + while (X < context->Header.width) { + /* The joys of having a BGR byteorder */ + Pixels[X * 4 + 0] = context->LineBuf[X * 4 + 2]; + Pixels[X * 4 + 1] = context->LineBuf[X * 4 + 1]; + Pixels[X * 4 + 2] = context->LineBuf[X * 4 + 0]; + Pixels[X * 4 + 3] = context->LineBuf[X * 4 + 3]; + X++; + } +} + +static void OneLine24(struct ras_progressive_state *context) +{ + gint X; + guchar *Pixels; + + X = 0; + Pixels = context->pixbuf->art_pixbuf->pixels + + context->pixbuf->art_pixbuf->rowstride * context->Lines; + while (X < context->Header.width) { + /* The joys of having a BGR byteorder */ + Pixels[X * 3 + 0] = context->LineBuf[X * 3 + 2]; + Pixels[X * 3 + 1] = context->LineBuf[X * 3 + 1]; + Pixels[X * 3 + 2] = context->LineBuf[X * 3 + 0]; + X++; + } + +} + +static void OneLine8(struct ras_progressive_state *context) +{ + gint X; + guchar *Pixels; + + X = 0; + Pixels = context->pixbuf->art_pixbuf->pixels + + context->pixbuf->art_pixbuf->rowstride * context->Lines; + while (X < context->Header.width) { + /* The joys of having a BGR byteorder */ + Pixels[X * 3 + 0] = + context->HeaderBuf[context->LineBuf[X] + 32]; + Pixels[X * 3 + 1] = + context->HeaderBuf[context->LineBuf[X] + 256 + 32]; + Pixels[X * 3 + 2] = + context->HeaderBuf[context->LineBuf[X] + 512 + 32]; + X++; + } +} + +static void OneLine1(struct ras_progressive_state *context) +{ + gint X; + guchar *Pixels; + + X = 0; + Pixels = context->pixbuf->art_pixbuf->pixels + + context->pixbuf->art_pixbuf->rowstride * context->Lines; + while (X < context->Header.width) { + int Bit; + + Bit = (context->LineBuf[X/8])>>(7-(X&7)); + Bit = Bit & 1; + /* The joys of having a BGR byteorder */ + Pixels[X * 3 + 0] = + context->HeaderBuf[Bit + 32]; + Pixels[X * 3 + 1] = + context->HeaderBuf[Bit + 2 + 32]; + Pixels[X * 3 + 2] = + context->HeaderBuf[Bit + 4 + 32]; + X++; + } +} + + +static void OneLine(struct ras_progressive_state *context) +{ + if (context->RasType == 32) + OneLine32(context); + if (context->RasType == 24) + OneLine24(context); + if (context->RasType == 8) + OneLine8(context); + if (context->RasType == 1) + OneLine1(context); + + context->LineDone = 0; + if (context->Lines > context->Header.height) + return; + context->Lines++; + + if (context->updated_func != NULL) { + (*context->updated_func) (context->pixbuf, + context->user_data, + 0, + context->Lines, + context->Header.width, + context->Header.height); + + } +} /* * context - from image_begin_load @@ -346,117 +409,52 @@ gboolean image_load_increment(gpointer data, guchar * buf, guint size) struct ras_progressive_state *context = (struct ras_progressive_state *) data; - if ((context->have_header == 0) && (size < 32)) - return FALSE; - - if (context->have_header == FALSE) { - memcpy(&context->Header, buf, 32); - buf += 32; - size -= 32; - - context->Header.width = be32_to_cpu(context->Header.width); - context->Header.height = - be32_to_cpu(context->Header.height); - context->Header.depth = be32_to_cpu(context->Header.depth); - context->Header.length = - be32_to_cpu(context->Header.length); - context->Header.type = be32_to_cpu(context->Header.type); - context->Header.maptype = - be32_to_cpu(context->Header.maptype); - context->Header.maplength = - be32_to_cpu(context->Header.maplength); - - context->bpp = 0; - if (context->Header.depth == 32) - context->bpp = 4; - if (context->Header.depth == 24) - context->bpp = 3; - if (context->Header.depth == 8) - context->bpp = 1; - - - g_assert(context->bpp != 0); /* Only 24 and 32 bpp for now */ - - - if (context->bpp == 4) - context->pixbuf = gdk_pixbuf_new(ART_PIX_RGB, TRUE, - 8, - (gint) - context->Header. - width, - (gint) - context->Header. - height); - else - context->pixbuf = - gdk_pixbuf_new(ART_PIX_RGB, FALSE, 8, - (gint) context->Header.width, - (gint) context->Header.height); - - /* Use pixbuf buffer to store decompressed data */ - g_assert(context->pixbuf != NULL); - g_assert(context->pixbuf->art_pixbuf != NULL); - context->PixelData = context->pixbuf->art_pixbuf->pixels; - g_assert(context->PixelData != NULL); - context->BytesPerLine = - context->Header.width * context->bpp; - - if (((context->BytesPerLine) & 1) != 0) /* Not 16 bit aligned */ - context->BytesPerLine++; - - context->linebuf = - (guchar *) g_malloc(context->BytesPerLine); - context->have_header = TRUE; - if (context->linebuf == NULL) { - /* Failed to allocate memory */ - g_error("Couldn't allocate linebuf"); - } - - - /* Notify the client that we are ready to go */ - (*context->prepared_func) (context->pixbuf, - context->user_data); - } - + gint BytesToCopy; while (size > 0) { - guint ToDo; - ToDo = context->BytesPerLine - context->BytesInLB; - if (ToDo > size) - ToDo = size; - memcpy(context->linebuf + context->BytesInLB, - buf, (size_t) ToDo); - size -= ToDo; - buf += ToDo; - context->BytesInLB += ToDo; - if (context->BytesInLB >= context->BytesPerLine) { - /* linebuf if full */ - if (context->bpp>1) - OneLineBGR_buf(context->linebuf, - context->Header.width, - context->PixelData, context->bpp); - else - OneLineMapped_buf(context->linebuf, - context->Header.width, - context->PixelData, context->bpp, - context->ColorMap); - context->BytesInLB = 0; - context->PixelData += - context->pixbuf->art_pixbuf->rowstride; - context->LinesDone++; - - (*context->updated_func) (context->pixbuf, - context->user_data, - 0, - context->LinesDone, - context->Header.width, - context->Header.height); + if (context->HeaderDone < context->HeaderSize) { /* We still + have headerbytes to do */ + BytesToCopy = + context->HeaderSize - context->HeaderDone; + if (BytesToCopy > size) + BytesToCopy = size; + + memcpy(context->HeaderBuf + context->HeaderDone, + buf, BytesToCopy); + + size -= BytesToCopy; + buf += BytesToCopy; + context->HeaderDone += BytesToCopy; + + } else { + /* Pixeldata only */ + BytesToCopy = + context->LineWidth - context->LineDone; + if (BytesToCopy > size) + BytesToCopy = size; + + if (BytesToCopy > 0) { + memcpy(context->LineBuf + + context->LineDone, buf, + BytesToCopy); + + size -= BytesToCopy; + buf += BytesToCopy; + context->LineDone += BytesToCopy; + } + if ((context->LineDone >= context->LineWidth) && + (context->LineWidth > 0)) + OneLine(context); } + if (context->HeaderDone >= 32) + RAS2State((struct rasterfile *) context->HeaderBuf, + context); + + } return TRUE; } - |