1 #ifdef _MSC_VER
2 #pragma warning(disable : 4996)
3 #endif
4
5 #include <memory>
6
7 #include "tiio_bmp.h"
8 // #include "bmp/filebmp.h"
9 #include "tpixel.h"
10 #include "tpixelgr.h"
11 #include "tproperty.h"
12 //#include "tconvert.h"
13 #include <stdio.h>
14
15 //=========================================================
16
17 namespace {
18
19 //=========================================================
20
21 typedef struct {
22 UINT bfSize;
23 UINT bfOffBits;
24 UINT biSize;
25 UINT biWidth;
26 UINT biHeight;
27 UINT biPlanes;
28 UINT biBitCount;
29 UINT biCompression;
30 UINT biSizeImage;
31 UINT biXPelsPerMeter;
32 UINT biYPelsPerMeter;
33 UINT biClrUsed;
34 UINT biClrImportant;
35 UINT biFilesize;
36 UINT biPad;
37
38 } BMP_HEADER;
39
40 const int BMP_WIN_SIZE = 40;
41 const int BMP_OS2_SIZE = 64;
42
43 const int BMP_BI_RGB = 0;
44 const int BMP_BI_RLE8 = 1;
45 const int BMP_BI_RLE4 = 2;
46
47 //=========================================================
48
getshort(FILE * fp)49 UINT getshort(FILE *fp) {
50 int c = getc(fp), c1 = getc(fp);
51
52 return ((UINT)c) + (((UINT)c1) << 8);
53 }
54
55 //---------------------------------------------------------
56
getint(FILE * fp)57 UINT getint(FILE *fp) {
58 int c = getc(fp), c1 = getc(fp), c2 = getc(fp), c3 = getc(fp);
59
60 return (((UINT)c) << 0) + (((UINT)c1) << 8) + (((UINT)c2) << 16) +
61 (((UINT)c3) << 24);
62 }
63
64 //---------------------------------------------------------
65
putshort(FILE * fp,int i)66 void putshort(FILE *fp, int i) {
67 int c = (((UINT)i)) & 0xff, c1 = (((UINT)i) >> 8) & 0xff;
68
69 putc(c, fp);
70 putc(c1, fp);
71 }
72
73 //---------------------------------------------------------
74
putint(FILE * fp,int i)75 void putint(FILE *fp, int i) {
76 int c = ((UINT)i) & 0xff, c1 = (((UINT)i) >> 8) & 0xff,
77 c2 = (((UINT)i) >> 16) & 0xff, c3 = (((UINT)i) >> 24) & 0xff;
78
79 putc(c, fp);
80 putc(c1, fp);
81 putc(c2, fp);
82 putc(c3, fp);
83 }
84
85 //=========================================================
86
87 } // namespace
88
89 //=========================================================
90
91 class BmpReader final : public Tiio::Reader {
92 FILE *m_chan;
93 BMP_HEADER m_header;
94 char *m_line;
95 int m_lineSize;
96 std::unique_ptr<TPixel[]> m_cmap;
97 bool m_corrupted;
98 typedef int (BmpReader::*ReadLineMethod)(char *buffer, int x0, int x1,
99 int shrink);
100 ReadLineMethod m_readLineMethod;
101
102 public:
103 BmpReader();
104 ~BmpReader();
105
106 void open(FILE *file) override;
107
108 int readNoLine(char *buffer, int x0, int x1, int shrink);
109
skipBytes(int count)110 void skipBytes(int count) {
111 // fseek(m_chan, count, SEEK_CUR); //inefficiente se count è piccolo
112 for (int i = 0; i < count; i++) {
113 getc(m_chan);
114 }
115 }
116
117 int read1Line(char *buffer, int x0, int x1, int shrink);
118 int read4Line(char *buffer, int x0, int x1, int shrink);
119 int read8Line(char *buffer, int x0, int x1, int shrink);
120 int read8LineRle(char *buffer, int x0, int x1, int shrink);
121 int read16m555Line(char *buffer, int x0, int x1, int shrink);
122 int read16m565Line(char *buffer, int x0, int x1, int shrink);
123 int read24Line(char *buffer, int x0, int x1, int shrink);
124 int read32Line(char *buffer, int x0, int x1, int shrink);
125
126 void readLine(char *buffer, int x0, int x1, int shrink) override;
skipLines(int lineCount)127 int skipLines(int lineCount) override {
128 fseek(m_chan, lineCount * m_lineSize, SEEK_CUR);
129 /* for(int i=0;i<lineCount;i++)
130 skipBytes(m_lineSize);*/
131 return lineCount;
132 }
133
134 private:
135 void readHeader();
136 };
137
138 //---------------------------------------------------------
139
BmpReader()140 BmpReader::BmpReader()
141 : m_chan(0), m_corrupted(false), m_readLineMethod(&BmpReader::readNoLine) {
142 memset(&m_header, 0, sizeof m_header);
143 }
144
145 //---------------------------------------------------------
146
~BmpReader()147 BmpReader::~BmpReader() {}
148
149 //---------------------------------------------------------
150
open(FILE * file)151 void BmpReader::open(FILE *file) {
152 m_chan = file;
153 readHeader();
154 }
155
156 //---------------------------------------------------------
157
readHeader()158 void BmpReader::readHeader() {
159 if (!m_chan) return;
160
161 fseek(m_chan, 0L, SEEK_END);
162 m_header.biFilesize = ftell(m_chan);
163 fseek(m_chan, 0L, 0);
164
165 /* read the file type (first two bytes) */
166 char signature[2];
167 signature[0] = fgetc(m_chan);
168 signature[1] = fgetc(m_chan);
169 if (signature[0] != 'B' || signature[1] != 'M') {
170 m_corrupted = true;
171 return;
172 }
173
174 m_header.bfSize = getint(m_chan);
175
176 /* reserved and ignored */
177 getshort(m_chan);
178 getshort(m_chan);
179
180 m_header.bfOffBits = getint(m_chan);
181 m_header.biSize = getint(m_chan);
182
183 if ((int)m_header.biSize == BMP_WIN_SIZE ||
184 (int)m_header.biSize == BMP_OS2_SIZE) {
185 m_header.biWidth = getint(m_chan);
186 m_header.biHeight = getint(m_chan);
187 m_header.biPlanes = getshort(m_chan);
188 m_header.biBitCount = getshort(m_chan);
189 m_header.biCompression = getint(m_chan);
190 m_header.biSizeImage = getint(m_chan);
191 m_header.biXPelsPerMeter = getint(m_chan);
192 m_header.biYPelsPerMeter = getint(m_chan);
193 m_header.biClrUsed = getint(m_chan);
194 m_header.biClrImportant = getint(m_chan);
195 } else // old bitmap format
196 {
197 m_header.biWidth = getshort(m_chan);
198 m_header.biHeight = getshort(m_chan);
199 m_header.biPlanes = getshort(m_chan);
200 m_header.biBitCount = getshort(m_chan);
201
202 /* Not in old versions so have to compute them */
203 m_header.biSizeImage =
204 (((m_header.biPlanes * m_header.biBitCount * m_header.biWidth) + 31) /
205 32) *
206 4 * m_header.biHeight;
207
208 m_header.biCompression = BMP_BI_RGB;
209 m_header.biXPelsPerMeter = 0;
210 m_header.biYPelsPerMeter = 0;
211 m_header.biClrUsed = 0;
212 m_header.biClrImportant = 0;
213 }
214 m_header.biPad = 0;
215
216 m_info.m_lx = m_header.biWidth;
217 m_info.m_ly = m_header.biHeight;
218
219 /*
220 BMP_HEADER *hd = m_header;
221 if ((int)hd->biSize != BMP_WIN_OS2_OLD)
222 {
223 // skip ahead to colormap, using biSize
224 int c = hd->biSize - 40; // 40 bytes read from biSize to biClrImportant
225 for (int i=0; i<c; i++) getc(m_chan);
226 hd->biPad = hd->bfOffBits - (hd->biSize + 14);
227 }
228 else
229 hd->biPad = 0;
230 */
231
232 // load up colormap, if any
233 if (m_header.biBitCount < 16) {
234 int cmaplen =
235 (m_header.biClrUsed) ? m_header.biClrUsed : 1 << m_header.biBitCount;
236 assert(cmaplen <= 256);
237 m_cmap.reset(new TPixel[256]);
238 TPixel32 *pix = m_cmap.get();
239 for (int i = 0; i < cmaplen; i++) {
240 pix->b = getc(m_chan);
241 pix->g = getc(m_chan);
242 pix->r = getc(m_chan);
243 pix->m = 255;
244 getc(m_chan);
245 ++pix;
246 }
247 }
248
249 /*
250 if (hd->biSize != BMP_WIN_OS2_OLD)
251 {
252 // Waste any unused bytes between the colour map (if present)
253 // and the start of the actual bitmap data.
254 while (hd->biPad > 0)
255 {
256 (void) getc(m_chan);
257 hd->biPad--;
258 }
259 }
260 */
261 // get information about the portion of the image to load
262 // get_info_region(&info, x1, y1, x2, y2, scale,
263 // (int)hd->biWidth, (int)hd->biHeight, TNZ_BOTLEFT);
264
265 // skip_bmp_lines(fp, hd->biWidth, (unsigned int)(info.startScanRow-1),
266 // (unsigned int)SEEK_CUR, subtype);
267
268 int lx = m_info.m_lx;
269
270 switch (m_header.biBitCount) {
271 case 1:
272 m_info.m_samplePerPixel = 1;
273 m_readLineMethod = &BmpReader::read1Line;
274 m_lineSize = (lx + 7) / 8;
275 break;
276 case 4:
277 m_info.m_samplePerPixel = 1;
278 if (m_header.biCompression == 0) m_readLineMethod = &BmpReader::read4Line;
279 m_lineSize = (lx + 1) / 2;
280 break;
281 case 8:
282 m_info.m_samplePerPixel = 1;
283 if (m_header.biCompression == 0)
284 m_readLineMethod = &BmpReader::read8Line;
285 else if (m_header.biCompression == 1)
286 m_readLineMethod = &BmpReader::read8LineRle;
287 m_lineSize = lx;
288 break;
289 case 16:
290 m_info.m_samplePerPixel = 3;
291 if (m_header.biCompression == 0) // BI_RGB
292 m_readLineMethod = &BmpReader::read16m555Line;
293 else if (m_header.biCompression == 3) // BI_BITFIELDS
294 {
295 unsigned int rmask = 0, gmask = 0, bmask = 0;
296 rmask = getint(m_chan);
297 gmask = getint(m_chan);
298 bmask = getint(m_chan);
299 if (gmask == 0x7E0)
300 m_readLineMethod = &BmpReader::read16m565Line;
301 else
302 m_readLineMethod = &BmpReader::read16m555Line;
303 }
304 m_lineSize = lx * 2;
305 break;
306 case 24:
307 m_info.m_samplePerPixel = 3;
308 m_readLineMethod = &BmpReader::read24Line;
309 m_lineSize = lx * 3;
310 break;
311 case 32:
312 m_info.m_samplePerPixel = 3;
313 m_readLineMethod = &BmpReader::read32Line;
314 m_lineSize = lx * 4;
315 break;
316 }
317 m_lineSize += 3 - ((m_lineSize + 3) & 3);
318 fseek(m_chan, m_header.bfOffBits, SEEK_SET);
319 }
320
321 //---------------------------------------------------------
322
readLine(char * buffer,int x0,int x1,int shrink)323 void BmpReader::readLine(char *buffer, int x0, int x1, int shrink) {
324 (this->*m_readLineMethod)(buffer, x0, x1, shrink);
325 }
326
327 //---------------------------------------------------------
328
readNoLine(char * buffer,int x0,int x1,int shrink)329 int BmpReader::readNoLine(char *buffer, int x0, int x1, int shrink) {
330 skipBytes(m_lineSize);
331 return 0;
332 }
333
334 //---------------------------------------------------------
335
read1Line(char * buffer,int x0,int x1,int shrink)336 int BmpReader::read1Line(char *buffer, int x0, int x1, int shrink) {
337 TPixel32 *pix = (TPixel32 *)buffer;
338
339 // pix += x0;
340 if (x0 > 0) skipBytes(x0 / 8);
341
342 TPixel32 *endPix = pix + x1 + 1;
343
344 int value = 0;
345 int index = x0;
346
347 if (x0 % 8 != 0) {
348 value = getc(m_chan);
349 for (index = x0; index < x0 + 8 - (x0 % 8); index += shrink) {
350 pix[index] = m_cmap[(value >> (7 - ((index) % 8))) & 1];
351 }
352 }
353 value = getc(m_chan);
354 int prevBlock = index / 8;
355 for (int j = index; pix + j < endPix; j += shrink) {
356 if (j / 8 > prevBlock) value = getc(m_chan);
357 prevBlock = j / 8;
358 pix[j] = m_cmap[(value >> (7 - (j % 8))) & 1];
359 }
360
361 /*
362 while(pix+8<=endPix)
363 {
364 value = getc(m_chan);
365 pix[0] = m_cmap[(value>>7)&1];
366 pix[1] = m_cmap[(value>>6)&1];
367 pix[2] = m_cmap[(value>>5)&1];
368 pix[3] = m_cmap[(value>>4)&1];
369 pix[4] = m_cmap[(value>>3)&1];
370 pix[5] = m_cmap[(value>>2)&1];
371 pix[6] = m_cmap[(value>>1)&1];
372 pix[7] = m_cmap[(value>>0)&1];
373 pix +=8*shrink;
374 if(shrink>1) value = getc(m_chan);
375 //pix+=8*shrink;
376 //if(pix+8<endPix && shrink>1) skipBytes(shrink-1);
377 }
378 if(pix<endPix)
379 {
380 value = getc(m_chan);
381 assert(pix+8>=endPix);
382 for(int j=0; pix+j<endPix; j++)
383 pix[j] = m_cmap[(value>>(7-j))&1];
384 } */
385 if ((m_info.m_lx - x1) / 8 > 0) {
386 skipBytes((m_info.m_lx - x1) / 8);
387 }
388
389 int bytes = (m_info.m_lx + 7) / 8;
390 if (m_lineSize - bytes > 0) skipBytes(m_lineSize - bytes);
391 return 0;
392 }
393
394 //---------------------------------------------------------
395
read4Line(char * buffer,int x0,int x1,int shrink)396 int BmpReader::read4Line(char *buffer, int x0, int x1, int shrink) {
397 TPixel32 *pix = (TPixel32 *)buffer;
398 pix += 2 * x0;
399 if (x0 > 0) skipBytes(x0 / 2);
400 TPixel32 *endPix = pix + x1 - x0 + 1;
401
402 int value;
403 while (pix + 2 <= endPix) {
404 value = getc(m_chan);
405 pix[0] = m_cmap[value & 0xF];
406 pix[1] = m_cmap[(value >> 4) & 0xF];
407 // pix+=2*shrink;
408 pix++;
409 // if(pix+2<=endPix && shrink>1) skipBytes(shrink-1);
410 }
411 if (pix < endPix) {
412 value = getc(m_chan);
413 pix[0] = m_cmap[value & 0xF];
414 }
415 if ((m_info.m_lx - x1) / 2 > 0) {
416 skipBytes((m_info.m_lx - x1) / 2);
417 }
418
419 int bytes = (m_info.m_lx + 1) / 2;
420 if (m_lineSize - bytes) skipBytes(m_lineSize - bytes);
421 return 0;
422 }
423
424 //---------------------------------------------------------
425
read8Line(char * buffer,int x0,int x1,int shrink)426 int BmpReader::read8Line(char *buffer, int x0, int x1, int shrink) {
427 TPixel32 *pix = (TPixel32 *)buffer;
428
429 if (x0 > 0) skipBytes(x0);
430 pix += x0;
431 TPixel32 *endPix = pix + x1 - x0 + 1;
432
433 while (pix < endPix) {
434 int value = getc(m_chan);
435 *pix++ = m_cmap[value];
436 if (pix < endPix && shrink > 1) {
437 skipBytes(shrink - 1);
438 pix += (shrink - 1);
439 }
440 }
441
442 if (m_info.m_lx - x1 - 1 > 0) {
443 skipBytes(m_info.m_lx - x1 - 1);
444 }
445
446 if (m_lineSize - m_info.m_lx > 0) skipBytes(m_lineSize - m_info.m_lx);
447 return 0;
448 }
449
450 //---------------------------------------------------------
451
read8LineRle(char * buffer,int x0,int x1,int shrink)452 int BmpReader::read8LineRle(char *buffer, int x0, int x1, int shrink) {
453 TPixel32 *pix = (TPixel32 *)buffer;
454 if (x0 > 0) skipBytes(x0);
455 pix += x0;
456 TPixel32 *endPix = pix + (x1 - x0 + 1);
457
458 while (pix < endPix) {
459 int i, count = getc(m_chan);
460 assert(count >= 0);
461 if (count == 0) {
462 int pixels = getc(m_chan);
463
464 assert(pixels >= 0 && pixels != 2);
465 if (pixels < 3) return 0;
466 for (i = 0; i < pixels; i++) *pix++ = m_cmap[getc(m_chan)];
467 if ((1 + 1 + pixels) & 0x1) getc(m_chan);
468 } else {
469 int value = getc(m_chan);
470 assert(value >= 0);
471 for (i = 0; i < count; i++) *pix++ = m_cmap[value];
472 }
473 if (pix < endPix && shrink > 1) {
474 skipBytes(shrink - 1);
475 pix += (shrink - 1);
476 }
477 }
478
479 if (m_info.m_lx - x1 - 1 > 0) {
480 skipBytes(m_info.m_lx - x1 - 1);
481 }
482
483 if (m_lineSize - m_info.m_lx > 0) skipBytes(m_lineSize - m_info.m_lx);
484 int val = getc(m_chan);
485 assert(val == 0); // end scanline or end bmp
486 val = getc(m_chan);
487 assert(val == 0 || val == 1);
488 return 0;
489 }
490
491 //---------------------------------------------------------
492
read16m555Line(char * buffer,int x0,int x1,int shrink)493 int BmpReader::read16m555Line(char *buffer, int x0, int x1, int shrink) {
494 TPixel32 *pix = (TPixel32 *)buffer;
495 if (x0 > 0) skipBytes(2 * x0);
496 pix += x0;
497 TPixel32 *endPix = pix + x1 - x0 + 1;
498
499 while (pix < endPix) {
500 int v = getshort(m_chan);
501 int r = (v >> 10) & 0x1F;
502 int g = (v >> 5) & 0x1F;
503 int b = v & 0x1F;
504 pix->r = r << 3 | r >> 2;
505 pix->g = g << 3 | g >> 2;
506 pix->b = b << 3 | b >> 2;
507 pix->m = 255;
508 pix += shrink;
509 if (pix < endPix && shrink > 1) skipBytes(2 * (shrink - 1));
510 }
511 if (m_info.m_lx - x1 - 1 > 0) skipBytes(2 * (m_info.m_lx - x1 - 1));
512
513 if (m_lineSize - 2 * m_info.m_lx > 0) skipBytes(m_lineSize - 2 * m_info.m_lx);
514 return 0;
515 }
516
517 //---------------------------------------------------------
518
read16m565Line(char * buffer,int x0,int x1,int shrink)519 int BmpReader::read16m565Line(char *buffer, int x0, int x1, int shrink) {
520 TPixel32 *pix = (TPixel32 *)buffer;
521 if (x0 > 0) skipBytes(2 * x0);
522 pix += x0;
523 TPixel32 *endPix = pix + x1 - x0 + 1;
524
525 while (pix < endPix) {
526 int v = getshort(m_chan);
527 int r = (v >> 11) & 0x1F;
528 int g = (v >> 5) & 0x3F;
529 int b = v & 0x1F;
530 pix->r = r << 3 | r >> 2;
531 pix->g = g << 2 | g >> 4;
532 pix->b = b << 3 | b >> 2;
533 pix->m = 255;
534 pix += shrink;
535 if (pix < endPix && shrink > 1) skipBytes(2 * (shrink - 1));
536 }
537 if (m_info.m_lx - x1 - 1 > 0) skipBytes(2 * (m_info.m_lx - x1 - 1));
538
539 if (m_lineSize - 2 * m_info.m_lx > 0) skipBytes(m_lineSize - 2 * m_info.m_lx);
540 return 0;
541 }
542 //---------------------------------------------------------
543
read24Line(char * buffer,int x0,int x1,int shrink)544 int BmpReader::read24Line(char *buffer, int x0, int x1, int shrink) {
545 TPixel32 *pix = (TPixel32 *)buffer;
546 if (x0 > 0) skipBytes(3 * x0);
547 pix += x0;
548 TPixel32 *endPix = pix + x1 - x0 + 1;
549
550 while (pix < endPix) {
551 pix->b = getc(m_chan);
552 pix->g = getc(m_chan);
553 pix->r = getc(m_chan);
554 pix->m = 255;
555 pix += shrink;
556 if (pix < endPix && shrink > 1) skipBytes(3 * (shrink - 1));
557 }
558 if (m_info.m_lx - x1 - 1 > 0) skipBytes(3 * (m_info.m_lx - x1 - 1));
559
560 if (m_lineSize - 3 * m_info.m_lx > 0) skipBytes(m_lineSize - 3 * m_info.m_lx);
561 return 0;
562 }
563
564 //---------------------------------------------------------
565
read32Line(char * buffer,int x0,int x1,int shrink)566 int BmpReader::read32Line(char *buffer, int x0, int x1, int shrink) {
567 TPixel32 *pix = (TPixel32 *)buffer;
568 if (x0 > 0) skipBytes(4 * x0);
569 pix += x0;
570 TPixel32 *endPix = pix + x1 - x0 + 1;
571
572 while (pix < endPix) {
573 pix->b = getc(m_chan);
574 pix->g = getc(m_chan);
575 pix->r = getc(m_chan);
576 pix->m = getc(m_chan);
577 pix += shrink;
578 if (pix < endPix && shrink > 1) skipBytes(4 * (shrink - 1));
579 }
580 if (m_info.m_lx - x1 - 1 > 0) skipBytes(4 * (m_info.m_lx - x1 - 1));
581 if (m_lineSize - 4 * m_info.m_lx > 0) skipBytes(m_lineSize - 4 * m_info.m_lx);
582 return 0;
583 }
584
585 //=========================================================
586
587 class BmpWriter final : public Tiio::Writer {
588 FILE *m_chan;
589 int m_bitPerPixel;
590 int m_compression;
591
592 public:
593 BmpWriter();
594 ~BmpWriter();
595
596 void open(FILE *file, const TImageInfo &info) override;
597
flush()598 void flush() override { fflush(m_chan); }
599
600 void writeLine(char *buffer) override;
601
602 // for now opentoonz does not support bmp format with alpha channel
writeAlphaSupported() const603 bool writeAlphaSupported() const override { return false; }
604 };
605
606 //---------------------------------------------------------
607
BmpWriter()608 BmpWriter::BmpWriter() : m_chan(0) {}
609
610 //---------------------------------------------------------
611
~BmpWriter()612 BmpWriter::~BmpWriter() { delete m_properties; }
613
614 //---------------------------------------------------------
615
open(FILE * file,const TImageInfo & info)616 void BmpWriter::open(FILE *file, const TImageInfo &info) {
617 m_chan = file;
618
619 m_info = info;
620 int lx = m_info.m_lx;
621 int ly = m_info.m_ly;
622
623 if (!m_properties) m_properties = new Tiio::BmpWriterProperties();
624
625 TEnumProperty *p =
626 (TEnumProperty *)(m_properties->getProperty("Bits Per Pixel"));
627 assert(p);
628 std::string str = ::to_string(p->getValue());
629 m_bitPerPixel = atoi(str.c_str());
630
631 int cmapSize = 0;
632 std::vector<TPixel> *colormap = 0;
633
634 if (m_bitPerPixel == 8) {
635 TPointerProperty *colormapProp =
636 (TPointerProperty *)(m_properties->getProperty("Colormap"));
637 if (colormapProp) {
638 colormap = (std::vector<TPixel> *)colormapProp->getValue();
639 cmapSize = colormap->size();
640 } else
641 cmapSize = 256;
642 }
643
644 assert(m_bitPerPixel == 8 || m_bitPerPixel == 24);
645
646 int bytePerLine =
647 ((lx * m_bitPerPixel + 31) / 32) * (m_bitPerPixel == 8 ? 1 : 4);
648
649 int fileSize = 14 // file header
650 + 40 // info header
651 + cmapSize * 4 // colormap size
652 + bytePerLine * ly // image size
653 ;
654 int offset = 14 + 40 + cmapSize * 4;
655 int compression = 0;
656 int imageSize = bytePerLine * ly;
657
658 putc('B', m_chan);
659 putc('M', m_chan); // BMP file magic number
660
661 putint(m_chan, fileSize);
662 putshort(m_chan, 0); // reserved1
663 putshort(m_chan, 0); // reserved2
664
665 putint(m_chan, offset); // offset from BOfile to BObitmap
666
667 putint(m_chan, 40); // size of bitmap info header
668 putint(m_chan, m_info.m_lx); // width
669 putint(m_chan, m_info.m_ly); // height
670 putshort(m_chan, 1); // must be '1'
671 putshort(m_chan, m_bitPerPixel); // 1,4,8, or 24
672 putint(m_chan, compression); // BMP_BI_RGB, BMP_BI_RLE8 or BMP_BI_RLE4
673 putint(m_chan, imageSize); // size of raw image data
674 putint(m_chan, 0); // dpi * 39" per meter
675 putint(m_chan, 0); // dpi * 39" per meter
676 putint(m_chan, cmapSize); // colors used in cmap
677 putint(m_chan, 0); // same as above
678
679 if (colormap)
680 for (int i = 0; i < (int)colormap->size(); i++) {
681 putc((*colormap)[i].b, m_chan);
682 putc((*colormap)[i].g, m_chan);
683 putc((*colormap)[i].r, m_chan);
684 putc(0, m_chan);
685 }
686 else
687 for (int i = 0; i < cmapSize; i++) // palette!!
688 {
689 putc(i, m_chan);
690 putc(i, m_chan);
691 putc(i, m_chan);
692 putc(0, m_chan);
693 }
694 }
695
696 //---------------------------------------------------------
697
writeLine(char * buffer)698 void BmpWriter::writeLine(char *buffer) {
699 int lx = m_info.m_lx;
700
701 int j;
702
703 switch (m_bitPerPixel) {
704 case 24: {
705 TPixel32 *pix = (TPixel32 *)buffer;
706 for (j = 0; j < lx; j++) {
707 putc(pix->b, m_chan);
708 putc(pix->g, m_chan);
709 putc(pix->r, m_chan);
710 ++pix;
711 }
712 int bytes = lx * 3;
713 while (bytes & 3) {
714 putc(0, m_chan);
715 bytes++;
716 }
717 break;
718 }
719 case 8: {
720 TPixelGR8 *pix = (TPixelGR8 *)buffer;
721 for (j = 0; j < lx; j++) {
722 putc(pix->value, m_chan);
723 ++pix;
724 }
725 while (lx & 3) {
726 putc(0, m_chan);
727 lx++;
728 }
729 break;
730 }
731 default:
732 assert(false);
733 }
734 ftell(m_chan);
735 }
736
737 //=========================================================
738
makeBmpReader()739 Tiio::Reader *Tiio::makeBmpReader() { return new BmpReader(); }
740
741 //=========================================================
742
makeBmpWriter()743 Tiio::Writer *Tiio::makeBmpWriter() { return new BmpWriter(); }
744
745 //=========================================================
746
BmpWriterProperties()747 Tiio::BmpWriterProperties::BmpWriterProperties()
748 : m_pixelSize("Bits Per Pixel") {
749 m_pixelSize.addValue(L"24 bits");
750 m_pixelSize.addValue(L"8 bits (Greyscale)");
751 bind(m_pixelSize);
752 }
753
updateTranslation()754 void Tiio::BmpWriterProperties::updateTranslation() {
755 m_pixelSize.setQStringName(tr("Bits Per Pixel"));
756 m_pixelSize.setItemUIName(L"24 bits", tr("24 bits"));
757 m_pixelSize.setItemUIName(L"8 bits (Greyscale)", tr("8 bits (Greyscale)"));
758 }
759