1 /*=========================================================================
2
3 Program: Visualization Toolkit
4 Module: vtkImageImport.cxx
5
6 Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7 All rights reserved.
8 See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9
10 This software is distributed WITHOUT ANY WARRANTY; without even
11 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12 PURPOSE. See the above copyright notice for more information.
13
14 =========================================================================*/
15 #include "vtkImageImport.h"
16
17 #include "vtkByteSwap.h"
18 #include "vtkDataArray.h"
19 #include "vtkImageData.h"
20 #include "vtkImageImportExecutive.h"
21 #include "vtkInformation.h"
22 #include "vtkInformationVector.h"
23 #include "vtkObjectFactory.h"
24 #include "vtkPointData.h"
25 #include "vtkStreamingDemandDrivenPipeline.h"
26
27 #include <cctype>
28 #include <exception>
29
30 vtkStandardNewMacro(vtkImageImport);
31
32 #define tryCatchMacro(invocation, messagePrepend) \
33 try \
34 { \
35 invocation; \
36 } \
37 catch (std::exception & _e) \
38 { \
39 vtkErrorMacro(<< messagePrepend << _e.what()); \
40 } \
41 catch (...) \
42 { \
43 vtkErrorMacro(<< "Unknown exception."); \
44 }
45
46 //------------------------------------------------------------------------------
vtkImageImport()47 vtkImageImport::vtkImageImport()
48 {
49 int idx;
50
51 this->ImportVoidPointer = nullptr;
52
53 this->DataScalarType = VTK_SHORT;
54 this->NumberOfScalarComponents = 1;
55
56 for (idx = 0; idx < 3; ++idx)
57 {
58 this->DataExtent[idx * 2] = this->DataExtent[idx * 2 + 1] = 0;
59 this->WholeExtent[idx * 2] = this->WholeExtent[idx * 2 + 1] = 0;
60 this->DataSpacing[idx] = 1.0;
61 this->DataOrigin[idx] = 0.0;
62 }
63 this->DataDirection[0] = this->DataDirection[4] = this->DataDirection[8] = 1.0;
64 this->DataDirection[1] = this->DataDirection[2] = this->DataDirection[3] =
65 this->DataDirection[5] = this->DataDirection[6] = this->DataDirection[7] = 0.0;
66
67 this->SaveUserArray = 0;
68
69 this->CallbackUserData = nullptr;
70
71 this->UpdateInformationCallback = nullptr;
72 this->PipelineModifiedCallback = nullptr;
73 this->WholeExtentCallback = nullptr;
74 this->SpacingCallback = nullptr;
75 this->OriginCallback = nullptr;
76 this->DirectionCallback = nullptr;
77 this->ScalarTypeCallback = nullptr;
78 this->NumberOfComponentsCallback = nullptr;
79 this->PropagateUpdateExtentCallback = nullptr;
80 this->UpdateDataCallback = nullptr;
81 this->DataExtentCallback = nullptr;
82 this->BufferPointerCallback = nullptr;
83
84 this->SetNumberOfInputPorts(0);
85
86 vtkExecutive* exec = vtkImageImportExecutive::New();
87 this->SetExecutive(exec);
88 exec->Delete();
89
90 this->ScalarArrayName = nullptr;
91 this->SetScalarArrayName("scalars");
92 }
93
94 //------------------------------------------------------------------------------
~vtkImageImport()95 vtkImageImport::~vtkImageImport()
96 {
97 if (!this->SaveUserArray)
98 {
99 delete[] static_cast<char*>(this->ImportVoidPointer);
100 }
101 this->SetScalarArrayName(nullptr);
102 }
103
104 //------------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)105 void vtkImageImport::PrintSelf(ostream& os, vtkIndent indent)
106 {
107 this->Superclass::PrintSelf(os, indent);
108
109 int idx;
110
111 os << indent << "ImportVoidPointer: " << this->ImportVoidPointer << "\n";
112
113 os << indent << "DataScalarType: " << vtkImageScalarTypeNameMacro(this->DataScalarType) << "\n";
114
115 os << indent << "NumberOfScalarComponents: " << this->NumberOfScalarComponents << "\n";
116
117 os << indent << "WholeExtent: (" << this->WholeExtent[0];
118 for (idx = 1; idx < 6; ++idx)
119 {
120 os << ", " << this->WholeExtent[idx];
121 }
122 os << ")\n";
123
124 os << indent << "DataExtent: (" << this->DataExtent[0];
125 for (idx = 1; idx < 6; ++idx)
126 {
127 os << ", " << this->DataExtent[idx];
128 }
129 os << ")\n";
130
131 os << indent << "DataSpacing: (" << this->DataSpacing[0];
132 for (idx = 1; idx < 3; ++idx)
133 {
134 os << ", " << this->DataSpacing[idx];
135 }
136 os << ")\n";
137
138 os << indent << "DataOrigin: (" << this->DataOrigin[0];
139 for (idx = 1; idx < 3; ++idx)
140 {
141 os << ", " << this->DataOrigin[idx];
142 }
143 os << ")\n";
144
145 os << indent << "DataDirection: (" << this->DataDirection[0];
146 for (idx = 1; idx < 9; ++idx)
147 {
148 os << ", " << this->DataDirection[idx];
149 }
150 os << ")\n";
151
152 os << indent << "CallbackUserData: " << (this->CallbackUserData ? "Set" : "Not Set") << "\n";
153
154 os << indent
155 << "UpdateInformationCallback: " << (this->UpdateInformationCallback ? "Set" : "Not Set")
156 << "\n";
157
158 os << indent
159 << "PipelineModifiedCallback: " << (this->PipelineModifiedCallback ? "Set" : "Not Set")
160 << "\n";
161
162 os << indent << "WholeExtentCallback: " << (this->WholeExtentCallback ? "Set" : "Not Set")
163 << "\n";
164
165 os << indent << "SpacingCallback: " << (this->SpacingCallback ? "Set" : "Not Set") << "\n";
166
167 os << indent << "OriginCallback: " << (this->OriginCallback ? "Set" : "Not Set") << "\n";
168
169 os << indent << "DirectionCallback: " << (this->DirectionCallback ? "Set" : "Not Set") << "\n";
170
171 os << indent << "ScalarTypeCallback: " << (this->ScalarTypeCallback ? "Set" : "Not Set") << "\n";
172
173 os << indent
174 << "NumberOfComponentsCallback: " << (this->NumberOfComponentsCallback ? "Set" : "Not Set")
175 << "\n";
176
177 os << indent << "PropagateUpdateExtentCallback: "
178 << (this->PropagateUpdateExtentCallback ? "Set" : "Not Set") << "\n";
179
180 os << indent << "UpdateDataCallback: " << (this->UpdateDataCallback ? "Set" : "Not Set") << "\n";
181
182 os << indent << "DataExtentCallback: " << (this->DataExtentCallback ? "Set" : "Not Set") << "\n";
183
184 os << indent << "BufferPointerCallback: " << (this->BufferPointerCallback ? "Set" : "Not Set")
185 << "\n";
186
187 os << indent << "ScalarArrayName: ";
188 if (this->ScalarArrayName != nullptr)
189 {
190 os << this->ScalarArrayName << endl;
191 }
192 else
193 {
194 os << "(none)" << endl;
195 }
196 }
197
198 //------------------------------------------------------------------------------
RequestUpdateExtent(vtkInformation * vtkNotUsed (request),vtkInformationVector ** vtkNotUsed (inputVector),vtkInformationVector * outputVector)199 int vtkImageImport::RequestUpdateExtent(vtkInformation* vtkNotUsed(request),
200 vtkInformationVector** vtkNotUsed(inputVector), vtkInformationVector* outputVector)
201 {
202 if (this->PropagateUpdateExtentCallback)
203 {
204 int uExt[6];
205
206 vtkInformation* outInfo = outputVector->GetInformationObject(0);
207 outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(), uExt);
208 tryCatchMacro((this->PropagateUpdateExtentCallback)(this->CallbackUserData, uExt),
209 "PropagateUpdateExtentCallback: ");
210 }
211
212 return 1;
213 }
214
215 //------------------------------------------------------------------------------
ComputePipelineMTime(vtkInformation * request,vtkInformationVector ** inInfoVec,vtkInformationVector * outInfoVec,int requestFromOutputPort,vtkMTimeType * mtime)216 int vtkImageImport::ComputePipelineMTime(vtkInformation* request, vtkInformationVector** inInfoVec,
217 vtkInformationVector* outInfoVec, int requestFromOutputPort, vtkMTimeType* mtime)
218 {
219 if (this->InvokePipelineModifiedCallbacks())
220 {
221 this->Modified();
222 }
223 // Superclass normally returns our MTime.
224 return Superclass::ComputePipelineMTime(
225 request, inInfoVec, outInfoVec, requestFromOutputPort, mtime);
226 }
227
228 //------------------------------------------------------------------------------
RequestInformation(vtkInformation * vtkNotUsed (request),vtkInformationVector ** vtkNotUsed (inputVector),vtkInformationVector * outputVector)229 int vtkImageImport::RequestInformation(vtkInformation* vtkNotUsed(request),
230 vtkInformationVector** vtkNotUsed(inputVector), vtkInformationVector* outputVector)
231 {
232 // get the info objects
233 vtkInformation* outInfo = outputVector->GetInformationObject(0);
234
235 // If set, use the callbacks to fill in our data members.
236 this->InvokeExecuteInformationCallbacks();
237
238 // Legacy support for code that sets only DataExtent.
239 this->LegacyCheckWholeExtent();
240
241 // set the whole extent
242 outInfo->Set(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), this->WholeExtent, 6);
243
244 // set the spacing
245 outInfo->Set(vtkDataObject::SPACING(), this->DataSpacing, 3);
246
247 // set the origin.
248 outInfo->Set(vtkDataObject::ORIGIN(), this->DataOrigin, 3);
249
250 // set the direction.
251 outInfo->Set(vtkDataObject::DIRECTION(), this->DataDirection, 9);
252
253 // set data type
254 vtkDataObject::SetPointDataActiveScalarInfo(
255 outInfo, this->DataScalarType, this->NumberOfScalarComponents);
256 return 1;
257 }
258
259 //------------------------------------------------------------------------------
ExecuteDataWithInformation(vtkDataObject * output,vtkInformation * outInfo)260 void vtkImageImport::ExecuteDataWithInformation(vtkDataObject* output, vtkInformation* outInfo)
261 {
262 // If set, use the callbacks to prepare our input data.
263 this->InvokeExecuteDataCallbacks();
264
265 vtkImageData* data = vtkImageData::SafeDownCast(output);
266 data->SetExtent(0, 0, 0, 0, 0, 0);
267 data->AllocateScalars(outInfo);
268 void* ptr = this->GetImportVoidPointer();
269 vtkIdType size = this->NumberOfScalarComponents;
270 size *= this->DataExtent[1] - this->DataExtent[0] + 1;
271 size *= this->DataExtent[3] - this->DataExtent[2] + 1;
272 size *= this->DataExtent[5] - this->DataExtent[4] + 1;
273
274 data->SetExtent(this->DataExtent);
275 data->GetPointData()->GetScalars()->SetVoidArray(ptr, size, 1);
276 data->GetPointData()->GetScalars()->SetName(this->ScalarArrayName);
277 }
278
279 //------------------------------------------------------------------------------
CopyImportVoidPointer(void * ptr,vtkIdType size)280 void vtkImageImport::CopyImportVoidPointer(void* ptr, vtkIdType size)
281 {
282 unsigned char* mem = new unsigned char[size];
283 memcpy(mem, ptr, size);
284 this->SetImportVoidPointer(mem, 0);
285 }
286
287 //------------------------------------------------------------------------------
SetImportVoidPointer(void * ptr)288 void vtkImageImport::SetImportVoidPointer(void* ptr)
289 {
290 this->SetImportVoidPointer(ptr, 1);
291 }
292
293 //------------------------------------------------------------------------------
SetImportVoidPointer(void * ptr,int save)294 void vtkImageImport::SetImportVoidPointer(void* ptr, int save)
295 {
296 if (ptr != this->ImportVoidPointer)
297 {
298 if ((this->ImportVoidPointer) && (!this->SaveUserArray))
299 {
300 vtkDebugMacro(<< "Deleting the array...");
301 delete[] static_cast<char*>(this->ImportVoidPointer);
302 }
303 else
304 {
305 vtkDebugMacro(<< "Warning, array not deleted, but will point to new array.");
306 }
307 this->Modified();
308 }
309 this->SaveUserArray = save;
310 this->ImportVoidPointer = ptr;
311 }
312
313 //------------------------------------------------------------------------------
InvokePipelineModifiedCallbacks()314 int vtkImageImport::InvokePipelineModifiedCallbacks()
315 {
316 if (this->PipelineModifiedCallback)
317 {
318 int ret;
319 try
320 {
321 ret = (this->PipelineModifiedCallback)(this->CallbackUserData);
322 }
323 catch (std::exception& _e)
324 {
325 vtkErrorMacro(<< "Calling PipelineModifiedCallback: " << _e.what());
326 // if an error occurred, we don't want the pipeline to run again
327 // until the error has been rectified. It can be assumed that
328 // the rectifying actions will set the modified flag.
329 ret = 0;
330 }
331 catch (...)
332 {
333 vtkErrorMacro(<< "Unknown exception.");
334 // same logic as above
335 ret = 0;
336 }
337
338 return ret;
339 }
340 else
341 {
342 // if there's no PipelineModified installed, we return 0
343 return 0;
344 }
345 }
346
347 //------------------------------------------------------------------------------
InvokeUpdateInformationCallbacks()348 void vtkImageImport::InvokeUpdateInformationCallbacks()
349 {
350 if (this->UpdateInformationCallback)
351 {
352 tryCatchMacro((this->UpdateInformationCallback)(this->CallbackUserData),
353 "Calling UpdateInformationCallback: ");
354 }
355
356 if (this->InvokePipelineModifiedCallbacks())
357 {
358 this->Modified();
359 }
360 }
361
362 //------------------------------------------------------------------------------
InvokeExecuteInformationCallbacks()363 void vtkImageImport::InvokeExecuteInformationCallbacks()
364 {
365 if (this->WholeExtentCallback)
366 {
367 tryCatchMacro(this->SetWholeExtent((this->WholeExtentCallback)(this->CallbackUserData)),
368 "Calling WholeExtentCallback: ");
369 }
370 if (this->SpacingCallback)
371 {
372 tryCatchMacro(this->SetDataSpacing((this->SpacingCallback)(this->CallbackUserData)),
373 "Calling SpacingCallback: ");
374 }
375 if (this->OriginCallback)
376 {
377 tryCatchMacro(this->SetDataOrigin((this->OriginCallback)(this->CallbackUserData)),
378 "Calling OriginCallback: ");
379 }
380 if (this->DirectionCallback)
381 {
382 tryCatchMacro(this->SetDataDirection((this->DirectionCallback)(this->CallbackUserData)),
383 "Calling DirectionCallback: ");
384 }
385 if (this->NumberOfComponentsCallback)
386 {
387 tryCatchMacro(
388 this->SetNumberOfScalarComponents((this->NumberOfComponentsCallback)(this->CallbackUserData)),
389 "Calling NumberOfComponentsCallback: ");
390 }
391 if (this->ScalarTypeCallback)
392 {
393 const char* scalarType = "double"; // default
394 tryCatchMacro(scalarType = (this->ScalarTypeCallback)(this->CallbackUserData),
395 "Calling ScalarTypeCallback: ");
396
397 if (strcmp(scalarType, "double") == 0)
398 {
399 this->SetDataScalarType(VTK_DOUBLE);
400 }
401 else if (strcmp(scalarType, "float") == 0)
402 {
403 this->SetDataScalarType(VTK_FLOAT);
404 }
405 else if (strcmp(scalarType, "long") == 0)
406 {
407 this->SetDataScalarType(VTK_LONG);
408 }
409 else if (strcmp(scalarType, "unsigned long") == 0)
410 {
411 this->SetDataScalarType(VTK_UNSIGNED_LONG);
412 }
413 else if (strcmp(scalarType, "int") == 0)
414 {
415 this->SetDataScalarType(VTK_INT);
416 }
417 else if (strcmp(scalarType, "unsigned int") == 0)
418 {
419 this->SetDataScalarType(VTK_UNSIGNED_INT);
420 }
421 else if (strcmp(scalarType, "short") == 0)
422 {
423 this->SetDataScalarType(VTK_SHORT);
424 }
425 else if (strcmp(scalarType, "unsigned short") == 0)
426 {
427 this->SetDataScalarType(VTK_UNSIGNED_SHORT);
428 }
429 else if (strcmp(scalarType, "char") == 0)
430 {
431 this->SetDataScalarType(VTK_CHAR);
432 }
433 else if (strcmp(scalarType, "unsigned char") == 0)
434 {
435 this->SetDataScalarType(VTK_UNSIGNED_CHAR);
436 }
437 else if (strcmp(scalarType, "signed char") == 0)
438 {
439 this->SetDataScalarType(VTK_SIGNED_CHAR);
440 }
441 }
442 }
443
444 //------------------------------------------------------------------------------
InvokeExecuteDataCallbacks()445 void vtkImageImport::InvokeExecuteDataCallbacks()
446 {
447 if (this->UpdateDataCallback)
448 {
449 tryCatchMacro(
450 (this->UpdateDataCallback)(this->CallbackUserData), "Calling UpdateDataCallback: ");
451 }
452 if (this->DataExtentCallback)
453 {
454 tryCatchMacro(this->SetDataExtent((this->DataExtentCallback)(this->CallbackUserData)),
455 "Calling DataExtentCallback: ");
456 }
457 if (this->BufferPointerCallback)
458 {
459 tryCatchMacro(this->SetImportVoidPointer((this->BufferPointerCallback)(this->CallbackUserData)),
460 "Calling BufferPointerCallback: ");
461 }
462 }
463
464 //------------------------------------------------------------------------------
465 // In the past, this class made no distinction between whole extent and
466 // buffered extent, so only SetDataExtent also set the whole extent of
467 // the output. Now, there is a separate SetWholeExtent which should be
468 // called as well.
LegacyCheckWholeExtent()469 void vtkImageImport::LegacyCheckWholeExtent()
470 {
471 // If the WholeExtentCallback is set, this must not be legacy code.
472 if (this->WholeExtentCallback)
473 {
474 return;
475 }
476 int i;
477 // Check whether the whole extent has been set.
478 for (i = 0; i < 6; ++i)
479 {
480 if (this->WholeExtent[i] != 0)
481 {
482 return;
483 }
484 }
485
486 // The whole extent has not been set. Copy it from the data extent
487 // and issue a warning.
488 for (i = 0; i < 6; ++i)
489 {
490 this->WholeExtent[i] = this->DataExtent[i];
491 }
492
493 vtkWarningMacro("\n"
494 "There is a distinction between the whole extent and the buffered\n"
495 "extent of an imported image. Use SetWholeExtent to set the extent\n"
496 "of the entire image. Use SetDataExtent to set the extent of the\n"
497 "portion of the image that is in the buffer set with\n"
498 "SetImportVoidPointer. Both should be called even if the extents are\n"
499 "the same.");
500 }
501