git » fp-git.git » master » tree

[master] / PR / src / lib / formats / bmp.c

/*  Princed V3 - Prince of Persia Level Editor for PC Version
    Copyright (C) 2003 Princed Development Team

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 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 General Public License for more details.

    You should have received a copy of the GNU 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

    The authors of this program may be contacted at http://forum.princed.com.ar
*/

/*
bmp.c: Princed Resources : BMP file support
�����
 Copyright 2003 Princed Development Team
  Created: 24 Aug 2003

  Author: Enrique Calot <ecalot.cod@princed.com.ar>
  Version: 1.01 (2003-Oct-23)
  Version: 1.10 (2004-Feb-17)

 Note:
  DO NOT remove this copyright notice
*/

#include "bmp.h"
#include "common.h"
#include "compress.h"
#include "dat.h"
#include "disk.h"
#include "memory.h"
#include "palette.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int mWriteBmp(const char* file,const unsigned char* data, int w, int h, int b, int colors, const tColor* colorArray, int lineWidth, int optionflag, const char* backupExtension) {

	/* declare variables */
	int a;
	unsigned short int planes=1;
	unsigned long int colours=colors;
	unsigned long int extra=1000;
	unsigned long int filesize;
	unsigned long int headerSize;
	unsigned long int height=h;
	unsigned long int offset;
	unsigned short int bits=b;
	unsigned char color;
	unsigned long int width=w;
	const unsigned long int zero=0;
	char lineSerialization;
	FILE* bitmap;

	/* open file */
	if (!writeOpen(file,&bitmap,optionflag)) return PR_RESULT_F_FILE_NOT_WRITE_ACCESS;

	/* initialize variables */
/*	width=img.width;
	height=img.height;
	bits=getCarry(img.type);
	colours=1<<bits;*/
	headerSize=40;
	offset=54+(colors<<2);
	lineSerialization=(-lineWidth)&3;
	filesize=offset+(lineWidth+lineSerialization)*height;

	/* Write header */
	fwrite     ("BM",2,1   ,bitmap);    /* Magic identifier            */
	fwritelong (&filesize  ,bitmap);    /* File size in bytes          */
	fwritelong (&zero      ,bitmap);    /* reserved                    */
	fwritelong (&offset    ,bitmap);    /* Offset to image data, bytes */
	fwritelong (&headerSize,bitmap);    /* Header size in bytes        */
	fwritelong (&width     ,bitmap);    /* Width of image              */
	fwritelong (&height    ,bitmap);    /* Height of image             */
	fwriteshort(&planes    ,bitmap);    /* Number of colour planes     */
	fwriteshort(&bits      ,bitmap);    /* Bits per pixel              */
	fwritelong (&zero      ,bitmap);    /* Compression type (0=none)   */
	fwritelong (&zero      ,bitmap);    /* Image size in bytes (may be 0 if no compression) */
	fwritelong (&extra     ,bitmap);    /* Pixels per meter x          */
	fwritelong (&extra     ,bitmap);    /* Pixels per meter y          */
	fwritelong (&colours   ,bitmap);    /* Number of colours           */
	fwritelong (&zero      ,bitmap);    /* Important colours           */

	/* Write ColorTable */
	for (a=0;a<colors;a++) {
		color=colorArray[a].b;
		fwritechar(&color,bitmap); /* Blue  */
		color=colorArray[a].g;
		fwritechar(&color,bitmap); /* Green */
		color=colorArray[a].r;
		fwritechar(&color,bitmap); /* Red   */
		fwritechar(&zero ,bitmap); /* alpha */
	}

	/* Write data */
	while (h--) {
		fwrite(data+h*lineWidth,lineWidth,1,bitmap);
		fwrite(&zero,lineSerialization,1,bitmap);
	}

	writeCloseOk(bitmap,optionflag,backupExtension);
	return PR_RESULT_SUCCESS;
}

