wiretap 0.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +2 -1
- data/ext/Makefile +27 -24
- data/ext/audio_format.cpp +10 -8
- data/ext/charstream.h +41 -0
- data/ext/extconf.rb +8 -10
- data/ext/frame_io.cpp +120 -0
- data/ext/frame_io.h +45 -0
- data/ext/image_format.cpp +49 -169
- data/ext/image_io.cpp +466 -0
- data/ext/image_io.h +73 -0
- data/ext/node.cpp +71 -48
- data/ext/nodeframes.cpp +36 -34
- data/ext/nodemetadata.cpp +21 -3
- data/ext/server.cpp +2 -2
- data/ext/serverlist.cpp +20 -8
- data/ext/wiretap.cpp +11 -8
- data/ext/wiretap.h +17 -13
- data/lib/wiretap.rb +65 -5
- data/test_new/common.rb +8 -0
- data/{test/wiretap-images → test_new/fixtures/img/ppm-8bit}/01.ppm +0 -0
- data/test_new/fixtures/raw/cube_2k_12bitP_1f/0.stoneimage +0 -0
- data/test_new/fixtures/raw/cube_2k_8bit_1f/0.stoneimage +0 -0
- data/test_new/fixtures/raw/cube_SD_10bit_5f/0.stoneimage +0 -0
- data/test_new/fixtures/raw/cube_SD_10bit_5f/1.stoneimage +0 -0
- data/test_new/fixtures/raw/cube_SD_10bit_5f/2.stoneimage +0 -0
- data/test_new/fixtures/raw/cube_SD_10bit_5f/3.stoneimage +0 -0
- data/test_new/fixtures/raw/cube_SD_10bit_5f/4.stoneimage +0 -0
- data/test_new/fixtures/raw/cube_SD_12bitP_5f/0.stoneimage +0 -0
- data/test_new/fixtures/raw/cube_SD_12bitP_5f/1.stoneimage +0 -0
- data/test_new/fixtures/raw/cube_SD_12bitP_5f/2.stoneimage +0 -0
- data/test_new/fixtures/raw/cube_SD_12bitP_5f/3.stoneimage +0 -0
- data/test_new/fixtures/raw/cube_SD_12bitP_5f/4.stoneimage +0 -0
- data/test_new/fixtures/raw/cube_SD_12bitU_5f/0.stoneimage +0 -0
- data/test_new/fixtures/raw/cube_SD_12bitU_5f/1.stoneimage +0 -0
- data/test_new/fixtures/raw/cube_SD_12bitU_5f/2.stoneimage +0 -0
- data/test_new/fixtures/raw/cube_SD_12bitU_5f/3.stoneimage +0 -0
- data/test_new/fixtures/raw/cube_SD_12bitU_5f/4.stoneimage +0 -0
- data/test_new/fixtures/raw/cube_SD_8bit_8f/0.stoneimage +0 -0
- data/test_new/fixtures/raw/cube_SD_8bit_8f/1.stoneimage +0 -0
- data/test_new/fixtures/raw/cube_SD_8bit_8f/2.stoneimage +0 -0
- data/test_new/fixtures/raw/cube_SD_8bit_8f/3.stoneimage +0 -0
- data/test_new/fixtures/raw/cube_SD_8bit_8f/4.stoneimage +0 -0
- data/test_new/fixtures/raw/cube_SD_8bit_8f/5.stoneimage +0 -0
- data/test_new/fixtures/raw/cube_SD_8bit_8f/6.stoneimage +0 -0
- data/test_new/fixtures/raw/cube_SD_8bit_8f/7.stoneimage +0 -0
- data/{test/wiretap-images/b1.stonesound → test_new/fixtures/raw-snd/simple.stonesound} +0 -0
- data/{test/wiretap-images/output.wav → test_new/fixtures/snd/simple-wave.wav} +0 -0
- data/test_new/test_audio_conversions.rb +28 -0
- data/test_new/test_image_conversions.rb +132 -0
- data/test_new/test_parts/connect_to_test_host.rb +27 -0
- data/test_new/test_parts/constants.rb +7 -0
- data/test_new/test_parts/create_test_project.rb +37 -0
- data/test_new/test_parts/raw_formats_and_uploads.rb +170 -0
- data/test_new/test_parts/server_list.rb +20 -0
- data/test_new/test_parts/simple_node_lookup_and_browsing.rb +76 -0
- data/test_new/test_suite.rb +70 -0
- data/{test/convert.rb → test_new/test_thread_worker.rb} +2 -3
- metadata +71 -61
- data/ext/bmp.cpp +0 -65
- data/ext/image.h +0 -27
- data/ext/ppm.cpp +0 -132
- data/ext/sgi.cpp +0 -69
- data/test/audio.rb +0 -27
- data/test/image.rb +0 -101
- data/test/read_frames.rb +0 -142
- data/test/wiretap-images/32bit.stoneimage +0 -621
- data/test/wiretap-images/36bit.stoneimage +0 -1036
- data/test/wiretap-images/48bit.stoneimage +1 -800
- data/test/wiretap-images/a.stoneimage +0 -0
- data/test/wiretap-images/a0.stoneimage +0 -0
- data/test/wiretap-images/a1.stoneimage +0 -0
- data/test/wiretap-images/a2.stoneimage +0 -0
- data/test/wiretap-images/a3.stoneimage +0 -0
- data/test/wiretap-images/a4.stoneimage +0 -0
- data/test/wiretap-images/importable-seq/00000001.ppm +0 -0
- data/test/wiretap-images/importable-seq/00000002.ppm +0 -0
- data/test/wiretap-images/importable-seq/00000003.ppm +0 -0
- data/test/wiretap-images/importable-seq/00000004.ppm +0 -0
- data/test/wiretap-images/importable-seq/00000005.ppm +0 -0
- data/test/wiretap-images/importable-seq/00000006.ppm +0 -0
- data/test/wiretap-images/importable-seq/00000007.ppm +0 -0
- data/test/wiretap-images/importable-seq/00000008.ppm +0 -0
- data/test/wiretap-images/importable-seq/00000009.ppm +0 -0
- data/test/wiretap-images/importable-seq/00000010.ppm +0 -0
- data/test/wiretap-images/importable-seq/00000011.ppm +0 -0
- data/test/wiretap-images/importable-seq/00000012.ppm +0 -0
- data/test/wiretap-images/monsters_001.tif +0 -0
- data/test/wiretap-images/monsters_002.tif +0 -0
- data/test/wiretap-images/monsters_003.tif +0 -0
- data/test/wiretap-images/output.mov +0 -0
- data/test/write_frames.rb +0 -82
data/ext/image_io.cpp
ADDED
|
@@ -0,0 +1,466 @@
|
|
|
1
|
+
#include "wiretap.h"
|
|
2
|
+
#include <sys/types.h>
|
|
3
|
+
#include <sys/stat.h>
|
|
4
|
+
|
|
5
|
+
/************ Memstream writers *****************/
|
|
6
|
+
charstream::charstream() {}
|
|
7
|
+
void charstream::write_char(unsigned char channel) {}
|
|
8
|
+
charstream::~charstream() {}
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
void charstream::write_int32_le(int value) {
|
|
12
|
+
write_char(value >> 0 & 0xFF);
|
|
13
|
+
write_char(value >> 8 & 0xFF);
|
|
14
|
+
write_char(value >> 16& 0xFF);
|
|
15
|
+
write_char(value >> 24& 0xFF);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
void charstream::write_int32_be(int value) {
|
|
19
|
+
write_char(value >> 24& 0xFF);
|
|
20
|
+
write_char(value >> 16& 0xFF);
|
|
21
|
+
write_char(value >> 8 & 0xFF);
|
|
22
|
+
write_char(value >> 0 & 0xFF);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
void charstream::write_int16_le(short value) {
|
|
26
|
+
write_char(value >> 0 & 0xFF);
|
|
27
|
+
write_char(value >> 8 & 0xFF);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
void charstream::write_int16_be(short value) {
|
|
31
|
+
write_char(value >> 8 & 0xFF);
|
|
32
|
+
write_char(value >> 0 & 0xFF);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
void charstream::write_string(char* value) {
|
|
36
|
+
while(value && *value) {
|
|
37
|
+
write_char(*value);
|
|
38
|
+
value++;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
memstream::memstream(unsigned char* _ptr) { ptr = _ptr; }
|
|
44
|
+
void memstream::write_char(unsigned char channel) {
|
|
45
|
+
*ptr++ = channel;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
filestream::filestream(FILE* _f) { f = _f; }
|
|
49
|
+
void filestream::write_char(unsigned char channel) {
|
|
50
|
+
fwrite(&channel, sizeof(channel), 1, f);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
filestream_bgr::filestream_bgr(FILE* _f){ f = _f; count = 0; memset(buffer, 0, sizeof(buffer)); }
|
|
54
|
+
void filestream_bgr::write_char(unsigned char channel) {
|
|
55
|
+
buffer[2 - count] = channel;
|
|
56
|
+
count++;
|
|
57
|
+
if(count == 3) {
|
|
58
|
+
fwrite(buffer, sizeof(buffer), 1, f);
|
|
59
|
+
count = 0;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
/************ ImageIO *************/
|
|
65
|
+
|
|
66
|
+
ImageIO* ImageIO::open(const char* filename, WireTapClipFormat& format, bool read_only) {
|
|
67
|
+
FILE* infile = fopen(filename, read_only ? "r" : "w+");
|
|
68
|
+
if(!infile) {
|
|
69
|
+
THROW("Couldn't open file %s for %s", filename, read_only ? "reading" : "writing");
|
|
70
|
+
}
|
|
71
|
+
char *extension = 0;
|
|
72
|
+
for(extension = const_cast<char *>(filename) + strlen(filename); extension > filename; extension--) {
|
|
73
|
+
if(*extension == '.') {
|
|
74
|
+
extension++;
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if(!strcmp(extension, "ppm")) return new ImageIO_PPM(filename, infile, format);
|
|
79
|
+
if(!strcmp(extension, "sgi")) return new ImageIO_SGI(filename, infile, format);
|
|
80
|
+
if(!strcmp(extension, "bmp")) return new ImageIO_BMP(filename, infile, format);
|
|
81
|
+
if(!strcmp(extension, "stoneimage")) return new ImageIO_RAW(filename, infile, format);
|
|
82
|
+
return NULL;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
int ImageIO::extract_int() {
|
|
87
|
+
char buffer[256];
|
|
88
|
+
int pos = 0;
|
|
89
|
+
char c;
|
|
90
|
+
while(!feof(this->f)) {
|
|
91
|
+
c = fgetc(this->f);
|
|
92
|
+
if(!isalnum(c)) {
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
buffer[pos++] = c;
|
|
96
|
+
if(pos == sizeof(buffer)) break;
|
|
97
|
+
}
|
|
98
|
+
buffer[pos] = '\0';
|
|
99
|
+
return atoi(buffer);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
int ImageIO::read_int32_be() {
|
|
103
|
+
unsigned char bytes[4];
|
|
104
|
+
fread(bytes, sizeof(bytes), 1, f);
|
|
105
|
+
return (bytes[0] << 24) + (bytes[1] << 16) + (bytes[2] << 8) + (bytes[3]);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
short ImageIO::read_int16_be() {
|
|
109
|
+
unsigned char bytes[2];
|
|
110
|
+
fread(bytes, sizeof(bytes), 1, f);
|
|
111
|
+
return (bytes[0] << 8) + (bytes[1]);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
unsigned char ImageIO::read_int8() {
|
|
115
|
+
unsigned char byte;
|
|
116
|
+
fread(&byte, 1, 1, f);
|
|
117
|
+
return byte;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
ImageIO::ImageIO(const char* _filename, FILE* _f, WireTapClipFormat& _format) : format(_format) {
|
|
123
|
+
filename = _filename;
|
|
124
|
+
f = _f;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
ImageIO::~ImageIO() {
|
|
129
|
+
if(f) {
|
|
130
|
+
fclose(f);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
void ImageIO::decode_image_data(unsigned char* frame, charstream& writer) {
|
|
136
|
+
std::auto_ptr<FrameIO> frame_io(FrameIO::decoder(frame, format.width(), format.height(), format.bitsPerPixel()));
|
|
137
|
+
if(!frame_io.get()) {
|
|
138
|
+
THROW("Unsupported color depth for dumping image: %d", format.bitsPerPixel());
|
|
139
|
+
}
|
|
140
|
+
frame_io->decode(writer);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/************** PPM format *****************/
|
|
144
|
+
|
|
145
|
+
ImageIO_PPM::ImageIO_PPM(const char* _filename, FILE* _f, WireTapClipFormat& _format) : ImageIO(_filename, _f, _format) {
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
void ImageIO_PPM::read_format() {
|
|
149
|
+
extract_int();
|
|
150
|
+
|
|
151
|
+
format.setWidth(extract_int());
|
|
152
|
+
format.setHeight(extract_int());
|
|
153
|
+
|
|
154
|
+
int maxval = extract_int();
|
|
155
|
+
if(maxval > 255) {
|
|
156
|
+
//FIXME: possible memory leak in using function.
|
|
157
|
+
THROW("Decoding 16bit PPM files is not supported");
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
format.setBitsPerPixel(24);
|
|
161
|
+
format.setNumChannels(3);
|
|
162
|
+
format.setFrameBufferSize((format.bitsPerPixel()/8)*format.width()*format.height());
|
|
163
|
+
format.setFrameRate(25);
|
|
164
|
+
format.setScanFormat(format.strToScanFormat("progressive"));
|
|
165
|
+
format.setFormatTag("rgb");
|
|
166
|
+
format.setMetaDataTag("IFFFS_XML");
|
|
167
|
+
format.setMetaData("<IFFFS_XML Version=\"1.0\"><ClipData></ClipData></IFFFS_XML>");
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
unsigned char* ImageIO_PPM::read_data() {
|
|
172
|
+
unsigned char* frame = new unsigned char[format.frameBufferSize()];
|
|
173
|
+
|
|
174
|
+
size_t row_size = format.width()*3;
|
|
175
|
+
|
|
176
|
+
for(int i = 0; i < format.height(); i++) {
|
|
177
|
+
size_t read_bytes = fread(frame + (format.height() - 1 - i)*row_size, 1, row_size, f);
|
|
178
|
+
if(read_bytes != row_size) {
|
|
179
|
+
rb_warn("Read %d bytes, expected %d. Step: %d", read_bytes, row_size, i);
|
|
180
|
+
return 0;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return frame;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
void ImageIO_PPM::write_data(unsigned char* frame) {
|
|
188
|
+
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
/************** SGI format *****************/
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
ImageIO_SGI::ImageIO_SGI(const char* _filename, FILE* _f, WireTapClipFormat& _format) : ImageIO(_filename, _f, _format) {
|
|
196
|
+
compressed = false;
|
|
197
|
+
bit16 = false;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
void ImageIO_SGI::read_format() {
|
|
201
|
+
const int header_padding = 404;
|
|
202
|
+
const int magic = 474;
|
|
203
|
+
|
|
204
|
+
short _magic = read_int16_be();
|
|
205
|
+
if(_magic != magic) {
|
|
206
|
+
rb_warn("Warning: %s has a broken file format: %d", filename, _magic);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
compressed = read_int8() ? true : false;
|
|
210
|
+
switch(read_int8()) { // 1 for 1 byte per channel. 24 bit picture
|
|
211
|
+
case 1: format.setBitsPerPixel(24);
|
|
212
|
+
break;
|
|
213
|
+
case 2: format.setBitsPerPixel(48);
|
|
214
|
+
bit16 = true;
|
|
215
|
+
break;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
format.setFrameBufferSize((format.bitsPerPixel()/8)*format.width()*format.height());
|
|
219
|
+
format.setFrameRate(25);
|
|
220
|
+
format.setScanFormat(format.strToScanFormat("progressive"));
|
|
221
|
+
format.setFormatTag("rgb");
|
|
222
|
+
format.setMetaDataTag("IFFFS_XML");
|
|
223
|
+
format.setMetaData("<IFFFS_XML Version=\"1.0\"><ClipData></ClipData></IFFFS_XML>");
|
|
224
|
+
|
|
225
|
+
short d;
|
|
226
|
+
if((d = read_int16_be()) != 3) {
|
|
227
|
+
rb_warn("Unknown number of dimensions: %d. Cannot read", d);
|
|
228
|
+
}
|
|
229
|
+
format.setWidth(read_int16_be());
|
|
230
|
+
format.setHeight(read_int16_be());
|
|
231
|
+
format.setNumChannels(read_int16_be());
|
|
232
|
+
/*int pix_min = */read_int32_be();
|
|
233
|
+
/*int pix_max = */read_int32_be();
|
|
234
|
+
read_int32_be(); // dummy
|
|
235
|
+
|
|
236
|
+
char image_name[80];
|
|
237
|
+
fread(image_name, sizeof(image_name), 1, f);
|
|
238
|
+
|
|
239
|
+
int cl;
|
|
240
|
+
if((cl = read_int32_be()) != 0) {
|
|
241
|
+
rb_warn("Unkwnown colormap: %d", cl);
|
|
242
|
+
}
|
|
243
|
+
char padding[header_padding];
|
|
244
|
+
fread(padding, sizeof(padding), 1, f);
|
|
245
|
+
if(compressed) {
|
|
246
|
+
int tablen = format.height()*3; //Only for colour pictures
|
|
247
|
+
|
|
248
|
+
start_table = std::auto_ptr<unsigned long>(new unsigned long[tablen]);
|
|
249
|
+
for(int i = 0; i < tablen; i++) {
|
|
250
|
+
start_table.get()[i] = read_int32_be();
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
length_table = std::auto_ptr<unsigned long>(new unsigned long[tablen]);
|
|
254
|
+
for(int i = 0; i < tablen; i++) {
|
|
255
|
+
length_table.get()[i] = read_int32_be();
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
unsigned char* ImageIO_SGI::read_channel(int channel) {
|
|
261
|
+
return compressed ? read_compressed(channel) : read_uncompressed(channel);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/*
|
|
265
|
+
* Decoding as here: http://www.martinreddy.net/gfx/2d/RGB.txt
|
|
266
|
+
*/
|
|
267
|
+
unsigned char* ImageIO_SGI::read_compressed(int channel) {
|
|
268
|
+
int row_size = format.width()*format.bitsPerPixel()/24;
|
|
269
|
+
int line_size = row_size*format.height();
|
|
270
|
+
unsigned char* line = new unsigned char[line_size];
|
|
271
|
+
for(int rowno = 0; rowno < format.height(); rowno++) {
|
|
272
|
+
int compressed_row_length = length_table.get()[rowno + channel*format.height()];
|
|
273
|
+
std::auto_ptr<unsigned char> row_in(new unsigned char[compressed_row_length]);
|
|
274
|
+
fseek(f, start_table.get()[rowno + channel*format.height()], SEEK_SET);
|
|
275
|
+
fread(row_in.get(), compressed_row_length, 1, f);
|
|
276
|
+
expand_row(line + row_size*rowno, row_in.get());
|
|
277
|
+
}
|
|
278
|
+
return line;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
void ImageIO_SGI::expand_row(unsigned char* optr, unsigned char* iptr) {
|
|
282
|
+
unsigned char pixel, count, pixel_high = 0;
|
|
283
|
+
while(1) {
|
|
284
|
+
pixel = *iptr++;
|
|
285
|
+
if(bit16) pixel = *iptr++;
|
|
286
|
+
if ( !(count = (pixel & 0x7f)) ) {
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
if(pixel & 0x80) {
|
|
290
|
+
while(count--) {
|
|
291
|
+
*optr = *iptr++;
|
|
292
|
+
optr++;
|
|
293
|
+
if(bit16) {
|
|
294
|
+
*optr = *iptr++;
|
|
295
|
+
optr++;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
} else {
|
|
299
|
+
pixel = *iptr++;
|
|
300
|
+
if(bit16) {
|
|
301
|
+
pixel_high = pixel;
|
|
302
|
+
pixel = *iptr++;
|
|
303
|
+
}
|
|
304
|
+
while(count--) {
|
|
305
|
+
if(bit16) {
|
|
306
|
+
*optr = pixel_high;
|
|
307
|
+
optr++;
|
|
308
|
+
}
|
|
309
|
+
*optr = pixel;
|
|
310
|
+
optr++;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
unsigned char* ImageIO_SGI::read_uncompressed(int channel) {
|
|
318
|
+
int line_size = format.width()*format.height()*format.bitsPerPixel()/24;
|
|
319
|
+
unsigned char* line = new unsigned char[line_size];
|
|
320
|
+
fread(line, line_size, 1, f);
|
|
321
|
+
return line;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
unsigned char* ImageIO_SGI::read_data() {
|
|
325
|
+
int pixel_count = format.width()*format.height()*format.bitsPerPixel()/8;
|
|
326
|
+
unsigned char* frame = new unsigned char[pixel_count];
|
|
327
|
+
std::auto_ptr<unsigned char> line_r(read_channel(0));
|
|
328
|
+
std::auto_ptr<unsigned char> line_g(read_channel(1));
|
|
329
|
+
std::auto_ptr<unsigned char> line_b(read_channel(2));
|
|
330
|
+
|
|
331
|
+
int frame_ptr = 0;
|
|
332
|
+
int line_ptr = 0;
|
|
333
|
+
for(int i = 0; i < format.height(); i++) {
|
|
334
|
+
for(int j = 0; j < format.width(); j++) {
|
|
335
|
+
frame[frame_ptr++] = line_r.get()[line_ptr];
|
|
336
|
+
if(bit16) frame[frame_ptr++] = line_r.get()[line_ptr+1];
|
|
337
|
+
frame[frame_ptr++] = line_g.get()[line_ptr];
|
|
338
|
+
if(bit16) frame[frame_ptr++] = line_g.get()[line_ptr+1];
|
|
339
|
+
frame[frame_ptr++] = line_b.get()[line_ptr];
|
|
340
|
+
if(bit16) frame[frame_ptr++] = line_b.get()[line_ptr+1];
|
|
341
|
+
line_ptr++;
|
|
342
|
+
if(bit16) line_ptr++;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
return frame;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
static void write_channel(int width, int height, int number, unsigned char* frame, FILE* f) {
|
|
351
|
+
std::auto_ptr<unsigned char> buffer(new unsigned char[width*height]);
|
|
352
|
+
for(int i = 0; i < width*height; i++) {
|
|
353
|
+
buffer.get()[i] = frame[3*i + number];
|
|
354
|
+
}
|
|
355
|
+
fwrite(buffer.get(), width*height, 1, f);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
static int wiretap_write_sgi_header(int width, int height, charstream& writer) {
|
|
360
|
+
//const int header_size = 512;
|
|
361
|
+
const int header_padding = 404;
|
|
362
|
+
const int magic = 474;
|
|
363
|
+
|
|
364
|
+
writer.write_int16_be(magic); // Magic 474
|
|
365
|
+
writer.write_char(0); // 0 for uncompressed
|
|
366
|
+
writer.write_char(1); // 1 for 1 byte per channel. 24 bit picture
|
|
367
|
+
writer.write_int16_be(3); // 3 dimensions - one plain image with multiple channels
|
|
368
|
+
writer.write_int16_be(width);
|
|
369
|
+
writer.write_int16_be(height);
|
|
370
|
+
writer.write_int16_be(3); // 3 for RGB mode: 3 channels
|
|
371
|
+
writer.write_int32_be(0); // minimum pixel value
|
|
372
|
+
writer.write_int32_be(0xFF); // maximum pixel value
|
|
373
|
+
writer.write_int32_be(0); // dummy
|
|
374
|
+
|
|
375
|
+
char image_name[80] = "Ruby wiretap encoded";
|
|
376
|
+
for(size_t i = 0; i < sizeof(image_name); i++) {
|
|
377
|
+
writer.write_char(image_name[i]);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
writer.write_int32_be(0); // colormap is in normal mode (0)
|
|
381
|
+
for(int i = 0; i < header_padding; i++) {
|
|
382
|
+
writer.write_char(0);
|
|
383
|
+
}
|
|
384
|
+
return 0;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
|
|
389
|
+
void ImageIO_SGI::write_data(unsigned char* frame) {
|
|
390
|
+
std::auto_ptr<unsigned char> buffer(new unsigned char[format.width()*format.height()*3]);
|
|
391
|
+
filestream stream(f);
|
|
392
|
+
memstream mem(buffer.get());
|
|
393
|
+
|
|
394
|
+
wiretap_write_sgi_header(format.width(), format.height(), stream);
|
|
395
|
+
decode_image_data(frame, mem);
|
|
396
|
+
|
|
397
|
+
write_channel(format.width(), format.height(), 0, buffer.get(), f);
|
|
398
|
+
write_channel(format.width(), format.height(), 1, buffer.get(), f);
|
|
399
|
+
write_channel(format.width(), format.height(), 2, buffer.get(), f);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
|
|
403
|
+
|
|
404
|
+
/************** BMP format *****************/
|
|
405
|
+
|
|
406
|
+
ImageIO_BMP::ImageIO_BMP(const char* _filename, FILE* _f, WireTapClipFormat& _format) : ImageIO(_filename, _f, _format) {
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
void ImageIO_BMP::read_format() {
|
|
410
|
+
}
|
|
411
|
+
unsigned char* ImageIO_BMP::read_data() {
|
|
412
|
+
return NULL;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
void ImageIO_BMP::write_header() {
|
|
416
|
+
filestream writer(f);
|
|
417
|
+
const int header_size = 54;
|
|
418
|
+
int size = header_size + format.width() * format.height() * 3;
|
|
419
|
+
writer.write_string("BM"); // 0,1
|
|
420
|
+
writer.write_int32_le(size); // 2,3,4,5
|
|
421
|
+
writer.write_int32_le(0); // 6,7,8,9: reserved data
|
|
422
|
+
writer.write_int32_le(header_size); // 10,11,12,13: Image header ends.
|
|
423
|
+
writer.write_int32_le(40); // 14,15,16,17: Image information size
|
|
424
|
+
writer.write_int32_le(format.width()); // 18,19,20,21: Width
|
|
425
|
+
writer.write_int32_le(format.height()); // 22,23,24,25: Height
|
|
426
|
+
writer.write_int16_le(1); // 26,27: Number of color planes
|
|
427
|
+
writer.write_int16_le(24); // 28,29: Bits per pixel. We write only 24 bit images
|
|
428
|
+
writer.write_int32_le(0); // 30,31,32,33: Compression schema. None
|
|
429
|
+
writer.write_int32_le(format.width()*format.height()*3); // 34,35,36,37: raw data size. 3 bytes per pixel.
|
|
430
|
+
writer.write_int32_le(2834); // 38,39,40,41: horisontal resolution. Perhaprs 72 dpi. I don't know
|
|
431
|
+
writer.write_int32_le(2834); // 42,43,44,45: vertical resolution
|
|
432
|
+
writer.write_int32_le(0); // 46,47,48,49: number of colors
|
|
433
|
+
writer.write_int32_le(0); // 50,51,52,53: number of important colors
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
|
|
437
|
+
void ImageIO_BMP::write_data(unsigned char* frame) {
|
|
438
|
+
filestream_bgr stream_bgr(f);
|
|
439
|
+
|
|
440
|
+
write_header();
|
|
441
|
+
decode_image_data(frame, stream_bgr);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
/************** RAW format *****************/
|
|
446
|
+
ImageIO_RAW::ImageIO_RAW(const char* _filename, FILE* _f, WireTapClipFormat& _format) : ImageIO(_filename, _f, _format) {
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
void ImageIO_RAW::read_format() {}
|
|
450
|
+
unsigned char* ImageIO_RAW::read_data() {
|
|
451
|
+
struct stat sb;
|
|
452
|
+
if(!stat(filename, &sb)) {
|
|
453
|
+
return NULL;
|
|
454
|
+
}
|
|
455
|
+
unsigned char* frame = new unsigned char[sb.st_size];
|
|
456
|
+
if(!fread(frame, sb.st_size, 1, f)) {
|
|
457
|
+
delete frame;
|
|
458
|
+
return NULL;
|
|
459
|
+
}
|
|
460
|
+
return frame;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
void ImageIO_RAW::write_data(unsigned char* frame) {
|
|
464
|
+
fwrite(frame, format.frameBufferSize(), 1, f);
|
|
465
|
+
}
|
|
466
|
+
|
data/ext/image_io.h
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
#ifndef _IMAGE_IO_H_
|
|
2
|
+
#define _IMAGE_IO_H_
|
|
3
|
+
#include <string.h>
|
|
4
|
+
#include "charstream.h"
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ImageIO {
|
|
10
|
+
public:
|
|
11
|
+
virtual void read_format() = 0;
|
|
12
|
+
virtual unsigned char* read_data() = 0;
|
|
13
|
+
virtual void write_data(unsigned char* frame) = 0;
|
|
14
|
+
|
|
15
|
+
static ImageIO* open(const char* filename, WireTapClipFormat& format, bool read_only = true);
|
|
16
|
+
ImageIO(const char* _filename, FILE* _f, WireTapClipFormat& _format);
|
|
17
|
+
virtual ~ImageIO();
|
|
18
|
+
protected:
|
|
19
|
+
FILE* f;
|
|
20
|
+
const char* filename;
|
|
21
|
+
WireTapClipFormat& format;
|
|
22
|
+
int extract_int();
|
|
23
|
+
int read_int32_be();
|
|
24
|
+
short read_int16_be();
|
|
25
|
+
unsigned char read_int8();
|
|
26
|
+
void decode_image_data(unsigned char* frame, charstream& writer);
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
class ImageIO_SGI : public ImageIO {
|
|
30
|
+
public:
|
|
31
|
+
ImageIO_SGI(const char* filename, FILE* f, WireTapClipFormat& _format);
|
|
32
|
+
virtual void read_format();
|
|
33
|
+
virtual unsigned char* read_data();
|
|
34
|
+
virtual void write_data(unsigned char* frame);
|
|
35
|
+
protected:
|
|
36
|
+
bool compressed;
|
|
37
|
+
bool bit16;
|
|
38
|
+
std::auto_ptr<unsigned long> length_table;
|
|
39
|
+
std::auto_ptr<unsigned long> start_table;
|
|
40
|
+
unsigned char* read_channel(int channel);
|
|
41
|
+
unsigned char* read_uncompressed(int channel);
|
|
42
|
+
unsigned char* read_compressed(int channel);
|
|
43
|
+
void expand_row(unsigned char* optr, unsigned char* iptr);
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
class ImageIO_PPM : public ImageIO {
|
|
47
|
+
public:
|
|
48
|
+
ImageIO_PPM(const char* filename, FILE* f, WireTapClipFormat& _format);
|
|
49
|
+
virtual void read_format();
|
|
50
|
+
virtual unsigned char* read_data();
|
|
51
|
+
virtual void write_data(unsigned char* frame);
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
class ImageIO_BMP : public ImageIO {
|
|
55
|
+
public:
|
|
56
|
+
ImageIO_BMP(const char* filename, FILE* f, WireTapClipFormat& _format);
|
|
57
|
+
virtual void read_format();
|
|
58
|
+
virtual unsigned char* read_data();
|
|
59
|
+
virtual void write_data(unsigned char* frame);
|
|
60
|
+
protected:
|
|
61
|
+
void write_header();
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
class ImageIO_RAW : public ImageIO {
|
|
65
|
+
public:
|
|
66
|
+
ImageIO_RAW(const char* filename, FILE* f, WireTapClipFormat& _format);
|
|
67
|
+
virtual void read_format();
|
|
68
|
+
virtual unsigned char* read_data();
|
|
69
|
+
virtual void write_data(unsigned char* frame);
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
#endif /* _IMAGE_IO_H_ */
|
|
73
|
+
|