VTK  9.3.20240831
vtkX3DExporterFIWriterHelper.h
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
2// SPDX-License-Identifier: BSD-3-Clause
8#ifndef vtkX3DExporterFIWriterHelper_h
9#define vtkX3DExporterFIWriterHelper_h
10
11//#include "vtkX3DExporterFIByteWriter.h"
13#include <cassert>
14
15#define EXPONENT_MASK_32 0x7f800000
16#define MANTISSA_MASK_32 0x007fffff
17
18#ifndef max
19#define max(a, b) (((a) > (b)) ? (a) : (b))
20#endif
21VTK_ABI_NAMESPACE_BEGIN
23{
24public:
26 float f;
27 unsigned int ui;
28 unsigned char ub[4]; // unsigned bytes
29 };
30
31 template <typename T>
32 static inline void EncodeFloatFI(vtkX3DExporterFIByteWriter* writer, T* value, size_t size)
33 {
34 // We want to start at position 3
35 assert(writer->CurrentBytePos == 2);
36
37 // ITU C.19.3.4: If the alternative encoding-algorithm is present,
38 // then the two bits '11' (discriminant) are appended
39 writer->PutBits("11");
40 // ITU 10.8.1: This encoding algorithm has a vocabulary table index of 7,
41 writer->PutBits(7 - 1, 8);
42
43 std::string bytes;
44 char byte[4];
45 for (size_t i = 0; i < size; i++)
46 {
48 v.f = value[i];
49
50 // Avoid -0
51 if (v.ui == 0x80000000)
52 {
53 v.f = 0;
54 }
55
56 byte[0] = v.ub[3];
57 byte[1] = v.ub[2];
58 byte[2] = v.ub[1];
59 byte[3] = v.ub[0];
60
61 bytes.append(byte, 4);
62 }
63 EncodeNonEmptyByteString5(writer, bytes);
64 }
65
66 template <typename T>
67 static inline void EncodeIntegerFI(vtkX3DExporterFIByteWriter* writer, T* value, size_t size)
68 {
69 // We want to start at position 3
70 assert(writer->CurrentBytePos == 2);
71
72 // ITU C.19.3.4: If the alternative encoding-algorithm is present,
73 // then the two bits '11' (discriminant) are appended
74 writer->PutBits("11");
75 // ITU 10.8.1: This encoding algorithm has a vocabulary table index of 4,
76 writer->PutBits(4 - 1, 8);
77 std::string bytes;
78 for (size_t i = 0; i < size; i++)
79 {
80 int v = value[i];
81 int f = ReverseBytes(&v);
82 char* p = reinterpret_cast<char*>(&f);
83 bytes.append(p, 4);
84 }
85 EncodeNonEmptyByteString5(writer, bytes);
86 }
87
88 static inline void EncodeCharacterString3(
89 vtkX3DExporterFIByteWriter* writer, const std::string& value)
90 {
91 // We want to start at position 3
92 assert(writer->CurrentBytePos == 2);
93
94 // ITU C.19.3.1 If the alternative utf-8 is present, then the two bits '00'
95 // are appended to the bit stream.
96 writer->PutBits("00");
97 // ITU C.19.4: The component bytes is encoded as described in C.23.
98 EncodeNonEmptyByteString5(writer, value);
99 }
100
101 // ITU C.23: Encoding of the NonEmptyByteString starting
102 // on the fifth bit of an byte
103 static inline void EncodeNonEmptyByteString5(
104 vtkX3DExporterFIByteWriter* writer, const std::string& value)
105 {
106 int length = static_cast<int>(value.length());
107 if (length <= 8)
108 {
109 writer->PutBit(false);
110 writer->PutBits(length - 1, 3);
111 }
112 else if (length <= 264)
113 {
114 writer->PutBits("1000");
115 writer->PutBits(length - 9, 8);
116 }
117 else
118 {
119 writer->PutBits("1100");
120 writer->PutBits(length - 265, 32);
121 }
122 writer->PutBytes(value.c_str(), length);
123 }
124
125 // ITU C.27: Encoding of integers in the range 1 to 2^20
126 // starting on the third bit of an byte
127 static inline void EncodeInteger3(vtkX3DExporterFIByteWriter* writer, unsigned int value)
128 {
129 // We want to start at position 3
130 assert(writer->CurrentBytePos == 2);
131
132 if (value <= 32) // ITU C.27.2
133 {
134 writer->PutBit(false);
135 writer->PutBits(value - 1, 5);
136 }
137 else if (value <= 2080) // ITU C.27.3
138 {
139 writer->PutBits("100");
140 writer->PutBits(value - 33, 11);
141 }
142 else if (value < 526368) // ITU C.27.4
143 {
144 writer->PutBits("101");
145 writer->PutBits(value - 2081, 19);
146 }
147 else // ITU C.27.5
148 {
149 writer->PutBits("1100000000");
150 writer->PutBits(value - 526369, 20);
151 }
152 }
153
154 // ITU C.25: Encoding of integers in the range 1 to 2^20
155 // starting on the second bit of an byte
156 static inline void EncodeInteger2(vtkX3DExporterFIByteWriter* writer, unsigned int value)
157 {
158 // We want to start at position 2
159 assert(writer->CurrentBytePos == 1);
160
161 if (value <= 64) // ITU C.25.2
162 {
163 writer->PutBits("0");
164 writer->PutBits(value - 1, 6);
165 }
166 else if (value <= 8256) // ITU C.25.3
167 {
168 writer->PutBits("10");
169 writer->PutBits(value - 65, 13);
170 }
171 else // ITU C.25.4
172 {
173 writer->PutBits("110");
174 writer->PutBits(value - 8257, 20);
175 }
176 }
177
178 static inline void EncodeLineFeed(vtkX3DExporterFIByteWriter* writer)
179 {
180 static bool firstTime = true;
181 writer->FillByte();
182 if (firstTime)
183 {
184 writer->PutBits("1001000000001010");
185 firstTime = false;
186 }
187 else
188 {
189 // cout << "Encode NOT the first time" << endl;
190 writer->PutBits("10100000");
191 }
192 }
193
194private:
195 static int ReverseBytes(int* x)
196 {
197 /* break x apart, then put it back together backwards */
198 int part1 = (*x) & 0xFF;
199 int part2 = ((*x) >> 8) & 0xFF;
200 int part3 = ((*x) >> 16) & 0xFF;
201 int part4 = ((*x) >> 24) & 0xFF;
202 return (part1 << 24) | (part2 << 16) | (part3 << 8) | part4;
203 }
204
206};
207
209{
210
211public:
212 template <typename T>
213 static inline void EncodeIntegerDeltaZ(vtkX3DExporterFIByteWriter* writer, T* value, size_t size,
214 vtkZLibDataCompressor* compressor, bool image = false)
215 {
216 // We want to start at position 3
217 assert(writer->CurrentBytePos == 2);
218
219 // ITU C.19.3.4: If the alternative encoding-algorithm is present,
220 // then the two bits '11' (discriminant) are appended
221 writer->PutBits("11");
222 // ITU 10.8.1: This encoding algorithm has a vocabulary table index of 33
223 writer->PutBits(34 - 1, 8);
224
225 // compute delta
226 char span = 0;
227 size_t i = 0;
228 int f;
229 unsigned char* p;
230 std::vector<unsigned char> deltas;
231
232 if (image)
233 {
234 span = 0;
235 for (i = 0; i < size; i++)
236 {
237 int v = 1 + (value[i]);
238 int* vp = reinterpret_cast<int*>(&v);
239 f = vtkX3DExporterFIWriterHelper::ReverseBytes(vp);
240 p = reinterpret_cast<unsigned char*>(&f);
241 deltas.push_back(p[0]);
242 deltas.push_back(p[1]);
243 deltas.push_back(p[2]);
244 deltas.push_back(p[3]);
245 }
246 compressor->SetCompressionLevel(9);
247 }
248 else
249 {
250 for (i = 0; i < 20; i++)
251 {
252 if (value[i] == -1)
253 {
254 span = static_cast<char>(i) + 1;
255 break;
256 }
257 }
258 if (!span)
259 span = 4;
260
261 for (i = 0; i < static_cast<size_t>(span); i++)
262 {
263 int v = 1 + value[i];
264 int* vp = reinterpret_cast<int*>(&v);
265 f = vtkX3DExporterFIWriterHelper::ReverseBytes(vp);
266
267 p = reinterpret_cast<unsigned char*>(&f);
268 deltas.push_back(p[0]);
269 deltas.push_back(p[1]);
270 deltas.push_back(p[2]);
271 deltas.push_back(p[3]);
272 }
273 for (i = span; i < size; i++)
274 {
275 int v = 1 + (value[i] - value[i - span]);
276 f = vtkX3DExporterFIWriterHelper::ReverseBytes(&v);
277
278 p = reinterpret_cast<unsigned char*>(&f);
279 deltas.push_back(p[0]);
280 deltas.push_back(p[1]);
281 deltas.push_back(p[2]);
282 deltas.push_back(p[3]);
283 }
284 }
285
286 size_t bufferSize = deltas.size() + static_cast<unsigned int>(ceil(deltas.size() * 0.001)) + 12;
287 unsigned char* buffer = new unsigned char[bufferSize];
288 size_t newSize = compressor->Compress(deltas.data(), static_cast<unsigned long>(deltas.size()),
289 buffer, static_cast<unsigned long>(bufferSize));
290
291 std::string bytes;
292 int size32 = static_cast<int>(size);
293 int size32_reversed = vtkX3DExporterFIWriterHelper::ReverseBytes(&size32);
294 char* s = reinterpret_cast<char*>(&size32_reversed);
295 bytes.append(s, 4);
296 bytes.append(&span, 1);
297
298 for (i = 0; i < newSize; i++)
299 {
300 unsigned char c = buffer[i];
301 bytes += c;
302 }
303 delete[] buffer;
304
306 if (image)
307 {
308 compressor->SetCompressionLevel(5);
309 }
310 }
311
312 static inline void EncodeQuantizedzlibFloatArray(vtkX3DExporterFIByteWriter* writer,
313 const double* value, size_t size, vtkZLibDataCompressor* compressor)
314 {
315 // We want to start at position 3
316 assert(writer->CurrentBytePos == 2);
317
318 // ITU C.19.3.4: If the alternative encoding-algorithm is present,
319 // then the two bits '11' (discriminant) are appended
320 writer->PutBits("11");
321 // ITU 10.8.1: This encoding algorithm has a vocabulary table index of 33
322 writer->PutBits(34, 8);
323
324 unsigned char* bytes = new unsigned char[size * 4];
325 unsigned char* bytepos = bytes;
326 std::string bytesCompressed;
327 size_t i;
328
329 const double* vd = value;
330 for (i = 0; i < size; i++)
331 {
332 union float_to_unsigned_int_to_bytes {
333 float f;
334 unsigned int ui;
335 unsigned char ub[4]; // unsigned bytes
336 };
337 float_to_unsigned_int_to_bytes v;
338 v.f = (*vd) * 2.0;
339
340 // Avoid -0
341 if (v.ui == 0x80000000)
342 {
343 v.f = 0.0f;
344 }
345 // vtkGenericWarningMacro(<< "value: " << v << " bytes: " << (int)s[0] << " " << (int)s[1] <<
346 // " " << (int)s[2] << " " << (int)s[3]);
347 *bytepos++ = v.ub[3];
348 *bytepos++ = v.ub[2];
349 *bytepos++ = v.ub[1];
350 *bytepos++ = v.ub[0];
351 vd++;
352 }
353
354 // Compress the data
355 size_t bufferSize = (size * 4) + static_cast<size_t>(ceil((size * 4) * 0.001)) + 12;
356 unsigned char* buffer = new unsigned char[bufferSize];
357 size_t newSize = compressor->Compress(
358 bytes, static_cast<unsigned long>(size * 4), buffer, static_cast<unsigned long>(bufferSize));
359
360 char* s;
361 // Put the number of bits for exponent
362 bytesCompressed += static_cast<char>(8);
363 // Put the number of bits for mantissa
364 bytesCompressed += static_cast<char>(23);
365 // Put the length
366 int length = static_cast<int>(size * 4);
367 int length_reversed = vtkX3DExporterFIWriterHelper::ReverseBytes(&length);
368 s = reinterpret_cast<char*>(&length_reversed);
369 bytesCompressed.append(s, 4);
370
371 // Put the number of floats
372 int numFloats = static_cast<int>(size);
373 int numFloats_reversed = vtkX3DExporterFIWriterHelper::ReverseBytes(&numFloats);
374 s = reinterpret_cast<char*>(&numFloats_reversed);
375 bytesCompressed.append(s, 4);
376
377 for (i = 0; i < newSize; i++)
378 {
379 unsigned char c = buffer[i];
380 bytesCompressed += c;
381 }
383 delete[] buffer;
384 delete[] bytes;
385 }
386};
387
388VTK_ABI_NAMESPACE_END
389#endif
390// VTK-HeaderTest-Exclude: vtkX3DExporterFIWriterHelper.h
static void EncodeQuantizedzlibFloatArray(vtkX3DExporterFIByteWriter *writer, const double *value, size_t size, vtkZLibDataCompressor *compressor)
static void EncodeIntegerDeltaZ(vtkX3DExporterFIByteWriter *writer, T *value, size_t size, vtkZLibDataCompressor *compressor, bool image=false)
size_t Compress(unsigned char const *uncompressedData, size_t uncompressedSize, unsigned char *compressedData, size_t compressionSpace)
Compress the given input data buffer into the given output buffer.
static void EncodeInteger2(vtkX3DExporterFIByteWriter *writer, unsigned int value)
static void EncodeInteger3(vtkX3DExporterFIByteWriter *writer, unsigned int value)
static void EncodeCharacterString3(vtkX3DExporterFIByteWriter *writer, const std::string &value)
static void EncodeLineFeed(vtkX3DExporterFIByteWriter *writer)
static void EncodeIntegerFI(vtkX3DExporterFIByteWriter *writer, T *value, size_t size)
static void EncodeFloatFI(vtkX3DExporterFIByteWriter *writer, T *value, size_t size)
static void EncodeNonEmptyByteString5(vtkX3DExporterFIByteWriter *writer, const std::string &value)
Data compression using zlib.
void SetCompressionLevel(int compressionLevel) override
Get/Set the compression level.