ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/abitmapio.cpp
Revision: 2.1
Committed: Wed Aug 14 20:05:23 2024 UTC (8 months, 2 weeks ago) by greg
Branch: MAIN
Log Message:
feat(rxpict): Added new C++ picture rendering tool with multi-processing and spectral output

File Contents

# Content
1 /*
2 * abitmapio.cpp
3 * panlib
4 *
5 * BitMap class file i/o using BMP format.
6 *
7 * Created by Greg Ward on 6/30/16.
8 * Copyright 2016 Anyhere Software. All rights reserved.
9 *
10 */
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include "abitmap.h"
16 #include "bmpfile.h"
17 #include "dmessage.h"
18
19 static const char BitMap1Dmagic[] = "1-D BitMap";
20 static const char BitMap2Dmagic[] = "2-D BitMap";
21
22 // Function to write a bitmap to a BMP file
23 bool
24 WriteBitMap(const ABitMap &bm, const char *fname)
25 {
26 if (!bm.Length() || fname == NULL || !*fname)
27 return false;
28 if (bm.Length() >= 1L<<31) {
29 DMESG(DMCparameter, "BitMap too long to write as one scanline");
30 return false;
31 }
32 BMPHeader * hdr = BMPmappedHeader(bm.Length(), 1, 16, 2);
33 if (hdr == NULL) {
34 DMESG(DMCparameter, "Cannot create BMP header");
35 return false;
36 }
37 strncpy(BMPinfo(hdr), BitMap1Dmagic, 16);
38
39 BMPWriter * wtr = BMPopenOutputFile(fname, hdr);
40 if (wtr == NULL) {
41 DMESGF(DMCresource, "Cannot open BMP output file '%s'", fname);
42 free(hdr);
43 return false;
44 }
45 DMESGF(DMCtrace, "Writing 1-D bitmap to '%s'", fname);
46
47 memset(wtr->scanline, 0, (bm.Length()+7)>>3);
48 for (uint32 i = 0; bm.Find(&i); i++)
49 wtr->scanline[i>>3] |= 128>>(i&7);
50
51 int rval = BMPwriteScanline(wtr);
52
53 BMPcloseOutput(wtr);
54
55 if (rval != BIR_OK) {
56 DMESG(DMCdata, BMPerrorMessage(rval));
57 return false;
58 }
59 return true;
60 }
61
62 // Function to write a 2-D bitmap to a BMP file
63 bool
64 WriteBitMap2(const ABitMap2 &bm2, const char *fname)
65 {
66 if (!bm2.Width() | !bm2.Height() || fname == NULL || !*fname)
67 return false;
68
69 BMPHeader * hdr = BMPmappedHeader(bm2.Width(), bm2.Height(), 16, 2);
70 if (hdr == NULL) {
71 DMESG(DMCparameter, "Cannot create BMP header");
72 return false;
73 }
74 strncpy(BMPinfo(hdr), BitMap2Dmagic, 16);
75 hdr->yIsDown = 1; // sane scanline ordering
76
77 BMPWriter * wtr = BMPopenOutputFile(fname, hdr);
78 if (wtr == NULL) {
79 DMESGF(DMCresource, "Cannot open BMP output file '%s'", fname);
80 free(hdr);
81 return false;
82 }
83 DMESGF(DMCtrace, "Writing 2-D bitmap to '%s'", fname);
84 int rval = BIR_OK;
85 int my = 0;
86 for (int y = 0; y < bm2.Height(); y++) {
87 memset(wtr->scanline, 0, (bm2.Width()+7)>>3);
88 while (y < my) { // write empty scanlines
89 if ((rval = BMPwriteScanline(wtr)) != BIR_OK)
90 break;
91 ++y;
92 }
93 if ((rval != BIR_OK) | (y >= bm2.Height()))
94 break;
95 for (int x = 0; bm2.Find(&x, &my) && my == y; x++)
96 wtr->scanline[x>>3] |= 128>>(x&7);
97
98 if ((rval = BMPwriteScanline(wtr)) != BIR_OK)
99 break;
100 }
101 BMPcloseOutput(wtr);
102
103 if (rval != BIR_OK) {
104 DMESG(DMCdata, BMPerrorMessage(rval));
105 return false;
106 }
107 return true;
108 }
109
110 // Function to read a bitmap from a BMP file
111 bool
112 ReadBitMap(ABitMap *bmp, const char *fname)
113 {
114 if (bmp == NULL || fname == NULL || !*fname)
115 return false;
116 // open call reads 1st scanline
117 BMPReader * rdr = BMPopenInputFile(fname);
118
119 if (rdr == NULL) {
120 DMESGF(DMCresource, "Cannot open BMP input file '%s'", fname);
121 return false;
122 }
123 if (rdr->hdr->nColors > 2) {
124 DMESGF(DMCdata, "BMP input file '%s' is not a bitmap", fname);
125 BMPcloseInput(rdr);
126 return false;
127 }
128 if (rdr->hdr->height != 1) {
129 DMESGF(DMCdata, "BMP input file '%s' has more than one scan line", fname);
130 BMPcloseInput(rdr);
131 return false;
132 }
133 if (rdr->hdr->infoSiz <= 0 ||
134 strncmp(BMPinfo(rdr->hdr), BitMap1Dmagic, rdr->hdr->infoSiz))
135 DMESGF(DMCwarning, "BMP file '%s' not flagged as 1-D bitmap", fname);
136
137 DASSERT(rdr->yscan == 0);
138 DMESGF(DMCtrace, "Reading 1-D bitmap from '%s'", fname);
139 bmp->NewBitMap(rdr->hdr->width);
140 for (uint32 i = rdr->hdr->width; i--; )
141 if (rdr->scanline[i>>3] & 128>>(i&7))
142 bmp->Set(i);
143 if (rdr->hdr->palette[0].g >= 128)
144 bmp->Invert(); // against normal convention!
145 BMPcloseInput(rdr);
146 return true;
147 }
148
149 // Function to read a 2-D bitmap from a BMP file
150 bool
151 ReadBitMap2(ABitMap2 *bm2p, const char *fname)
152 {
153 if (bm2p == NULL || fname == NULL || !*fname)
154 return false;
155
156 BMPReader * rdr = BMPopenInputFile(fname);
157
158 if (rdr == NULL) {
159 DMESGF(DMCresource, "Cannot open BMP input file '%s'", fname);
160 return false;
161 }
162 if (rdr->hdr->nColors > 2) {
163 DMESGF(DMCdata, "BMP input file '%s' is not a bitmap", fname);
164 BMPcloseInput(rdr);
165 return false;
166 }
167 if (rdr->hdr->infoSiz <= 0 ||
168 strncmp(BMPinfo(rdr->hdr), BitMap2Dmagic, rdr->hdr->infoSiz))
169 DMESGF(DMCwarning, "BMP file '%s' not flagged as 2-D bitmap", fname);
170
171 int y, rval = BIR_OK;
172 bm2p->NewBitMap(rdr->hdr->width, rdr->hdr->height);
173 DMESGF(DMCtrace, "Reading 2-D bitmap from '%s'", fname);
174 for (y = 0; y < rdr->hdr->height; y++) {
175 const int my = rdr->hdr->yIsDown ? y
176 : rdr->hdr->height-1 - y;
177 while (rdr->yscan < y && (rval = BMPreadScanline(rdr)) == BIR_OK)
178 ;
179 if (rval != BIR_OK)
180 break;
181 for (uint32 x = rdr->hdr->width; x--; )
182 if (rdr->scanline[x>>3] & 128>>(x&7))
183 bm2p->Set(x, my);
184 }
185 if (rval == BIR_OK && rdr->hdr->palette[0].g >= 128)
186 bm2p->Invert(); // against normal convention!
187 BMPcloseInput(rdr);
188
189 if (rval != BIR_OK) {
190 bm2p->NewBitMap(0,0);
191 sprintf(dmessage_buf, "%s at y==%d", BMPerrorMessage(rval), y);
192 DMESG(DMCdata, dmessage_buf);
193 return false;
194 }
195 return true;
196 }