VTK  9.4.20250304
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 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 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 void EncodeCharacterString3(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
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 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 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
178private:
179 static int ReverseBytes(int* x)
180 {
181 /* break x apart, then put it back together backwards */
182 int part1 = (*x) & 0xFF;
183 int part2 = ((*x) >> 8) & 0xFF;
184 int part3 = ((*x) >> 16) & 0xFF;
185 int part4 = ((*x) >> 24) & 0xFF;
186 return (part1 << 24) | (part2 << 16) | (part3 << 8) | part4;
187 }
188
190};
191
193{
194
195public:
196 template <typename T>
197 static void EncodeIntegerDeltaZ(vtkX3DExporterFIByteWriter* writer, T* value, size_t size,
198 vtkZLibDataCompressor* compressor, bool image = false)
199 {
200 // We want to start at position 3
201 assert(writer->CurrentBytePos == 2);
202
203 // ITU C.19.3.4: If the alternative encoding-algorithm is present,
204 // then the two bits '11' (discriminant) are appended
205 writer->PutBits("11");
206 // ITU 10.8.1: This encoding algorithm has a vocabulary table index of 33
207 writer->PutBits(34 - 1, 8);
208
209 // compute delta
210 char span = 0;
211 size_t i = 0;
212 int f;
213 unsigned char* p;
214 std::vector<unsigned char> deltas;
215
216 if (image)
217 {
218 span = 0;
219 for (i = 0; i < size; i++)
220 {
221 int v = 1 + (value[i]);
222 int* vp = &v;
223 f = vtkX3DExporterFIWriterHelper::ReverseBytes(vp);
224 p = reinterpret_cast<unsigned char*>(&f);
225 deltas.push_back(p[0]);
226 deltas.push_back(p[1]);
227 deltas.push_back(p[2]);
228 deltas.push_back(p[3]);
229 }
230 compressor->SetCompressionLevel(9);
231 }
232 else
233 {
234 for (i = 0; i < 20; i++)
235 {
236 if (value[i] == -1)
237 {
238 span = static_cast<char>(i) + 1;
239 break;
240 }
241 }
242 if (!span)
243 span = 4;
244
245 for (i = 0; i < static_cast<size_t>(span); i++)
246 {
247 int v = 1 + value[i];
248 int* vp = &v;
249 f = vtkX3DExporterFIWriterHelper::ReverseBytes(vp);
250
251 p = reinterpret_cast<unsigned char*>(&f);
252 deltas.push_back(p[0]);
253 deltas.push_back(p[1]);
254 deltas.push_back(p[2]);
255 deltas.push_back(p[3]);
256 }
257 for (i = span; i < size; i++)
258 {
259 int v = 1 + (value[i] - value[i - span]);
260 f = vtkX3DExporterFIWriterHelper::ReverseBytes(&v);
261
262 p = reinterpret_cast<unsigned char*>(&f);
263 deltas.push_back(p[0]);
264 deltas.push_back(p[1]);
265 deltas.push_back(p[2]);
266 deltas.push_back(p[3]);
267 }
268 }
269
270 size_t bufferSize = deltas.size() + static_cast<unsigned int>(ceil(deltas.size() * 0.001)) + 12;
271 unsigned char* buffer = new unsigned char[bufferSize];
272 size_t newSize = compressor->Compress(deltas.data(), static_cast<unsigned long>(deltas.size()),
273 buffer, static_cast<unsigned long>(bufferSize));
274
275 std::string bytes;
276 int size32 = static_cast<int>(size);
277 int size32_reversed = vtkX3DExporterFIWriterHelper::ReverseBytes(&size32);
278 char* s = reinterpret_cast<char*>(&size32_reversed);
279 bytes.append(s, 4);
280 bytes.append(&span, 1);
281
282 for (i = 0; i < newSize; i++)
283 {
284 unsigned char c = buffer[i];
285 bytes += c;
286 }
287 delete[] buffer;
288
290 if (image)
291 {
292 compressor->SetCompressionLevel(5);
293 }
294 }
295
296 static void EncodeQuantizedzlibFloatArray(vtkX3DExporterFIByteWriter* writer, const double* value,
297 size_t size, vtkZLibDataCompressor* compressor)
298 {
299 // We want to start at position 3
300 assert(writer->CurrentBytePos == 2);
301
302 // ITU C.19.3.4: If the alternative encoding-algorithm is present,
303 // then the two bits '11' (discriminant) are appended
304 writer->PutBits("11");
305 // ITU 10.8.1: This encoding algorithm has a vocabulary table index of 33
306 writer->PutBits(34, 8);
307
308 unsigned char* bytes = new unsigned char[size * 4];
309 unsigned char* bytepos = bytes;
310 std::string bytesCompressed;
311 size_t i;
312
313 const double* vd = value;
314 for (i = 0; i < size; i++)
315 {
316 union float_to_unsigned_int_to_bytes
317 {
318 float f;
319 unsigned int ui;
320 unsigned char ub[4]; // unsigned bytes
321 };
322 float_to_unsigned_int_to_bytes v;
323 v.f = (*vd) * 2.0;
324
325 // Avoid -0
326 if (v.ui == 0x80000000)
327 {
328 v.f = 0.0f;
329 }
330 // vtkGenericWarningMacro(<< "value: " << v << " bytes: " << (int)s[0] << " " << (int)s[1] <<
331 // " " << (int)s[2] << " " << (int)s[3]);
332 *bytepos++ = v.ub[3];
333 *bytepos++ = v.ub[2];
334 *bytepos++ = v.ub[1];
335 *bytepos++ = v.ub[0];
336 vd++;
337 }
338
339 // Compress the data
340 size_t bufferSize = (size * 4) + static_cast<size_t>(ceil((size * 4) * 0.001)) + 12;
341 unsigned char* buffer = new unsigned char[bufferSize];
342 size_t newSize = compressor->Compress(
343 bytes, static_cast<unsigned long>(size * 4), buffer, static_cast<unsigned long>(bufferSize));
344
345 char* s;
346 // Put the number of bits for exponent
347 bytesCompressed += static_cast<char>(8);
348 // Put the number of bits for mantissa
349 bytesCompressed += static_cast<char>(23);
350 // Put the length
351 int length = static_cast<int>(size * 4);
352 int length_reversed = vtkX3DExporterFIWriterHelper::ReverseBytes(&length);
353 s = reinterpret_cast<char*>(&length_reversed);
354 bytesCompressed.append(s, 4);
355
356 // Put the number of floats
357 int numFloats = static_cast<int>(size);
358 int numFloats_reversed = vtkX3DExporterFIWriterHelper::ReverseBytes(&numFloats);
359 s = reinterpret_cast<char*>(&numFloats_reversed);
360 bytesCompressed.append(s, 4);
361
362 for (i = 0; i < newSize; i++)
363 {
364 unsigned char c = buffer[i];
365 bytesCompressed += c;
366 }
368 delete[] buffer;
369 delete[] bytes;
370 }
371};
372
373VTK_ABI_NAMESPACE_END
374#endif
375// 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 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.