diff libvisual/lv_bmp.c @ 23:0db4a1dc75c4 trunk

[svn] libvisual. P3 detection appears to be borked. I'll work on it later.
author nenolod
date Mon, 24 Oct 2005 23:13:56 -0700
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libvisual/lv_bmp.c	Mon Oct 24 23:13:56 2005 -0700
@@ -0,0 +1,289 @@
+/* Libvisual - The audio visualisation framework.
+ * 
+ * Copyright (C) 2004, 2005 Dennis Smit <ds@nerds-incorporated.org>
+ *
+ * Authors: Dennis Smit <ds@nerds-incorporated.org>
+ *
+ * $Id:
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "lv_common.h"
+#include "lv_log.h"
+#include "lv_endianess.h"
+#include "lv_bmp.h"
+
+#define BI_RGB	0
+#define BI_RLE8	1
+#define BI_RLE	2
+
+/**
+ * @defgroup VisBitmap VisBitmap
+ * @{
+ */
+
+/**
+ * Loads a BMP file into a VisVideo. The buffer will be located
+ * for the VisVideo.
+ *
+ * The loader currently only supports uncompressed bitmaps in the form
+ * of either 8 bits indexed or 24 bits RGB.
+ *
+ * Keep in mind that you need to free the palette by hand.
+ * 
+ * @param video Destination video where the bitmap should be loaded in.
+ * @param filename The filename of the bitmap to be loaded.
+ *
+ * @return VISUAL_OK on succes, -VISUAL_ERROR_VIDEO_NULL, -VISUAL_ERROR_BMP_NOT_FOUND,
+ * 	-VISUAL_ERROR_BMP_NO_BMP, -VISUAL_ERROR_BMP_NOT_SUPPORTED or -VISUAL_ERROR_BMP_CORRUPTED
+ * 	on failure.
+ */
+int visual_bitmap_load (VisVideo *video, const char *filename)
+{
+	/* The win32 BMP header */
+	char magic[2];
+	uint32_t bf_size = 0;
+	uint32_t bf_bits = 0;
+
+	/* The win32 BITMAPINFOHEADER */
+	int32_t bi_size = 0;
+	int32_t bi_width = 0;
+	int32_t bi_height = 0;
+	int16_t bi_bitcount = 0;	
+	uint32_t bi_compression;
+	uint32_t bi_clrused;
+
+	/* File read vars */
+	int fd;
+
+	/* Worker vars */
+	uint8_t *data;
+	int pad;
+	int i;
+
+	visual_log_return_val_if_fail (video != NULL, -VISUAL_ERROR_VIDEO_NULL);
+
+	fd = open (filename, O_RDONLY);
+
+	if (fd < 0) {
+		visual_log (VISUAL_LOG_WARNING, "Bitmap file not found: %s", filename);
+
+		return -VISUAL_ERROR_BMP_NOT_FOUND;
+	}
+
+	/* Read the magic string */
+	read (fd, magic, 2);
+
+	if (strncmp (magic, "BM", 2) != 0) {
+		visual_log (VISUAL_LOG_WARNING, "Not a bitmap file"); 
+	
+		return -VISUAL_ERROR_BMP_NO_BMP;
+	}
+
+	/* Read the file size */
+	read (fd, &bf_size, 4);
+	bf_size = VISUAL_ENDIAN_LEI32 (bf_size);
+
+	/* Skip past the reserved bits */
+	lseek (fd, 4, SEEK_CUR);
+
+	/* Read the offset bits */
+	read (fd, &bf_bits, 4);
+	bf_bits = VISUAL_ENDIAN_LEI32 (bf_bits);
+
+	/* Read the info structure size */
+	read (fd, &bi_size, 4);
+	bi_size = VISUAL_ENDIAN_LEI32 (bi_size);
+
+	if (bi_size == 12) {
+		/* And read the width, height */
+		read (fd, &bi_width, 2);
+		read (fd, &bi_height, 2);
+		bi_width = VISUAL_ENDIAN_LEI16 (bi_width);
+		bi_height = VISUAL_ENDIAN_LEI16 (bi_height);
+
+		/* Skip over the planet */
+		lseek (fd, 2, SEEK_CUR);
+
+		/* Read the bits per pixel */
+		read (fd, &bi_bitcount, 2);
+		bi_bitcount = VISUAL_ENDIAN_LEI16 (bi_bitcount);
+
+		bi_compression = BI_RGB;
+	} else {
+		/* And read the width, height */
+		read (fd, &bi_width, 4);
+		read (fd, &bi_height, 4);
+		bi_width = VISUAL_ENDIAN_LEI16 (bi_width);
+		bi_height = VISUAL_ENDIAN_LEI16 (bi_height);
+
+		/* Skip over the planet */
+		lseek (fd, 2, SEEK_CUR);
+
+		/* Read the bits per pixel */
+		read (fd, &bi_bitcount, 2);
+		bi_bitcount = VISUAL_ENDIAN_LEI16 (bi_bitcount);
+
+		/* Read the compression flag */
+		read (fd, &bi_compression, 4);
+		bi_compression = VISUAL_ENDIAN_LEI32 (bi_compression);
+
+		/* Skip over the nonsense we don't want to know */
+		lseek (fd, 12, SEEK_CUR);
+
+		/* Number of colors in palette */
+		read (fd, &bi_clrused, 4);
+		bi_clrused = VISUAL_ENDIAN_LEI32 (bi_clrused);
+
+		/* Skip over the other nonsense */
+		lseek (fd, 4, SEEK_CUR);
+	}
+
+	/* Check if we can handle it */
+	if (bi_bitcount != 8 && bi_bitcount != 24) {
+		visual_log (VISUAL_LOG_CRITICAL, "Only bitmaps with 8 bits or 24 bits per pixel are supported");
+		
+		return -VISUAL_ERROR_BMP_NOT_SUPPORTED;
+	}
+
+	/* We only handle uncompressed bitmaps */
+	if (bi_compression != BI_RGB) {
+		visual_log (VISUAL_LOG_CRITICAL, "Only uncompressed bitmaps are supported");
+
+		return -VISUAL_ERROR_BMP_NOT_SUPPORTED;
+	}
+
+	/* Load the palette */
+	if (bi_bitcount == 8) {
+		if (bi_clrused == 0)
+			bi_clrused = 256;
+
+		if (video->pal == NULL)
+			visual_object_unref (VISUAL_OBJECT (video->pal));
+		
+		video->pal = visual_palette_new (bi_clrused);
+
+		if (bi_size == 12) {
+			for (i = 0; i < bi_clrused; i++) {
+				read (fd, &video->pal->colors[i].b, 1);
+				read (fd, &video->pal->colors[i].g, 1);
+				read (fd, &video->pal->colors[i].r, 1);
+			}
+		} else {
+			for (i = 0; i < bi_clrused; i++) {
+				read (fd, &video->pal->colors[i].b, 1);
+				read (fd, &video->pal->colors[i].g, 1);
+				read (fd, &video->pal->colors[i].r, 1);
+				lseek (fd, 1, SEEK_CUR);
+			}
+		}
+	}
+
+	/* Make the target VisVideo ready for use */
+	visual_video_set_depth (video, visual_video_depth_enum_from_value (bi_bitcount));
+	visual_video_set_dimension (video, bi_width, bi_height);
+	visual_video_allocate_buffer (video);
+
+	/* Set to the beginning of image data, note that MickeySoft likes stuff upside down .. */
+	lseek (fd, bf_bits, SEEK_SET);
+
+	pad = ((video->pitch % 4) ? (4 - (video->pitch % 4)) : 0);
+
+	data = video->pixels + (video->height * video->pitch);
+	while (data > (uint8_t *) video->pixels) {
+		data -= video->pitch;
+
+		if (read (fd, data, video->pitch) != video->pitch) {
+			visual_log (VISUAL_LOG_CRITICAL, "Bitmap data is not complete");
+			
+			visual_video_free_buffer (video);
+
+			return -VISUAL_ERROR_BMP_CORRUPTED;
+		}
+
+#if !VISUAL_LITTLE_ENDIAN
+		switch (bi_bitcount) {
+			case 24: {
+				int i, p;
+				for (p=0, i=0; i<bi_width; i++){
+#	if VISUAL_BIG_ENDIAN
+					uint8_t c[2];
+
+					c[0] = data[p];
+					c[1] = data[p+2];
+
+					data[p] = c[1];
+					data[p+2] = c[0];
+
+					p+=3;
+#	else
+#		error todo
+#	endif
+				}
+				break;
+			}
+			default:
+				visual_log (VISUAL_LOG_CRITICAL, "Internal error.");
+		}
+#endif
+
+		if (pad != 0) {
+			lseek (fd, 4, pad);
+		}
+	}
+
+	close (fd);
+
+	return VISUAL_OK;
+}
+
+/**
+ * Loads a bitmap into a VisVideo and return this, so it's not needed to 
+ * allocate a VisVideo before by hand.
+ *
+ * @see visual_bitmap_load
+ *
+ * @param filename The filename of the bitmap to be loaded.
+ *
+ * @return The VisVideo containing the bitmap or NULL on failure.
+ */
+VisVideo *visual_bitmap_load_new_video (const char *filename)
+{
+	VisVideo *video;
+
+	video = visual_video_new ();
+	
+	if (visual_bitmap_load (video, filename) < 0) {
+		visual_object_unref (VISUAL_OBJECT (video));
+
+		return NULL;
+	}
+
+	return video;
+}
+
+/**
+ * @}
+ */
+