VTK  9.7.1
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"
12 #include "vtkZLibDataCompressor.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
21 VTK_ABI_NAMESPACE_BEGIN
23 {
24 public:
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 
178 private:
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 
189  friend class X3DEncoderFunctions;
190 };
191 
193 {
194 
195 public:
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 
373 VTK_ABI_NAMESPACE_END
374 #endif
375 // VTK-HeaderTest-Exclude: vtkX3DExporterFIWriterHelper.h
static void EncodeNonEmptyByteString5(vtkX3DExporterFIByteWriter *writer, const std::string &value)
static void EncodeIntegerDeltaZ(vtkX3DExporterFIByteWriter *writer, T *value, size_t size, vtkZLibDataCompressor *compressor, bool image=false)
static void EncodeCharacterString3(vtkX3DExporterFIByteWriter *writer, const std::string &value)
static void EncodeInteger2(vtkX3DExporterFIByteWriter *writer, unsigned int value)
Data compression using zlib.
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 EncodeInteger3(vtkX3DExporterFIByteWriter *writer, unsigned int value)
void SetCompressionLevel(int compressionLevel) override
Get/Set the compression level.
static void EncodeFloatFI(vtkX3DExporterFIByteWriter *writer, T *value, size_t size)
static void EncodeQuantizedzlibFloatArray(vtkX3DExporterFIByteWriter *writer, const double *value, size_t size, vtkZLibDataCompressor *compressor)
static void EncodeIntegerFI(vtkX3DExporterFIByteWriter *writer, T *value, size_t size)