source: branches/blt4/packages/vizservers/vtkvis/PPMWriter.cpp @ 2542

Last change on this file since 2542 was 2542, checked in by gah, 13 years ago

update from trunk

File size: 4.9 KB
Line 
1/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2/*
3 * Copyright (C) 2011, Purdue Research Foundation
4 *
5 * Author: George A. Howlett <gah@purdue.edu>
6 */
7
8#include <cstdio>
9#include <cstdlib>
10#include <cstring>
11#include <cerrno>
12#include <sys/uio.h>
13
14#include "Trace.h"
15#include "PPMWriter.h"
16#ifdef USE_THREADS
17#include "ResponseQueue.h"
18#endif
19
20using namespace Rappture::VtkVis;
21
22#ifdef USE_THREADS
23
24/**
25 * \brief Writes image data as PPM binary data to the client.
26 *
27 * The PPM binary format is very simple.
28 *
29 *     P6 w h 255\n
30 *     3-byte RGB pixel data.
31 *
32 * The client (using the TkImg library) will do less work to unpack this
33 * format, as opposed to BMP or PNG.
34 *
35 * Note that currently the image data has bottom to top scanlines.  This
36 * routine could be made even simpler (faster) if the image data had top
37 * to bottom scanlines.
38 *
39 * \param[in] queue Pointer to ResponseQueue to write to
40 * \param[in] cmdName Command name to send (byte length will be appended)
41 * \param[in] data Image data
42 * \param[in] width Width of image in pixels
43 * \param[in] height Height of image in pixels
44 */
45void
46Rappture::VtkVis::queuePPM(ResponseQueue *queue, const char *cmdName,
47                           const unsigned char *data, int width, int height)
48{
49#define PPM_MAXVAL 255
50    char header[200];
51
52    TRACE("Entering (%dx%d)\n", width, height);
53    // Generate the PPM binary file header
54    snprintf(header, sizeof(header), "P6 %d %d %d\n", width, height,
55             PPM_MAXVAL);
56
57    size_t headerLength = strlen(header);
58    size_t dataLength = width * height * 3;
59
60    char command[200];
61    snprintf(command, sizeof(command), "%s %lu\n", cmdName,
62             (unsigned long)headerLength + dataLength);
63
64    size_t cmdLength;
65    cmdLength = strlen(command);
66
67    size_t length;
68    unsigned char *mesg;
69
70    length = headerLength + dataLength + cmdLength;
71    mesg = (unsigned char *)malloc(length);
72    if (mesg == NULL) {
73        ERROR("can't allocate %ld bytes for the image message", length);
74        return;
75    }
76    memcpy(mesg, command, cmdLength);
77    memcpy(mesg + cmdLength, header, headerLength);
78
79    size_t bytesPerRow = width * 3;
80    unsigned char *destRowPtr = mesg + length - bytesPerRow;
81    int y;
82    unsigned char *srcRowPtr = const_cast<unsigned char *>(data);
83    for (y = 0; y < height; y++) {
84        memcpy(destRowPtr, srcRowPtr, bytesPerRow);
85        srcRowPtr += bytesPerRow;
86        destRowPtr -= bytesPerRow;
87    }
88
89    Response *response;
90    if (strncmp(cmdName, "nv>legend", 9) == 0) {
91        response = new Response(Response::LEGEND);
92    } else {
93        response = new Response(Response::IMAGE);
94    }
95    response->setMessage(mesg, length, Response::DYNAMIC);
96    queue->enqueue(response);
97    TRACE("Leaving (%dx%d)\n", width, height);
98}
99#else
100
101/**
102 * \brief Writes image data as PPM binary data to the client.
103 *
104 * The PPM binary format is very simple.
105 *
106 *     P6 w h 255\n
107 *     3-byte RGB pixel data.
108 *
109 * The client (using the TkImg library) will do less work to unpack this
110 * format, as opposed to BMP or PNG.
111 *
112 * Note that currently the image data has bottom to top scanlines.  This
113 * routine could be made even simpler (faster) if the image data had top
114 * to bottom scanlines.
115 *
116 * \param[in] fd File descriptor that will be written to
117 * \param[in] cmdName Command name to send (byte length will be appended)
118 * \param[in] data Image data
119 * \param[in] width Width of image in pixels
120 * \param[in] height Height of image in pixels
121 */
122void
123Rappture::VtkVis::writePPM(int fd, const char *cmdName,
124                           const unsigned char *data, int width, int height)
125{
126#define PPM_MAXVAL 255
127    char header[200];
128
129    TRACE("Entering (%dx%d)\n", width, height);
130    // Generate the PPM binary file header
131    snprintf(header, sizeof(header), "P6 %d %d %d\n", width, height,
132             PPM_MAXVAL);
133
134    size_t headerLength = strlen(header);
135    size_t dataLength = width * height * 3;
136
137    char command[200];
138    snprintf(command, sizeof(command), "%s %lu\n", cmdName,
139             (unsigned long)headerLength + dataLength);
140
141    size_t nRecs = height + 2;
142
143    struct iovec *iov;
144    iov = (struct iovec *)malloc(sizeof(struct iovec) * nRecs);
145
146    // Write the command, then the image header and data.
147    // Command
148    iov[0].iov_base = command;
149    iov[0].iov_len = strlen(command);
150    // Header of image data
151    iov[1].iov_base = header;
152    iov[1].iov_len = headerLength;
153
154    // Image data
155    size_t bytesPerRow = width * 3;
156    int y;
157    unsigned char *srcRowPtr = const_cast<unsigned char *>(data);
158    for (y = height + 1; y >= 2; y--) {
159        iov[y].iov_base = srcRowPtr;
160        iov[y].iov_len = bytesPerRow;
161        srcRowPtr += bytesPerRow;
162    }
163    if (writev(fd, iov, nRecs) < 0) {
164        ERROR("write failed: %s\n", strerror(errno));
165    }
166    free(iov);
167
168    TRACE("Leaving (%dx%d)\n", width, height);
169}
170
171#endif /*USE_THREADS*/
Note: See TracBrowser for help on using the repository browser.