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