| author | ecalot
<ecalot> 2004-06-20 16:36:42 UTC |
| committer | ecalot
<ecalot> 2004-06-20 16:36:42 UTC |
| parent | 518baa8fd44f1e268a94727451f0a0f28728a6d8 |
| FP/src/res/compress.c | +329 | -0 |
diff --git a/FP/src/res/compress.c b/FP/src/res/compress.c new file mode 100644 index 0000000..4f45131 --- /dev/null +++ b/FP/src/res/compress.c @@ -0,0 +1,329 @@ +/* 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 +*/ + +/* +compress.c: Princed Resources : Image Compression Library +\xaf\xaf\xaf\xaf\xaf\xaf\xaf\xaf\xaf\xaf + Copyright 2003, 2004 Princed Development Team + Created: 24 Aug 2003 + + Author: Enrique Calot <ecalot.cod@princed.com.ar> + Version: 1.01 (2003-Oct-23) + Version: 2.00 (2004-Mar-07) + + Note: + DO NOT remove this copyright notice +*/ + +#include <stdio.h> +#include <string.h> +#include "compress.h" +#include "memory.h" +//#include "pr.h" +#include "disk.h" /* array2short */ + +/***************************************************************\ +| I M P L E M E N T A T I O N | +\***************************************************************/ + +/***************************************************************\ +| Image transpose | +\***************************************************************/ + +/* Determines where the transposed byte must be saved */ +int transpose(int x,int w,int h) { + return ((x%h)*(w))+(int)(x/h); +} + +void transposeImage(tImage* image,int size) { + unsigned char* outputaux=getMemory(size); + int cursor=0; + + while (cursor<size) {outputaux[transpose(cursor,image->widthInBytes,image->height)]=image->pix[cursor];cursor++;} + free(image->pix); + image->pix=outputaux; +} + +void antiTransposeImage(tImage* image,int size) { + unsigned char* outputaux=getMemory(size); + int cursor=0; + + while (cursor<size) {outputaux[cursor]=image->pix[transpose(cursor,image->widthInBytes,image->height)];cursor++;} + free(image->pix); + image->pix=outputaux; +} + +/***************************************************************\ +| Uncompression algorithms | +\***************************************************************/ + +/* LZG expansion algorithm sub function */ +unsigned char popBit(unsigned char *byte) { + unsigned char bit=(unsigned char)((*byte)&1); + (*byte)>>=1; + return bit; +} + +/* Expands LZ Groody algorithm. This is the core of PR */ +int expandLzg(const unsigned char* array, int arraySize, tImage* image, int imageSize) { + char k; + int location,h,cursor=0,pos=0; + unsigned char maskbyte,rep; + + if ((image->pix=getMemory(/*imageSize*/MAX_MOD_SIZE_IN_LZG))==NULL) return COMPRESS_RESULT_FATAL; /* reserve memory */ + for(location=0;location<MAX_MOD_SIZE_IN_LZG;image->pix[location]=0,location++); /* clean output garbage */ + + /* main loop */ + while (cursor<imageSize) { + maskbyte=array[pos++]; + for (k=8;k&&(cursor<imageSize);k--) { + if (popBit(&maskbyte)) { + image->pix[cursor++]=array[pos++]; + } else { + location=66+(((rep=array[pos])&3)<<8)+(unsigned char)array[pos+1];pos+=2; + rep=(unsigned char)((rep>>2)+3); + while (rep--) { /* Be careful in big images */ + h=cursor/MAX_MXD_SIZE_IN_LZG-((location%MAX_MXD_SIZE_IN_LZG)>(cursor%MAX_MXD_SIZE_IN_LZG)); + image->pix[cursor++]=image->pix[((h<0)?0:h)*MAX_MXD_SIZE_IN_LZG+(location++)%MAX_MXD_SIZE_IN_LZG]; +/* + h=((cursor-(location&0x3FF))&(~0x3FF)); + image->pix[cursor]=image->pix[((h<0)?0:h)+(location&0x3FF)]; + cursor++;location++; +*/ + } + } + } + } + return ((pos==arraySize)&(cursor==imageSize))-1; /* WARNING or SUCCESS */ +} + +/* Expands RLE algorithm */ +int expandRle(const unsigned char* array, int arraySize, tImage* image, int imageSize) { + int cursor=0; + register signed char rep; + int pos=0; + + if ((image->pix=getMemory(imageSize+128))==NULL) return COMPRESS_RESULT_FATAL; /* reserve memory */ + + /* main loop */ + while (cursor<imageSize) { + rep=(signed char)(array[pos++]); + if (rep<0) { + /* Negative */ + while (rep++) image->pix[cursor++]=array[pos]; + pos++; + } else { + /* Positive */ + rep=~rep; + while (rep++) image->pix[cursor++]=array[pos++]; + } + } + return ((pos==arraySize)&(cursor==imageSize))-1; /* WARNING or SUCCESS */ +} + +/***************************************************************\ +| Compression algorithms | +\***************************************************************/ + +/* Compress using the Run Length Encoding algorithm */ +void compressRle(unsigned char* data,tImage* img,int *dataSize) { + /* Declare pointers */ + unsigned char* cursorData = data; + char* counter; + unsigned char* cursorPix = img->pix; + unsigned char* imgEnd = img->pix+(*dataSize); + + while (cursorPix<imgEnd) { + /* Step 1: Create counter */ + *(counter=(char*)(cursorData++))=-1; + + /* Step 2: Look and copy the string until a repeated byte is found */ + while ( + (cursorPix<imgEnd)&& + ( + (*cursorPix!=*(cursorPix+1))|| + ( + /*(*cursorPix==*(cursorPix+1))&&*/ + ((cursorPix+1)<imgEnd)&& + (*cursorPix!=*(cursorPix+2)) + ) + )&& + ((*counter)!=127) + ) { + *(cursorData)=*(cursorPix); + (*counter)++; + cursorPix++; + cursorData++; + } + + /* Step 3: If there was a repeated string, let's ignore it and add the cursor with the repetitions */ + if (*counter==-1) { + while ((cursorPix+1<imgEnd)&&(*cursorPix==(*(cursorPix+1)))&&((*counter)!=-128)) { + cursorPix++; + (*counter)--; + } + + *(cursorData)=*(cursorPix); /* Print repeated char */ + cursorPix++; + cursorData++; + } + } + + *(cursorData++)=0; + *(cursorData)=*(cursorPix); + *dataSize=(int)((long int)cursorData-(long int)data)-1; /* Note: casted to long for portability with 64 bits architectures */ +} + +/***************************************************************\ +| Main compress and expand graphics | +\***************************************************************/ + +/* + Header info: + 1 byte - checksum char checksum + 2 bytes - height short int height + 2 bytes - width short int width + 1 byte - 00 (char)0 + 1 byte - compression type unsigned char compressionType +*/ + +/* Expands an array into an image */ +int mExpandGraphic(const unsigned char* data,tImage *image, int dataSizeInBytes) { + /* + Reads data and extracts tImage + returns the next image address or -1 in case of error + */ + + int imageSizeInBytes; + int result; + + data++; + image->height=array2short(data);//((unsigned char)data[0])+((unsigned char)data[1]<<8);data+=2; + data+=2; + image->width =array2short(data);//((unsigned char)data[0])+((unsigned char)data[1]<<8);data+=2; + data+=2; + + if (*(data++)) return COMPRESS_RESULT_FATAL; /* Verify format */ + image->type=(unsigned char)(*(data++)); + dataSizeInBytes-=7; + if (image->type&0xB0) { + image->widthInBytes=(image->width+1)/2; + } else { + image->widthInBytes=(image->width+7)/8; + } + imageSizeInBytes=image->widthInBytes*image->height; + + switch (getAlgor(image->type)) { + case COMPRESS_RAW: /* No Compression Algorithm */ + if ((image->pix=getMemory(imageSizeInBytes))==NULL) return COMPRESS_RESULT_FATAL; + memcpy(image->pix,data,imageSizeInBytes); + result=COMPRESS_RESULT_SUCCESS; + break; + case COMPRESS_RLE_LR: /* RLE Left to Right Compression Algorithm */ + result=expandRle(data,dataSizeInBytes,image,imageSizeInBytes); + break; + case COMPRESS_RLE_UD: /* RLE Up to Down Compression Algorithm */ + result=expandRle(data,dataSizeInBytes,image,imageSizeInBytes); + if (result==COMPRESS_RESULT_FATAL) return COMPRESS_RESULT_FATAL; + transposeImage(image,imageSizeInBytes); + break; + case COMPRESS_LZG_LR: /* LZ Groody Left to Right Compression Algorithm */ + result=expandLzg(data,dataSizeInBytes,image,imageSizeInBytes); + break; + case COMPRESS_LZG_UD: /* LZ Groody Up to Down Compression Algorithm */ + result=expandLzg(data,dataSizeInBytes,image,imageSizeInBytes); + if (result==COMPRESS_RESULT_FATAL) return COMPRESS_RESULT_FATAL; + transposeImage(image,imageSizeInBytes); + break; + default: + result=COMPRESS_RESULT_FATAL; + break; + } + return result; /* Ok */ +} + +/* Compress an image into binary data */ +int mCompressGraphic(unsigned char* *data,tImage* image, int* dataSizeInBytes) { + /* Declare variables */ + unsigned char* compressed [COMPRESS_WORKING_ALGORITHMS]; + int compressedSize [COMPRESS_WORKING_ALGORITHMS]; + int algorithm; + int i; + int imageSizeInBytes; + + /* Initialize variables */ + imageSizeInBytes=image->widthInBytes*image->height; + for (i=0;i<COMPRESS_WORKING_ALGORITHMS;i++) compressedSize[i]=imageSizeInBytes; + + /* + Perform all compressions + */ + + /* COMPRESS_RAW */ + compressed[COMPRESS_RAW]=getMemory(compressedSize[COMPRESS_RAW]); + memcpy(compressed[COMPRESS_RAW],image->pix,compressedSize[COMPRESS_RAW]); + + /* COMPRESS_RLE_LR */ + compressed[COMPRESS_RLE_LR]=getMemory((10*imageSizeInBytes+50)); /* This will reserve 10*(image size)+50 bytes, to allocate the compressed file */ + compressRle(compressed[COMPRESS_RLE_LR],image,&(compressedSize[COMPRESS_RLE_LR])); + + /* COMPRESS_RLE_UD */ + compressed[COMPRESS_RLE_UD]=getMemory(10*imageSizeInBytes+50); /* This will reserve 10*(image size)+50 bytes, to allocate the compressed file */ + antiTransposeImage(image,imageSizeInBytes); + compressRle(compressed[COMPRESS_RLE_UD],image,&(compressedSize[COMPRESS_RLE_UD])); + + /* + Process results + */ + + /* Select the best compression (find minimum) */ + *dataSizeInBytes=compressedSize[COMPRESS_RAW]; + algorithm=COMPRESS_RAW; + for (i=COMPRESS_RLE_LR;i<COMPRESS_WORKING_ALGORITHMS;i++) { + if ((*dataSizeInBytes)>compressedSize[i]) { + (*dataSizeInBytes)=compressedSize[i]; + algorithm=i; + } + } + + /* Copy the best algorithm in the compressed data */ + *data=getMemory(*dataSizeInBytes+6); + memcpy(*data+6,compressed[algorithm],*dataSizeInBytes); + (*dataSizeInBytes)+=6; + + /* + Write header + */ + + /* (16 bits)height (Intel short int format) */ + (*data)[0]=image->height; + (*data)[1]=image->height>>8; + /* (16 bits)width (Intel short int format) */ + (*data)[2]=image->width; + (*data)[3]=image->width>>8; + /* (8 bits)00000000+(4 bits)palette type+(4 bits)algorithm */ + (*data)[4]=0; + (*data)[5]=image->type|algorithm; + + /* Free all compression attempts */ + for (i=COMPRESS_RAW;i<COMPRESS_WORKING_ALGORITHMS;i++) free(compressed[i]); + return 1; +} +