int readBmp(const char* file, unsigned char** data, int *ph, int *pw,  int *pbits, int *pcolors, tColor** colorArray, int *plineWidth) {
/*int mReadBitMap(tImage* image,unsigned char* data, int size) {*/
	FILE* bitmap;
	char lineSerialization;
	int ok;
	char magic[2];
	int a;
	unsigned long int colours=0;
	unsigned long int filesize=0;
	unsigned long int offset=0;
	unsigned long int aux=0;
	unsigned short int bits=0;
	unsigned short int height=0;
	unsigned short int width=0;

	bitmap=fopen(file,"rb");
	if (!bitmap) return PR_RESULT_F_FILE_NOT_READ_ACCESS;

	/* Read headers */
		/* file header */
	ok=fread(magic,2,1         ,bitmap);
	ok=ok&&!strncmp(magic,"BM",2);
	ok=ok&&freadlong(&filesize ,bitmap);
	ok=ok&&freadlong(&aux      ,bitmap);
	ok=ok&&(!aux);
	ok=ok&&freadlong(&offset   ,bitmap);

		/* info header */
	ok=ok&&freadlong(&aux      ,bitmap);
	ok=ok&&(aux==40);
	ok=ok&&freadlong(&width    ,bitmap);
	ok=ok&&freadlong(&height   ,bitmap);
	ok=ok&&freadshort(&aux     ,bitmap);
	ok=ok&&(aux==1);
	ok=ok&&freadshort(&bits    ,bitmap);
	ok=ok&&freadlong(&aux      ,bitmap);    /* Compression type (0=none)   */
	if (ok&&aux!=0) { fclose(bitmap); return -1; /* PR_NO_COMPRESS_SUPPORT */ }
	ok=ok&&freadlong(&aux      ,bitmap);    /* Image size in bytes (junk)  */
	ok=ok&&freadlong(&aux      ,bitmap);    /* Pixels per meter x (junk)   */
	ok=ok&&freadlong(&aux      ,bitmap);    /* Pixels per meter y (junk)   */
	ok=ok&&freadlong(&colours  ,bitmap);    /* Number of colours (junk)    */
	ok=ok&&(colours<1000);
	ok=ok&&freadlong(&aux      ,bitmap);    /* Important colours (junk)    */

	/* Verify */
	*plineWidth=(width*bits+7)/8; /* Note: only works in bits=1,2,4,8 */
	lineSerialization=(-*plineWidth)&3;
/*	offset=54+(colors<<2);
	lineSerialization=(-lineWidth)&3;
	filesize=offset+(lineWidth+lineSerialization)*height;*/

	/* Read ColorTable */
	aux=0;
	*colorArray=malloc(sizeof(tColor)*colours);
	for (a=0;a<colours;a++) {
		ok=ok&&freadchar(&((*colorArray)[a].b),bitmap); /* Blue  */
		ok=ok&&freadchar(&((*colorArray)[a].g),bitmap); /* Green */
		ok=ok&&freadchar(&((*colorArray)[a].r),bitmap); /* Red   */
		ok=ok&&freadchar(&aux,bitmap); /* alpha */
	}

	/* Write data */
	*ph=height;
	*pw=width;
	*data=malloc((*plineWidth+lineSerialization)*height);
	while (height--) {
		ok=ok&&fread(*data+height**plineWidth,*plineWidth,1,bitmap);
		if (lineSerialization) ok=ok&&fread(&aux,lineSerialization,1,bitmap);
	}

#if 0
	/* Validate if there is header and if it starts in BM */
	ok    = size>50;
	ok=ok&& data[0]=='B' && data[1]=='M';
	/* Read sizes from header */
	width=(unsigned short)array2short(data+18);
	height=(unsigned short)array2short(data+22);
	bits=(unsigned short)(data[28]);

	/* Save sizes into image */
	image->width=width;            /* width in pixels */
	image->height=height;

	/* Calculate serialized widths */
	carry=(bits==1)?0:2;
	image->type=(bits==1)?0:0xB0;
	colours=1<<bits;
	offset=54+(colours<<2);
	width=(width+1)>>1;
	image->widthInBytes=(width+(0x07>>(1+carry)))>>(2-carry); /* this is an optimization of /(8/bits) : image->widthInBytes=imageWidthInPixels*bitsPerPixel/(8 bits/byte) */
	lineSerialization=(-image->widthInBytes)&3;
	serializedWidth=image->widthInBytes+lineSerialization;
	filesize=offset+serializedWidth*height;

	/* Validate image and file size; get memory to allocate the image */
	ok=ok&& (filesize==size);
	ok=ok&& (	(image->pix=malloc(height*image->widthInBytes*2)) != NULL	);
	/* if validations==wrong */
	if (!ok) {
		freeAllocation(image->pix);
		return 0; /* false: this is not a valid BMP file format or memory too low */
	}

	/* Serialize bitmap-->raw array */
	while (height--)
		memcpy(
			image->pix+(x++)*image->widthInBytes,
			data+offset+height*serializedWidth,
			image->widthInBytes
		);
#endif

	if (!ok) {
		free(*colorArray);
		free(*data);
		return PR_RESULT_F_FILE_NOT_READ_ACCESS; /* TODO: use a bad format code */
	}

	*pbits        = bits;
	*pcolors      = colours;

	return PR_RESULT_SUCCESS;
}