Removed changes by Nicholas. These will need to be re-submitted through Trac and manually validated.

Added BMP (24-bit uncompressed, 8-bit uncompressed, and RLE8) and PNG support to File::ReadImageFile(). So far everything in FileHandler is presumed to be safe with any input file except UTK decompression.

Also started making use of the static keyword in various places to aid the compiler in optimization.
This commit is contained in:
Fatbag 2012-04-06 13:27:40 -05:00
parent 7442579090
commit cb751c0bb8
29 changed files with 692 additions and 1291 deletions

View file

@ -14,36 +14,101 @@
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <stdio.h>
#include <stdint.h>
#include <memory.h>
#include <stdio.h>
#include <setjmp.h> //Used by libpng
#include "bmp/read_bmp.h"
#include "libjpeg-turbo/jpeglib.h"
#include "libpng/png.h"
#define NOWINDOWS
#include "FileHandler.hpp"
namespace File {
enum ImageType {
FIMG_BMP,
FIMG_JPEG,
FIMG_PNG,
FIMG_TGA,
FIMG_COUNT
};
uint8_t * ReadJPG(Image_t * Image, const uint8_t * InData, size_t FileSize);
uint8_t * ReadBMP(Image_t * Image, const uint8_t * InData, size_t FileSize);
uint8_t * ReadPNG(Image_t * Image, const uint8_t * InData, size_t FileSize);
uint8_t * ReadTGA(Image_t * Image, const uint8_t * InData, size_t FileSize);
static const uint8_t Signature[] = {
'B', //BMP
0xFF, //JPEG
0x89, //PNG
0x00 //TGA
};
static uint8_t* (* const ImageFunction[])(Image_t*, const uint8_t*, size_t) = {
ReadBMP,
ReadJPG,
ReadPNG,
ReadTGA
};
Image_t * ReadImageFile(const char * Filename){
uint8_t * InData = File::ReadFile(Filename);
if(InData == NULL) return NULL;
if(File::FileSize < 4){
free(InData);
File::Error = FERR_INVALIDDATA;
return NULL;
}
Image_t * Image = (Image_t*) malloc(sizeof(Image_t));
if(Image == NULL){
free(InData);
File::Error = FERR_MEMORY;
return NULL;
}
uint8_t * OutData = ReadJPG(Image, InData, File::FileSize);
free(InData);
if(OutData != NULL){
return Image;
uint8_t * OutData = NULL;
for(int i=0; i<FIMG_COUNT; i++){
if(InData[0] == Signature[i]){
OutData = ImageFunction[i](Image, InData, File::FileSize);
free(InData);
if(OutData == NULL){
File::Error = FERR_INVALIDDATA;
return NULL;
}
return Image;
}
}
free(InData);
File::Error = FERR_UNRECOGNIZED;
free(Image);
return NULL;
}
uint8_t * ReadBMP(Image_t * Image, const uint8_t * InData, size_t FileSize){
bmpheader_t BMPHeader;
if(!bmp_read_header(&BMPHeader, InData, FileSize)){
return NULL;
}
uint8_t * OutData = (uint8_t*) malloc(BMPHeader.DecompressedSize);
if(OutData == NULL){
return NULL;
}
if(!bmp_read_data(&BMPHeader, InData, OutData)){
free(OutData);
return NULL;
}
Image->Width = BMPHeader.biWidth;
Image->Height = BMPHeader.biHeight;
Image->Format = FIMG_BGR24;
Image->Data = OutData;
return OutData;
}
uint8_t * ReadJPG(Image_t * Image, const uint8_t * InData, size_t FileSize){
//Initialize
jpeg_decompress_struct cinfo;
@ -55,6 +120,7 @@ uint8_t * ReadJPG(Image_t * Image, const uint8_t * InData, size_t FileSize){
jpeg_destroy_decompress(&cinfo);
return NULL;
}
cinfo.out_color_space = JCS_EXT_BGR;
if(!jpeg_start_decompress(&cinfo)){
jpeg_destroy_decompress(&cinfo);
return NULL;
@ -68,10 +134,11 @@ uint8_t * ReadJPG(Image_t * Image, const uint8_t * InData, size_t FileSize){
jpeg_destroy_decompress(&cinfo);
return NULL;
}
for(unsigned i=0; cinfo.output_scanline < cinfo.output_height; i++){
for(unsigned i=cinfo.output_height; i; i--){
//According to the libjpeg documentation,
//jpeg_read_scanlines can only really read 1 scanline at a time.
uint8_t * Location = OutData + i*row_stride;
//We need to convert to bottom-up format anyway.
uint8_t * Location = OutData + (i-1)*row_stride;
if(!jpeg_read_scanlines(&cinfo, &Location, 1)){
free(OutData);
jpeg_finish_decompress(&cinfo);
@ -92,4 +159,64 @@ uint8_t * ReadJPG(Image_t * Image, const uint8_t * InData, size_t FileSize){
return OutData;
}
struct pngdata_t {
const uint8_t * buffer;
size_t size;
};
static void user_read_data(png_structp png_ptr, png_bytep data, png_size_t length){
pngdata_t *pngdata = (pngdata_t *) png_get_io_ptr(png_ptr);
if(length > pngdata->size) png_error(png_ptr, "");
memcpy(data, pngdata->buffer, length);
pngdata->buffer += length;
pngdata->size -= length;
}
uint8_t * ReadPNG(Image_t * Image, const uint8_t * InData, size_t FileSize){
pngdata_t pngdata;
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if(png_ptr == NULL) return 0;
png_infop info_ptr = png_create_info_struct(png_ptr);
if(info_ptr == NULL){
png_destroy_read_struct(&png_ptr, NULL, NULL);
return NULL;
}
if(setjmp(png_jmpbuf(png_ptr))){
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
return NULL;
}
pngdata.buffer = InData;
pngdata.size = FileSize;
png_set_read_fn(png_ptr, &pngdata, user_read_data);
png_set_user_limits(png_ptr, 4096, 4096);
png_read_png(png_ptr, info_ptr,
PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_STRIP_ALPHA |
PNG_TRANSFORM_PACKING | PNG_TRANSFORM_GRAY_TO_RGB | PNG_TRANSFORM_BGR, NULL);
//png_get_IHDR does not work in high-level mode.
unsigned width = png_get_image_width(png_ptr, info_ptr);
unsigned height = png_get_image_height(png_ptr, info_ptr);
uint8_t * OutData = (uint8_t *) malloc(width*height*3);
if(OutData == NULL){
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
return NULL;
}
uint8_t **Scanlines = png_get_rows(png_ptr, info_ptr);
printf("png:Now. %ux%u\n", width, height);
for(unsigned i=0; i<height; i++)
memcpy(OutData + i*width*3, Scanlines[height-i-1], width*3);
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
Image->Width = width;
Image->Height = height;
Image->Format = FIMG_BGR24;
Image->Data = OutData;
return OutData;
}
uint8_t * ReadTGA(Image_t * Image, const uint8_t * InData, size_t FileSize){
return NULL;
}
}