source: nanovis/trunk/BMPWriter.cpp @ 4897

Last change on this file since 4897 was 3914, checked in by ldelgass, 6 years ago

Fix for build without USE_THREADS

  • Property svn:eol-style set to native
File size: 9.7 KB
Line 
1/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2/*
3 * Copyright (c) 2004-2013  HUBzero Foundation, LLC
4 *
5 * Authors:
6 *   Wei Qiao <qiaow@purdue.edu>
7 *   Insoo Woo <iwoo@purdue.edu>
8 *   George A. Howlett <gah@purdue.edu>
9 */
10
11#ifndef USE_THREADS
12#include <unistd.h>
13#endif
14#include <cstdlib>
15#include <cstring>
16#include <cstdio>
17
18#include "nanovis.h"
19#include "BMPWriter.h"
20#ifdef USE_THREADS
21#include "ResponseQueue.h"
22#endif
23#include "Trace.h"
24
25using namespace nv;
26
27// used internally to build up the BMP file header
28// Writes an integer value into the header data structure at pos
29static inline void
30bmpHeaderAddInt(unsigned char* header, int& pos, int data)
31{
32#ifdef WORDS_BIGENDIAN
33    header[pos++] = (data >> 24) & 0xFF;
34    header[pos++] = (data >> 16) & 0xFF;
35    header[pos++] = (data >> 8)  & 0xFF;
36    header[pos++] = (data)       & 0xFF;
37#else
38    header[pos++] = data & 0xff;
39    header[pos++] = (data >> 8) & 0xff;
40    header[pos++] = (data >> 16) & 0xff;
41    header[pos++] = (data >> 24) & 0xff;
42#endif
43}
44
45/**
46 * \brief Write image data to a bitmap (BMP) file
47 *
48 * Note that this function assumes the imgData has 4 byte aligned
49 * rows (bottom to top) of RGB pixel data.
50 */
51bool
52nv::writeBMPFile(int frameNumber, const char *directoryName,
53                 unsigned char *imgData, int width, int height)
54{
55    unsigned char header[SIZEOF_BMP_HEADER];
56
57    // BE CAREFUL:  BMP files must have an even multiple of 4 bytes
58    // on each scan line.  If need be, we add padding to each line.
59    int pad = 0;
60    if ((3 * width) % 4 > 0) {
61        pad = 4 - ((3 * width) % 4);
62    }
63
64    size_t headerLength = SIZEOF_BMP_HEADER;
65    size_t pixelBytes = (3 * width + pad) * height;
66    int fsize = headerLength + pixelBytes;
67
68    // Prepare header
69    int pos = 0;
70    header[pos++] = 'B';
71    header[pos++] = 'M';
72
73    // file size in bytes
74    bmpHeaderAddInt(header, pos, fsize);
75
76    // reserved value (must be 0)
77    bmpHeaderAddInt(header, pos, 0);
78
79    // offset in bytes to start of bitmap data
80    bmpHeaderAddInt(header, pos, headerLength);
81
82    // size of the BITMAPINFOHEADER
83    bmpHeaderAddInt(header, pos, 40);
84
85    // width of the image in pixels
86    bmpHeaderAddInt(header, pos, width);
87
88    // height of the image in pixels
89    bmpHeaderAddInt(header, pos, height);
90
91    // 1 plane + (24 bits/pixel << 16)
92    bmpHeaderAddInt(header, pos, 1572865);
93
94    // no compression
95    // size of image for compression
96    bmpHeaderAddInt(header, pos, 0);
97    bmpHeaderAddInt(header, pos, 0);
98
99    // x pixels per meter
100    // y pixels per meter
101    bmpHeaderAddInt(header, pos, 0);
102    bmpHeaderAddInt(header, pos, 0);
103
104    // number of colors used (0 = compute from bits/pixel)
105    // number of important colors (0 = all colors important)
106    bmpHeaderAddInt(header, pos, 0);
107    bmpHeaderAddInt(header, pos, 0);
108
109    // BE CAREFUL: BMP format wants BGR ordering for screen data
110    unsigned char *scr = imgData;
111    for (int row = 0; row < height; row++) {
112        for (int col = 0; col < width; col++) {
113            unsigned char tmp = scr[2];
114            scr[2] = scr[0];  // B
115            scr[0] = tmp;     // R
116            scr += 3;
117        }
118        scr += pad;  // skip over padding already in screen data
119    }
120
121    bool ret = true;
122    FILE *filp;
123    char filename[100];
124    if (frameNumber >= 0) {
125        if (directoryName)
126            sprintf(filename, "%s/image%03d.bmp", directoryName, frameNumber);
127        else
128            sprintf(filename, "/tmp/flow_animation/image%03d.bmp", frameNumber);
129
130        TRACE("Writing %s", filename);
131        filp = fopen(filename, "wb");
132        if (filp == NULL) {
133            ERROR("cannot create file");
134            ret = false;
135        }
136    } else {
137        filp = fopen("/tmp/image.bmp", "wb");
138        if (filp == NULL) {
139            ERROR("cannot create file");
140            ret = false;
141        }
142    }
143    if (fwrite(header, headerLength, 1, filp) != 1) {
144        ERROR("can't write header: short write");
145        ret = false;
146    }
147    if (fwrite(imgData, pixelBytes, 1, filp) != 1) {
148        ERROR("can't write data: short write");
149        ret = false;
150    }
151    fclose(filp);
152    return ret;
153}
154
155#ifdef USE_THREADS
156
157/**
158 * \brief Write image data to a bitmap (BMP) stream
159 *
160 * Note that this function assumes the imgData has 4 byte aligned
161 * rows (bottom to top) of RGB pixel data.
162 */
163void
164nv::queueBMP(ResponseQueue *queue, const char *cmdName,
165             unsigned char *imgData, int width, int height)
166{
167    unsigned char header[SIZEOF_BMP_HEADER];
168
169    // BE CAREFUL:  BMP files must have an even multiple of 4 bytes
170    // on each scan line.  If need be, we add padding to each line.
171    int pad = 0;
172    if ((3 * width) % 4 > 0) {
173        pad = 4 - ((3 * width) % 4);
174    }
175
176    size_t headerLength = SIZEOF_BMP_HEADER;
177    size_t pixelBytes = (3 * width + pad) * height;
178    int fsize = headerLength + pixelBytes;
179
180    // Prepare header
181    int pos = 0;
182    header[pos++] = 'B';
183    header[pos++] = 'M';
184
185    // file size in bytes
186    bmpHeaderAddInt(header, pos, fsize);
187
188    // reserved value (must be 0)
189    bmpHeaderAddInt(header, pos, 0);
190
191    // offset in bytes to start of bitmap data
192    bmpHeaderAddInt(header, pos, headerLength);
193
194    // size of the BITMAPINFOHEADER
195    bmpHeaderAddInt(header, pos, 40);
196
197    // width of the image in pixels
198    bmpHeaderAddInt(header, pos, width);
199
200    // height of the image in pixels
201    bmpHeaderAddInt(header, pos, height);
202    // 1 plane + (24 bits/pixel << 16)
203    bmpHeaderAddInt(header, pos, 1572865);
204
205    // no compression
206    // size of image for compression
207    bmpHeaderAddInt(header, pos, 0);
208    bmpHeaderAddInt(header, pos, 0);
209
210    // x pixels per meter
211    // y pixels per meter
212    bmpHeaderAddInt(header, pos, 0);
213    bmpHeaderAddInt(header, pos, 0);
214
215    // number of colors used (0 = compute from bits/pixel)
216    // number of important colors (0 = all colors important)
217    bmpHeaderAddInt(header, pos, 0);
218    bmpHeaderAddInt(header, pos, 0);
219
220    char command[200];
221    sprintf(command, "%s %lu\n", cmdName,
222            (unsigned long)headerLength + pixelBytes);
223
224    size_t cmdLength;
225    cmdLength = strlen(command);
226
227    size_t length = cmdLength + headerLength + pixelBytes;
228    unsigned char *mesg = (unsigned char *)malloc(length);
229    if (mesg == NULL) {
230        ERROR("can't allocate %ld bytes for the image message", length);
231        return;
232    }
233    memcpy(mesg, command, cmdLength);
234    memcpy(mesg + cmdLength, header, headerLength);
235
236    // BE CAREFUL: BMP format wants BGR ordering for screen data
237    unsigned char *scr = imgData;
238    for (int row = 0; row < height; row++) {
239        for (int col = 0; col < width; col++) {
240            unsigned char tmp = scr[2];
241            scr[2] = scr[0];  // B
242            scr[0] = tmp;     // R
243            scr += 3;
244        }
245        scr += pad;  // skip over padding already in screen data
246    }
247
248    memcpy(mesg + cmdLength + headerLength, imgData, pixelBytes);
249
250    Response *response;
251    if (strncmp(cmdName, "nv>legend", 9) == 0) {
252        response = new Response(Response::LEGEND);
253    } else {
254        response = new Response(Response::IMAGE);
255    }
256    response->setMessage(mesg, length, Response::DYNAMIC);
257    queue->enqueue(response);
258}
259#else
260/**
261 * \brief Write image data to a bitmap (BMP) stream
262 *
263 * Note that this function assumes the imgData has 4 byte aligned
264 * rows (bottom to top) of RGB pixel data.
265 */
266void
267nv::writeBMP(int fd, const char *prefix,
268             unsigned char *imgData, int width, int height)
269{
270    unsigned char header[SIZEOF_BMP_HEADER];
271
272    // BE CAREFUL:  BMP files must have an even multiple of 4 bytes
273    // on each scan line.  If need be, we add padding to each line.
274    int pad = 0;
275    if ((3 * width) % 4 > 0) {
276        pad = 4 - ((3 * width) % 4);
277    }
278
279    size_t headerLength = SIZEOF_BMP_HEADER;
280    size_t pixelBytes = (3 * width + pad) * height;
281    int fsize = headerLength + pixelBytes;
282
283    char command[200];
284    sprintf(command, "%s %d\n", prefix, fsize);
285    if (write(fd, command, strlen(command)) != (ssize_t)strlen(command)) {
286        ERROR("Short write");
287        return;
288    }
289
290    // Prepare header
291    int pos = 0;
292    header[pos++] = 'B';
293    header[pos++] = 'M';
294
295    // file size in bytes
296    bmpHeaderAddInt(header, pos, fsize);
297
298    // reserved value (must be 0)
299    bmpHeaderAddInt(header, pos, 0);
300
301    // offset in bytes to start of bitmap data
302    bmpHeaderAddInt(header, pos, headerLength);
303
304    // size of the BITMAPINFOHEADER
305    bmpHeaderAddInt(header, pos, 40);
306
307    // width of the image in pixels
308    bmpHeaderAddInt(header, pos, width);
309
310    // height of the image in pixels
311    bmpHeaderAddInt(header, pos, height);
312
313    // 1 plane + (24 bits/pixel << 16)
314    bmpHeaderAddInt(header, pos, 1572865);
315
316    // no compression
317    // size of image for compression
318    bmpHeaderAddInt(header, pos, 0);
319    bmpHeaderAddInt(header, pos, 0);
320
321    // x pixels per meter
322    // y pixels per meter
323    bmpHeaderAddInt(header, pos, 0);
324    bmpHeaderAddInt(header, pos, 0);
325
326    // number of colors used (0 = compute from bits/pixel)
327    // number of important colors (0 = all colors important)
328    bmpHeaderAddInt(header, pos, 0);
329    bmpHeaderAddInt(header, pos, 0);
330
331    // BE CAREFUL: BMP format wants BGR ordering for screen data
332    unsigned char *scr = imgData;
333    for (int row = 0; row < height; row++) {
334        for (int col = 0; col < width; col++) {
335            unsigned char tmp = scr[2];
336            scr[2] = scr[0];  // B
337            scr[0] = tmp;     // R
338            scr += 3;
339        }
340        scr += pad;  // skip over padding already in screen data
341    }
342
343    if (write(fd, header, headerLength) != (ssize_t)headerLength) {
344        ERROR("Short write");
345        return;
346    }
347    if (write(fd, imgData, pixelBytes) != (ssize_t)pixelBytes) {
348        ERROR("Short write");
349        return;
350    }
351}
352#endif
Note: See TracBrowser for help on using the repository browser.