Cloned library of VTK-5.0.0 with extra build files for internal package management.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

311 lines
8.7 KiB

2 years ago
/*=========================================================================
Program: Visualization Toolkit
Module: $RCSfile: vtkPNGWriter.cxx,v $
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notice for more information.
=========================================================================*/
#include "vtkPNGWriter.h"
#include "vtkErrorCode.h"
#include "vtkImageData.h"
#include "vtkObjectFactory.h"
#include "vtkUnsignedCharArray.h"
#include "vtk_png.h"
vtkCxxRevisionMacro(vtkPNGWriter, "$Revision: 1.28 $");
vtkStandardNewMacro(vtkPNGWriter);
vtkCxxSetObjectMacro(vtkPNGWriter,Result,vtkUnsignedCharArray);
vtkPNGWriter::vtkPNGWriter()
{
this->FileLowerLeft = 1;
this->FileDimensionality = 2;
this->WriteToMemory = 0;
this->Result = 0;
this->TempFP = 0;
}
vtkPNGWriter::~vtkPNGWriter()
{
if (this->Result)
{
this->Result->Delete();
this->Result = 0;
}
}
//----------------------------------------------------------------------------
// Writes all the data from the input.
void vtkPNGWriter::Write()
{
this->SetErrorCode(vtkErrorCode::NoError);
// Error checking
if ( this->GetInput() == NULL )
{
vtkErrorMacro(<<"Write:Please specify an input!");
return;
}
if (!this->WriteToMemory && !this->FileName && !this->FilePattern)
{
vtkErrorMacro(<<"Write:Please specify either a FileName or a file prefix and pattern");
this->SetErrorCode(vtkErrorCode::NoFileNameError);
return;
}
// Make sure the file name is allocated
this->InternalFileName =
new char[(this->FileName ? strlen(this->FileName) : 1) +
(this->FilePrefix ? strlen(this->FilePrefix) : 1) +
(this->FilePattern ? strlen(this->FilePattern) : 1) + 10];
// Fill in image information.
this->GetInput()->UpdateInformation();
int *wExtent;
wExtent = this->GetInput()->GetWholeExtent();
this->FileNumber = this->GetInput()->GetWholeExtent()[4];
this->MinimumFileNumber = this->MaximumFileNumber = this->FileNumber;
this->FilesDeleted = 0;
this->UpdateProgress(0.0);
// loop over the z axis and write the slices
for (this->FileNumber = wExtent[4]; this->FileNumber <= wExtent[5];
++this->FileNumber)
{
this->MaximumFileNumber = this->FileNumber;
this->GetInput()->SetUpdateExtent(wExtent[0], wExtent[1],
wExtent[2], wExtent[3],
this->FileNumber,
this->FileNumber);
// determine the name
if (this->FileName)
{
sprintf(this->InternalFileName,"%s",this->FileName);
}
else
{
if (this->FilePrefix)
{
sprintf(this->InternalFileName, this->FilePattern,
this->FilePrefix, this->FileNumber);
}
else
{
sprintf(this->InternalFileName, this->FilePattern,this->FileNumber);
}
}
this->GetInput()->UpdateData();
this->WriteSlice(this->GetInput());
if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError)
{
this->DeleteFiles();
break;
}
this->UpdateProgress((this->FileNumber - wExtent[4])/
(wExtent[5] - wExtent[4] + 1.0));
}
delete [] this->InternalFileName;
this->InternalFileName = NULL;
}
extern "C"
{
void vtkPNGWriteInit(png_structp png_ptr, png_bytep data,
png_size_t sizeToWrite)
{
vtkPNGWriter *self =
vtkPNGWriter::SafeDownCast(static_cast<vtkObject *>
(png_get_io_ptr(png_ptr)));
if (self)
{
vtkUnsignedCharArray *uc = self->GetResult();
// write to the uc array
unsigned char *ptr = uc->WritePointer(uc->GetMaxId()+1,sizeToWrite);
memcpy(ptr, data, sizeToWrite);
}
}
}
extern "C"
{
void vtkPNGWriteFlush(png_structp vtkNotUsed(png_ptr))
{
}
}
extern "C"
{
/* The PNG library does not expect the error function to return.
Therefore we must use this ugly longjmp call. */
void vtkPNGWriteErrorFunction(png_structp png_ptr,
png_const_charp vtkNotUsed(error_msg))
{
longjmp(png_ptr->jmpbuf, 1);
}
}
extern "C"
{
void vtkPNGWriteWarningFunction(png_structp vtkNotUsed(png_ptr),
png_const_charp vtkNotUsed(warning_msg))
{
}
}
// we disable this warning because even though this is a C++ file, between
// the setjmp and resulting longjmp there should not be any C++ constructors
// or destructors.
#if defined(_MSC_VER) && !defined(VTK_DISPLAY_WIN32_WARNINGS)
#pragma warning ( disable : 4611 )
#endif
void vtkPNGWriter::WriteSlice(vtkImageData *data)
{
// Call the correct templated function for the output
unsigned int ui;
// Call the correct templated function for the input
if (data->GetScalarType() != VTK_UNSIGNED_SHORT &&
data->GetScalarType() != VTK_UNSIGNED_CHAR)
{
vtkWarningMacro("PNGWriter only supports unsigned char and unsigned short inputs");
return;
}
png_structp png_ptr = png_create_write_struct
(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, NULL, NULL);
if (!png_ptr)
{
vtkErrorMacro(<<"Unable to write PNG file!");
return;
}
png_infop info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr)
{
png_destroy_write_struct(&png_ptr,
(png_infopp)NULL);
vtkErrorMacro(<<"Unable to write PNG file!");
return;
}
this->TempFP = 0;
if (this->WriteToMemory)
{
vtkUnsignedCharArray *uc = this->GetResult();
if (!uc || uc->GetReferenceCount() > 1)
{
uc = vtkUnsignedCharArray::New();
this->SetResult(uc);
uc->Delete();
}
// start out with 10K as a guess for the image size
uc->Allocate(10000);
png_set_write_fn(png_ptr, static_cast<png_voidp>(this),
vtkPNGWriteInit, vtkPNGWriteFlush);
}
else
{
this->TempFP = fopen(this->InternalFileName, "wb");
if (!this->TempFP)
{
vtkErrorMacro("Unable to open file " << this->InternalFileName);
this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
return;
}
png_init_io(png_ptr, this->TempFP);
png_set_error_fn(png_ptr, png_ptr,
vtkPNGWriteErrorFunction, vtkPNGWriteWarningFunction);
if (setjmp(png_ptr->jmpbuf))
{
fclose(this->TempFP);
this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
return;
}
}
int *uExtent = data->GetUpdateExtent();
void *outPtr;
outPtr = data->GetScalarPointer(uExtent[0], uExtent[2], uExtent[4]);
png_uint_32 width, height;
width = uExtent[1] - uExtent[0] + 1;
height = uExtent[3] - uExtent[2] + 1;
int bit_depth = 8;
if (data->GetScalarType() == VTK_UNSIGNED_SHORT)
{
bit_depth = 16;
}
int color_type;
switch (data->GetNumberOfScalarComponents())
{
case 1: color_type = PNG_COLOR_TYPE_GRAY;
break;
case 2: color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
break;
case 3: color_type = PNG_COLOR_TYPE_RGB;
break;
default: color_type = PNG_COLOR_TYPE_RGB_ALPHA;
break;
}
png_set_IHDR(png_ptr, info_ptr, width, height,
bit_depth, color_type, PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT);
// interlace_type - PNG_INTERLACE_NONE or
// PNG_INTERLACE_ADAM7
png_write_info(png_ptr, info_ptr);
// default is big endian
if (bit_depth > 8)
{
#ifndef VTK_WORDS_BIGENDIAN
png_set_swap(png_ptr);
#endif
}
png_byte **row_pointers = new png_byte *[height];
vtkIdType *outInc = data->GetIncrements();
vtkIdType rowInc = outInc[1]*bit_depth/8;
for (ui = 0; ui < height; ui++)
{
row_pointers[height - ui - 1] = (png_byte *)outPtr;
outPtr = (unsigned char *)outPtr + rowInc;
}
png_write_image(png_ptr, row_pointers);
png_write_end(png_ptr, info_ptr);
delete [] row_pointers;
png_destroy_write_struct(&png_ptr, &info_ptr);
if (this->TempFP)
{
fflush(this->TempFP);
if (ferror(this->TempFP))
{
this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
}
}
if (this->TempFP)
{
fclose(this->TempFP);
}
}
void vtkPNGWriter::PrintSelf(ostream& os, vtkIndent indent)
{
this->Superclass::PrintSelf(os,indent);
os << indent << "Result: " << this->Result << "\n";
os << indent << "WriteToMemory: " << (this->WriteToMemory ? "On" : "Off") << "\n";
}