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