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
|
#include <assert.h>
#include <fstream>
#include "imageloader.h"
#include "../easylogging++.h"
using namespace std;
Image::Image(char* ps, int w, int h) : pixels(ps), width(w), height(h) {
VLOG(2) << "Constructing Image object [" << w << " x " << h << "]";
}
Image::~Image() {
VLOG(2) << "Destroying image object...";
delete[] pixels;
}
namespace {
//Converts a four-character array to an integer, using little-endian form
int toInt(const char* bytes) {
VLOG(2) << "Converting bytes to int";
return (int)(((unsigned char)bytes[3] << 24) |
((unsigned char)bytes[2] << 16) |
((unsigned char)bytes[1] << 8) |
(unsigned char)bytes[0]);
}
//Converts a two-character array to a short, using little-endian form
short toShort(const char* bytes) {
VLOG(2) << "Converting bytes to short";
return (short)(((unsigned char)bytes[1] << 8) |
(unsigned char)bytes[0]);
}
//Reads the next four bytes as an integer, using little-endian form
int readInt(ifstream &input) {
VLOG(2) << "Reading input as int...";
char buffer[4];
input.read(buffer, 4);
return toInt(buffer);
}
//Reads the next two bytes as a short, using little-endian form
short readShort(ifstream &input) {
VLOG(2) << "Reading input as short...";
char buffer[2];
input.read(buffer, 2);
return toShort(buffer);
}
//Just like auto_ptr, but for arrays
template<class T>
class auto_array {
private:
T* array;
mutable bool isReleased;
public:
explicit auto_array(T* array_ = NULL) :
array(array_), isReleased(false) {
VLOG(2) << "Creating auto_array";
}
auto_array(const auto_array<T> &aarray) {
VLOG(2) << "Copying auto_array";
array = aarray.array;
isReleased = aarray.isReleased;
aarray.isReleased = true;
}
~auto_array() {
VLOG(2) << "Destroying auto_array";
if (!isReleased && array != NULL) {
delete[] array;
}
}
T* get() const {
return array;
}
T &operator*() const {
return *array;
}
void operator=(const auto_array<T> &aarray) {
if (!isReleased && array != NULL) {
delete[] array;
}
array = aarray.array;
isReleased = aarray.isReleased;
aarray.isReleased = true;
}
T* operator->() const {
return array;
}
T* release() {
isReleased = true;
return array;
}
void reset(T* array_ = NULL) {
if (!isReleased && array != NULL) {
delete[] array;
}
array = array_;
}
T* operator+(int i) {
return array + i;
}
T &operator[](int i) {
return array[i];
}
};
}
Image* loadBMP(const char* filename) {
VLOG(1) << "Loading bitmap [" << filename << "]";
ifstream input;
input.open(filename, ifstream::binary);
CHECK(!input.fail()) << "Could not find file";
char buffer[2];
input.read(buffer, 2);
CHECK(buffer[0] == 'B' && buffer[1] == 'M') << "Not a bitmap file";
input.ignore(8);
int dataOffset = readInt(input);
//Read the header
int headerSize = readInt(input);
int width;
int height;
switch(headerSize) {
case 40:
//V3
width = readInt(input);
height = readInt(input);
input.ignore(2);
CHECK_EQ(readShort(input), 24) << "Image is not 24 bits per pixel";
CHECK_EQ(readShort(input), 0) << "Image is compressed";
break;
case 12:
//OS/2 V1
width = readShort(input);
height = readShort(input);
input.ignore(2);
CHECK_EQ(readShort(input), 24) << "Image is not 24 bits per pixel";
break;
case 64:
//OS/2 V2
LOG(FATAL) << "Can't load OS/2 V2 bitmaps";
break;
case 108:
//Windows V4
LOG(FATAL) << "Can't load Windows V4 bitmaps";
break;
case 124:
//Windows V5
LOG(FATAL) << "Can't load Windows V5 bitmaps";
break;
default:
LOG(FATAL) << "Unknown bitmap format";
}
//Read the data
VLOG(1) << "Reading bitmap data";
int bytesPerRow = ((width * 3 + 3) / 4) * 4 - (width * 3 % 4);
int size = bytesPerRow * height;
VLOG(1) << "Size of bitmap is [" << bytesPerRow << " x " << height << " = " << size;
auto_array<char> pixels(new char[size]);
input.seekg(dataOffset, ios_base::beg);
input.read(pixels.get(), size);
//Get the data into the right format
auto_array<char> pixels2(new char[width * height * 3]);
for(int y = 0; y < height; y++) {
for(int x = 0; x < width; x++) {
for(int c = 0; c < 3; c++) {
pixels2[3 * (width * y + x) + c] =
pixels[bytesPerRow * y + 3 * x + (2 - c)];
}
}
}
input.close();
return new Image(pixels2.release(), width, height);
}
|