cgv
Loading...
Searching...
No Matches
bmp_reader.cxx
1#ifdef WIN32
2#pragma warning (disable:4996)
3#endif
4
5#include "bmp_reader.h"
6#include <iostream>
7#include <cgv/base/import.h>
8#include <cgv/base/register.h>
9
10using namespace cgv::data;
11
12namespace cgv {
13 namespace media {
14 namespace image {
15
18{
19}
20
23{
24 if (fp)
25 fclose(fp);
26 fp = 0;
27}
28
30std::string bmp_reader::get_type_name() const
31{
32 return "bmp_reader";
33}
34
37{
38 return new bmp_reader();
39}
40
42const std::string& bmp_reader::get_last_error() const
43{
44 return last_error;
45}
46
49{
50 return "bmp";
51}
52
53#define GET_2B(array,offset) ( (unsigned int) array[offset] + (((unsigned int) array[offset+1]) << 8) )
54#define GET_4B(array,offset) ( (unsigned int) array[offset] + (((unsigned int) array[offset+1]) << 8) + \
55 (((unsigned int) array[offset+2]) << 16) + (((unsigned int) array[offset+3]) << 24) )
56
58bool bmp_reader::open(const std::string& file_name, data_format& df, std::vector<data_format>* palette_formats)
59{
60 if (fp != 0)
61 close();
62 palette.clear();
63
64 fp = cgv::base::open_data_file(file_name.c_str(), "rb");
65 if (!fp) {
66 last_error = "could not open file: ";
67 last_error += file_name;
68 return false;
69 }
70 unsigned char bmp_header[14];
71 if (fread(bmp_header, 1, 14, fp) != 14) {
72 last_error = "could not read bmp header"; fclose(fp); fp = 0; return false;
73 }
74 if (GET_2B(bmp_header,0) != 0x4D42) {
75 last_error = "bmp header does not start with BM"; fclose(fp); fp = 0; return false;
76 }
77 unsigned char bmp_info[64];
78 if (fread(bmp_info, 1, 4, fp) != 4) {
79 last_error = "could not read first 4 bytes of bmp info"; fclose(fp); fp = 0; return false;
80 }
81 unsigned int info_size = GET_4B(bmp_info,0);
82 if (!(info_size == 12 || info_size == 40 || info_size == 64)) {
83 last_error = "unknown size of bmp info"; fclose(fp); fp = 0; return false;
84 }
85 if (fread(bmp_info+4, 1, info_size-4, fp) != info_size-4) {
86 last_error = "could not read bmp info"; fclose(fp); fp = 0; return false;
87 }
88 unsigned int width = 0, height = 0, planes = 1, bits_per_pixel = 1;
89 switch ((int) info_size) {
90 case 12: /* Decode OS/2 1.x header (Microsoft calls this a BITMAPCOREHEADER) */
91 width = GET_2B(bmp_info,4);
92 height = GET_2B(bmp_info,6);
93 planes = GET_2B(bmp_info,8);
94 bits_per_pixel = GET_2B(bmp_info,10);
95 break;
96 case 40:
97 case 64:
98 /* Decode Windows 3.x header (Microsoft calls this a BITMAPINFOHEADER) */
99 /* or OS/2 2.x header, which has additional fields that we ignore */
100 width = GET_4B(bmp_info,4);
101 height = GET_4B(bmp_info,8);
102 planes = GET_2B(bmp_info,12);
103 bits_per_pixel = GET_2B(bmp_info,14);
104 /*biXPelsPerMeter = GET_4B(bmp_info,24), biYPelsPerMeter = GET_4B(bmp_info,28), biSizeImage, biClrImportant fields are ignored */
105 if (GET_4B(bmp_info,16) != 0) {
106 last_error = "compressed bmp files not supported"; fclose(fp); fp = 0; return false;
107 }
108 if (bits_per_pixel == 8 && GET_4B(bmp_info,32) != 256) {
109 last_error = "only bmp palettes with 256 entries supported allowed"; fclose(fp); fp = 0; return false;
110 }
111 break;
112 }
113 if (planes != 1) {
114 last_error = "bad number of planes in bmp file"; fclose(fp); fp = 0; return false;
115 }
116 if (!(bits_per_pixel == 8 || bits_per_pixel == 24)) {
117 last_error = "bad number of bits per pixel in bmp file"; fclose(fp); fp = 0; return false;
118 }
119
120 /* Compute distance to bitmap data --- will adjust for colormap below */
121 int skip_bytes = GET_4B(bmp_header,10) - (info_size + 14);
122
123 /* Read the colormap, if any */
124 if (bits_per_pixel == 8) {
125 int nr_entries = (info_size == 12) ? 3 : 4;
126 palette.resize(nr_entries*256);
127 if (fread(&palette[0], 1, nr_entries*256, fp) != (size_t)(nr_entries*256)) {
128 last_error = "could not read bmp color map"; palette.clear(); fclose(fp); fp = 0; return false;
129 }
130 skip_bytes -= nr_entries*256;
131 for (unsigned int i = 0; i < 256; ++i) {
132 unsigned char tmp = palette[nr_entries*i];
133 palette[3*i] = palette[nr_entries*i+2];
134 palette[3*i+1] = palette[nr_entries*i+1];
135 palette[3*i+2] = tmp;
136 }
137 }
138 /* Skip any remaining pad bytes */
139 if (skip_bytes < 0) {
140 last_error = "bmp incorrect bfOffBits value?"; palette.clear(); fclose(fp); fp = 0; return false;
141 }
142 while (--skip_bytes >= 0) {
143 fgetc(fp);
144 }
145 if (bits_per_pixel == 8 && palette_formats) {
146 df = data_format(width, height, cgv::type::info::TI_UINT8, "0");
147 palette_formats->push_back(data_format(256, cgv::type::info::TI_UINT8, CF_RGB));
148 }
149 else
150 df = data_format(width, height, cgv::type::info::TI_UINT8, CF_RGB);
151 return true;
152}
153
155bool bmp_reader::read_palette(unsigned int i, const data_view& dv)
156{
157 if (palette.empty()) {
158 last_error = "bmp file has no palette";
159 return false;
160 }
161 if (i > 0) {
162 last_error = "only one palette in bmp file";
163 return false;
164 }
165 std::copy(&palette[0], &palette[3*256], dv.get_ptr<unsigned char>());
166 return true;
167}
168
171{
172 return true;
173}
176{
177// static unsigned char temp[4];
178 unsigned char* data_ptr = dv.get_ptr<unsigned char>();
179 size_t n = df.get_width();
180 if (palette.empty()) {
181 if (fread(data_ptr, 3, n, fp) != n) {
182 last_error = "bmp read error"; return false;
183 }
184 for (size_t x = 0; x < n; ++x, data_ptr +=3)
185 std::swap(data_ptr[0], data_ptr[2]);
186 n *= 3;
187 }
188 else {
189 if (fread(data_ptr, 1, n, fp) != n) {
190 last_error = "bmp read error"; return false;
191 }
192 if (dv.get_format()->get_nr_components() == 3) {
193 data_ptr += n;
194 unsigned char* dest_ptr = data_ptr + 2*n;
195 for (size_t x = 0; x < n; ++x) {
196 --data_ptr;
197 dest_ptr -= 3;
198 const unsigned char* p = &palette[3*(*data_ptr)];
199 dest_ptr[0] = p[0];
200 dest_ptr[1] = p[1];
201 dest_ptr[2] = p[2];
202 }
203 }
204 }
205 while ((n & 3) != 0) {
206 fgetc(fp);
207 n++;
208 }
209 return true;
210}
211
214{
215 bool success = true;
216 for (unsigned int y = 0; success && y < df.get_height(); ++y)
217 success = read_line(df, dv(y));
218 return success;
219}
222{
223 if (!fp) {
224 last_error = "attempt to close a not open bmp file";
225 return false;
226 }
227 int res = fclose(fp);
228 if (res != 0)
229 last_error = "closing of bmp file failed";
230 fp = 0;
231 return res == 0;
232}
233
234cgv::base::object_registration<bmp_reader> brr("register bmp reader");
235
236 }
237 }
238}
complete implementation of method actions that only call one method when entering a node
Definition action.h:113
unsigned int get_nr_components() const
return the number of components
A data_format describes a multidimensional data block of data entries.
Definition data_format.h:17
size_t get_width() const
return the resolution in the first dimension, or 1 if not defined
size_t get_height() const
return the resolution in the second dimension, or 1 if not defined
const data_format * get_format() const
return the component format
Definition data_view.cxx:73
cgv::type::func::transfer_const< P, S * >::type get_ptr() const
return a data pointer to type S
Definition data_view.h:61
the data view gives access to a data array of one, two, three or four dimensions.
Definition data_view.h:153
abstract interface for image readers
bmp_reader()
default constructor
std::string get_type_name() const
overload to return the type name of this object
bool close()
close the image file
~bmp_reader()
close file in destructor
abst_image_reader * clone() const
construct a copy of the reader
const char * get_supported_extensions() const
return a string containing a colon separated list of extensions that can be read with this reader
bool supports_per_line_read() const
whether the reader supports per line reading (only valid after successful opening an image file
bool read_image(const cgv::data::data_format &df, const cgv::data::data_view &dv)
read the whole image into the given data pointer, set data format if not yet specified and allocate t...
bool read_line(const cgv::data::data_format &df, const cgv::data::data_view &dv)
read the next line into the given data pointer, set data format if not yet specified and allocate the...
const std::string & get_last_error() const
return a reference to the last error message
bool read_palette(unsigned int i, const cgv::data::data_view &dv)
read the i-th palette in case of a paletted file format, the standard implementation returns false
bool open(const std::string &file_name, cgv::data::data_format &df, std::vector< cgv::data::data_format > *palette_formats)
open the file and read the image header in order to determine the data format
FILE * open_data_file(const std::string &file_name, const char *mode)
open a file with fopen supporting resource files, that have the prefix "res://"
Definition import.cxx:350
namespace for data management components
@ CF_RGB
color format with two components R and G
@ TI_UINT8
signed integer stored in 64 bits
Definition type_id.h:23
the cgv namespace
Definition print.h:11