1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236
|
// ==============================================================
// This file is part of Glest Shared Library (www.glest.org)
//
// Copyright (C) 2001-2010 MartiƱo Figueroa and others
//
// You can redistribute this code 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
// ==============================================================
#include "JPGReader.h"
#include "FileReader.h"
#include "data_types.h"
#include "pixmap.h"
#include <stdexcept>
#include <jpeglib.h>
#include <setjmp.h>
#include "util.h"
#include "leak_dumper.h"
using std::runtime_error;
using std::ios;
namespace Shared{ namespace Graphics{
// =====================================================
// Methods used for JPG-Decompression
// =====================================================
//Methods used by jpeglib
static void init_source(j_decompress_ptr cinfo) {
//It already is initialized
}
static boolean fill_input_buffer (j_decompress_ptr cinfo) {
//it is already filled
return boolean(true);
}
static void skip_input_data (j_decompress_ptr cinfo, long num_bytes) {
if (num_bytes > 0) {
jpeg_source_mgr* This = cinfo->src;
This->bytes_in_buffer-= num_bytes;
This->next_input_byte+= num_bytes;
}
}
static void term_source (j_decompress_ptr cinfo) {
}
// =====================================================
// class JPGReader
// =====================================================
/**Return an array containing the used extensions,
* initialized*/
//static inline const string* getExtensions() {
//static const string extensions[] = {"jpg", "jpeg", ""};
static inline std::vector<string> getExtensions() {
static std::vector<string> extensions;
if(extensions.empty() == true) {
extensions.push_back("jpg");
extensions.push_back("jpeg");
}
return extensions;
}
JPGReader::JPGReader(): FileReader<Pixmap2D>(getExtensions()) {}
Pixmap2D* JPGReader::read(ifstream& is, const string& path, Pixmap2D* ret) const {
if(GlobalStaticFlags::getIsNonGraphicalModeEnabled() == true) {
throw megaglest_runtime_error("Loading graphics in headless server mode not allowed!");
}
//Read file
is.seekg(0, ios::end);
streampos length = is.tellg();
if (length < 8) {
return NULL;
}
is.seekg(0, ios::beg);
uint8 *buffer = new uint8[(unsigned int)length];
is.read((char*)buffer, (std::streamsize)length);
static bool bigEndianSystem = Shared::PlatformByteOrder::isBigEndian();
if(bigEndianSystem == true) {
Shared::PlatformByteOrder::fromEndianTypeArray<uint8>(buffer,(size_t)length);
}
if(length < 2) {
throw megaglest_runtime_error("length < 2",true);
}
//Check buffer (weak jpeg check)
//if (buffer[0] != 0x46 || buffer[1] != 0xA0) {
// Proper header check found from: http://www.fastgraph.com/help/jpeg_header_format.html
if (buffer[0] != 0xFF || buffer[1] != 0xD8) {
std::cout << "0 = [" << std::hex << (int)buffer[0] << "] 1 = [" << std::hex << (int)buffer[1] << "]" << std::endl;
delete[] buffer;
throw megaglest_runtime_error(path +" is not a jpeg",true);
}
struct jpeg_decompress_struct cinfo;
struct jpeg_error_mgr jerr;
JSAMPROW row_pointer[1];
row_pointer[0] = NULL;
cinfo.err = jpeg_std_error( &jerr ); //Standard error handler
jpeg_create_decompress( &cinfo ); //Create decompressing structure
struct jpeg_source_mgr source;
jmp_buf error_buffer; //Used for saving/restoring context
// Set up data pointer
source.bytes_in_buffer = (size_t)length;
source.next_input_byte = (JOCTET*)buffer;
cinfo.src = &source;
if (setjmp(error_buffer)) { //Longjump was called --> an exception was thrown
delete[] buffer;
jpeg_destroy_decompress(&cinfo);
if (row_pointer[0] != NULL) {
delete[] row_pointer[0];
}
throw megaglest_runtime_error(path +" is a corrupt(1) jpeg",true);
}
source.init_source = init_source;
source.fill_input_buffer = fill_input_buffer;
source.resync_to_restart = jpeg_resync_to_restart;
source.skip_input_data = skip_input_data;
source.term_source = term_source;
/* reading the image header which contains image information */
if (jpeg_read_header( &cinfo, TRUE ) != JPEG_HEADER_OK) {
delete[] buffer;
jpeg_destroy_decompress(&cinfo);
throw megaglest_runtime_error(path +" is a corrupt(1) jpeg",true);
}
/*std::cout << "JPEG FILE Information: " << std::endl;
std::cout << "Image width and height: " << cinfo.image_width <<" pixels and " << cinfo.image_height <<" pixels." << std::endl;
std::cout << "Color components per fixel: " << cinfo.num_components << std::endl;
std::cout << "Color space: " << cinfo.jpeg_color_space << std::endl;*/
int picComponents = (ret->getComponents() == -1)?cinfo.num_components:ret->getComponents();
//std::cout << "JPG-Components: Pic: " << picComponents << " old: " << (ret->getComponents()) << " File: " << cinfo.num_components << std::endl;
//picComponents = 4;
// Start decompression jpeg here
jpeg_start_decompress( &cinfo );
ret->init(cinfo.image_width, cinfo.image_height, picComponents);
uint8* pixels = ret->getPixels();
//std::cout << "output width and height: " << cinfo.output_width <<" pixels and " << cinfo.output_height <<" pixels." << std::endl;
/* now actually read the jpeg into the raw buffer */
row_pointer[0] = new unsigned char[cinfo.output_width*cinfo.num_components];
/* read one scan line at a time */
/* Again you need to invert the lines unfortunately*/
while( cinfo.output_scanline < cinfo.output_height )
{
jpeg_read_scanlines( &cinfo, row_pointer, 1 );
//Current pixel
size_t location = (cinfo.output_height - cinfo.output_scanline) * cinfo.output_width * picComponents;
if (picComponents == cinfo.num_components) {
memcpy(pixels+location,row_pointer[0],cinfo.output_width*cinfo.num_components);
} else {
int r,g,b,a,l;
for (unsigned int xPic = 0, xFile = 0; xPic < cinfo.output_width*picComponents; xPic+= picComponents, xFile+= cinfo.num_components) {
switch(cinfo.num_components) {
case 3:
r = row_pointer[0][xFile];
g = row_pointer[0][xFile+1];
b = row_pointer[0][xFile+2];
l = (r+g+b+2)/3;
a = 255;
break;
case 4:
r = row_pointer[0][xFile];
g = row_pointer[0][xFile+1];
b = row_pointer[0][xFile+2];
l = (r+g+b+2)/3;
a = row_pointer[0][xFile+3];
break;
default:
// Possible Error
case 1:
r = g = b = l = row_pointer[0][xFile];
a = 255;
break;
}
switch (picComponents) {
case 1:
pixels[location+xPic] = l;
break;
case 4:
pixels[location+xPic+3] = a; //Next case
case 3:
pixels[location+xPic] = r;
pixels[location+xPic+1] = g;
pixels[location+xPic+2] = b;
break;
default:
//just so at least something works
for (int i = 0; i < picComponents; ++i) {
pixels[location+xPic+i] = l;
}
break;
// Possible Error
}
}
}
}
/*for(int i = 0; i < cinfo.image_width*cinfo.image_height*picComponents; ++i) {
if (i%39 == 0) std::cout << std::endl;
int first = pixels[i]/16;
if (first < 10)
std:: cout << first;
else
std::cout << (char)('A'+(first-10));
first = pixels[i]%16;
if (first < 10)
std:: cout << first;
else
std::cout << (char)('A'+(first-10));
std::cout << " ";
}*/
/* wrap up decompression, destroy objects, free pointers and close open files */
jpeg_finish_decompress( &cinfo );
jpeg_destroy_decompress( &cinfo );
delete[] row_pointer[0];
delete[] buffer;
return ret;
}
}} //end namespace
|