diff --git a/Utilities/ITK/Utilities/DICOMParser/CMakeLists.txt b/Utilities/ITK/Utilities/DICOMParser/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..8e3cdb107e578096c2464ddd6ab31eb9b9f0095b --- /dev/null +++ b/Utilities/ITK/Utilities/DICOMParser/CMakeLists.txt @@ -0,0 +1,62 @@ +# The DICOMParser Library is intended to be included in other +# projects. The library's namespace and library name can be +# configured. + +# Typical usage is to import the DICOMParser directory tree into a +# subdirectory under a parent project and enable the library be used. +# The CMake listfile above this one configures the library as follows: +# +# SET(DICOMPARSER_NAMESPACE foodicomparser) +# SET(DICOMPARSER_LIBRARY foodicomparser) +# SUBDIRS(DICOMParser) +# + +#----------------------------------------------------------------------------- +# If a namespace is not specified, use "dicomparser". This should be +# the case only when dicom is not included inside another project +# +IF(NOT DICOMPARSER_NAMESPACE) + SET(DICOMPARSER_NAMESPACE dicomparser) + SET(DICOMPARSER_LIBRARY dicomparser) + SET(DICOMPARSER_STANDALONE 1) +ENDIF(NOT DICOMPARSER_NAMESPACE) + + +#----------------------------------------------------------------------------- +# The project name is that of the specified namespace. +PROJECT(${DICOMPARSER_NAMESPACE}) + +# Put the binary tree first in the include path to protect against +# when people accidently configure in their source tree +INCLUDE_DIRECTORIES(${PROJECT_BINARY_DIR}) +INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}) + +IF(WIN32) + IF(BUILD_SHARED_LIBS) + SET(DICOM_DLL 1) + ELSE(BUILD_SHARED_LIBS) + SET(DICOM_STATIC 1) + ENDIF(BUILD_SHARED_LIBS) +ENDIF(WIN32) + +IF(ITK_SOURCE_DIR) + # Inside ITK, use its setting. + SET(DICOM_ANSI_STDLIB 1) +ELSE(ITK_SOURCE_DIR) + # Not inside ITK, use ANSI streams. + SET(DICOM_ANSI_STDLIB 1) +ENDIF(ITK_SOURCE_DIR) + +INCLUDE(${CMAKE_ROOT}/Modules/TestForSTDNamespace.cmake) +SET(DICOM_NO_STD_NAMESPACE ${CMAKE_NO_STD_NAMESPACE}) + + +CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/DICOMCMakeConfig.h.in + ${PROJECT_BINARY_DIR}/DICOMCMakeConfig.h) + +ADD_LIBRARY(${DICOMPARSER_LIBRARY} DICOMSource.cxx DICOMBuffer.cxx DICOMFile.cxx DICOMParser.cxx DICOMAppHelper.cxx) + +INSTALL_TARGETS(/lib/InsightToolkit ${DICOMPARSER_LIBRARY}) +INSTALL_FILES(/include/InsightToolkit "(\\.h|\\.txx)$") +INSTALL_FILES(/include/InsightToolkit FILES + ${PROJECT_BINARY_DIR}/DICOMCMakeConfig.h) diff --git a/Utilities/ITK/Utilities/DICOMParser/Copyright.txt b/Utilities/ITK/Utilities/DICOMParser/Copyright.txt new file mode 100644 index 0000000000000000000000000000000000000000..8499456e49ad238040405a9f9ae0b42e9b4c544a --- /dev/null +++ b/Utilities/ITK/Utilities/DICOMParser/Copyright.txt @@ -0,0 +1,41 @@ +/*========================================================================= + + Program: DICOMParser + Module: $RCSfile: Copyright.txt,v $ + Language: C++ + Date: $Date: 2003/10/23 17:42:13 $ + Version: $Revision: 1.1 $ + + +Copyright (c) 2003 Matt Turek +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * The name of Matt Turek nor the names of any contributors may be used to + endorse or promote products derived from this software without specific + prior written permission. + + * Modified source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +=========================================================================*/ diff --git a/Utilities/ITK/Utilities/DICOMParser/DICOMAppHelper.cxx b/Utilities/ITK/Utilities/DICOMParser/DICOMAppHelper.cxx new file mode 100644 index 0000000000000000000000000000000000000000..1091865b9e64a1bf388a2aebf15eef3abc263cbf --- /dev/null +++ b/Utilities/ITK/Utilities/DICOMParser/DICOMAppHelper.cxx @@ -0,0 +1,2446 @@ +/*========================================================================= + + Program: DICOMParser + Module: $RCSfile: DICOMAppHelper.cxx,v $ + Language: C++ + Date: $Date: 2005/03/15 17:00:37 $ + Version: $Revision: 1.72 $ + + Copyright (c) 2003 Matt Turek + All rights reserved. + See Copyright.txt 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. + +=========================================================================*/ + +#ifdef _MSC_VER +#pragma warning ( disable : 4514 ) +#pragma warning ( disable : 4786 ) +#pragma warning ( disable : 4503 ) +#pragma warning ( disable : 4710 ) +#pragma warning ( disable : 4702 ) +#pragma warning ( push, 3 ) +#endif + +#include "DICOMConfig.h" +#include "DICOMAppHelper.h" +#include "DICOMCallback.h" + +#include <stdlib.h> +#include <stdio.h> +#include <string> +#include <math.h> +#include <algorithm> + +namespace DICOMPARSER_NAMESPACE +{ +//#define DEBUG_DICOM_APP_HELPER + +class DICOMAppHelperImplementation +{ +public: + // map from series UID to vector of instance UIDs in the series + typedef dicom_stl::map<dicom_stl::string, dicom_stl::vector<dicom_stl::string>, ltstdstr> SeriesUIDToInstanceUIDMapType; + SeriesUIDToInstanceUIDMapType SeriesUIDToInstanceUIDMap; + + // map from a series Description to an instance UID + typedef dicom_stl::map<dicom_stl::string, dicom_stl::string, ltstdstr> SeriesUIDToSeriesDescriptionMapType; + SeriesUIDToSeriesDescriptionMapType SeriesUIDToSeriesDescriptionMap; + + // map from a series body part to an instance UID + typedef dicom_stl::map<dicom_stl::string, dicom_stl::string, ltstdstr> SeriesUIDToBodyPartMapType; + SeriesUIDToBodyPartMapType SeriesUIDToBodyPartMap; + + // map from a series scan option to an instance UID + typedef dicom_stl::map<dicom_stl::string, dicom_stl::string, ltstdstr> SeriesUIDToScanOptionsMapType; + SeriesUIDToScanOptionsMapType SeriesUIDToScanOptionsMap; + + // map from an instance UID to a series UID + typedef dicom_stl::map<dicom_stl::string, dicom_stl::string, ltstdstr> InstanceUIDToSeriesUIDMapType; + InstanceUIDToSeriesUIDMapType InstanceUIDToSeriesUIDMap; + + // map from an instance UID to a filename + typedef dicom_stl::map<dicom_stl::string, dicom_stl::string, ltstdstr> InstanceUIDToFileNameMapType; + InstanceUIDToFileNameMapType InstanceUIDToFileNameMap; + + // map from instance UID to intraseries sortable tags + typedef dicom_stl::map<dicom_stl::string, DICOMOrderingElements, ltstdstr> InstanceUIDToSliceOrderingMapType; + InstanceUIDToSliceOrderingMapType InstanceUIDToSliceOrderingMap; + + // map for (group, element) to tag info + typedef dicom_stl::map<dicom_stl::pair<doublebyte, doublebyte>, DICOMTagInfo> TagMapType; + TagMapType TagMap; + + // data structure for a contour (store points as x,y,z,x,y,z,...) + // Do we want to have different contour types? POINT, OPEN_PLANAR, CLOSED_PLANAR + typedef dicom_stl::vector<float> ContourType; + + // vector of contours + typedef dicom_stl::vector<ContourType> ContoursVectorType; + + // map from series UID to vector of contours in that series + typedef dicom_stl::map<dicom_stl::string, ContoursVectorType, ltstdstr> SeriesUIDToContoursMapType; + SeriesUIDToContoursMapType SeriesUIDToContoursMap; + + // vector of instance UIDs + typedef dicom_stl::vector<dicom_stl::string> InstanceUIDVectorType; + + // map from series UID to referenced instance uid + typedef dicom_stl::map<dicom_stl::string, InstanceUIDVectorType, ltstdstr> SeriesUIDToReferencedInstanceUIDMapType; + SeriesUIDToReferencedInstanceUIDMapType SeriesUIDToReferencedInstanceUIDMap; +}; + + +struct lt_pair_int_string +{ + bool operator()(const dicom_stl::pair<int, dicom_stl::string> s1, + const dicom_stl::pair<int, dicom_stl::string> s2) const + { + return s1.first < s2.first; + } +}; + + +struct lt_pair_float_string +{ + bool operator()(const dicom_stl::pair<float, dicom_stl::string> s1, + const dicom_stl::pair<float, dicom_stl::string> s2) const + { + return s1.first < s2.first; + } +}; + + +struct gt_pair_int_string +{ + bool operator()(const dicom_stl::pair<int, dicom_stl::string> s1, + const dicom_stl::pair<int, dicom_stl::string> s2) const + { + return s1.first > s2.first; + } +}; + + +struct gt_pair_float_string +{ + bool operator()(const dicom_stl::pair<float, dicom_stl::string> s1, + const dicom_stl::pair<float, dicom_stl::string> s2) const + { + return s1.first > s2.first; + } +}; + + +DICOMAppHelper::DICOMAppHelper() +{ + this->FileCount = 0; + this->BitsAllocated = 8; + this->ByteSwapData = false; + this->PixelSpacing[0] = this->PixelSpacing[1] = this->PixelSpacing[2] = 1.0; + this->Dimensions[0] = this->Dimensions[1] = 0; + this->Width = this->Height = 0; + this->PhotometricInterpretation = NULL; + this->TransferSyntaxUID = NULL; + this->CurrentSeriesUID = ""; + this->InstanceUID = ""; + this->RescaleOffset = 0.0; + this->RescaleSlope = 1.0; + this->ImageData = NULL; + this->ImageDataLengthInBytes = 0; + + // Initialize the arrays + m_NumberOfSeriesInStudy[0]='\0'; + m_PatientName[0]='\0'; + m_PatientID[0]='\0'; + m_PatientDOB[0]='\0'; + m_StudyID[0]='\0'; + m_StudyDescription[0]='\0'; + m_BodyPart[0]='\0'; + m_NumberOfSeriesInStudy[0]='\0'; + m_NumberOfStudyRelatedSeries[0]='\0'; + m_PatientSex[0]='\0'; + m_PatientAge[0]='\0'; + m_StudyDate[0]='\0'; + m_Modality[0]='\0'; + m_Manufacturer[0]='\0'; + m_Institution[0]='\0'; + m_Model[0]='\0'; + m_ScanOptions[0]='\0'; + + + this->SeriesUIDCB = new DICOMMemberCallback<DICOMAppHelper>; + this->SeriesDescriptionCB = new DICOMMemberCallback<DICOMAppHelper>; + this->InstanceUIDCB = new DICOMMemberCallback<DICOMAppHelper>; + this->SliceNumberCB = new DICOMMemberCallback<DICOMAppHelper>; + this->SliceLocationCB = new DICOMMemberCallback<DICOMAppHelper>; + this->ImagePositionPatientCB = new DICOMMemberCallback<DICOMAppHelper>; + this->ImageOrientationPatientCB = new DICOMMemberCallback<DICOMAppHelper>; + this->TransferSyntaxCB = new DICOMMemberCallback<DICOMAppHelper>; + this->ToggleSwapBytesCB = new DICOMMemberCallback<DICOMAppHelper>; + this->BitsAllocatedCB = new DICOMMemberCallback<DICOMAppHelper>; + this->PixelSpacingCB = new DICOMMemberCallback<DICOMAppHelper>; + this->HeightCB = new DICOMMemberCallback<DICOMAppHelper>; + this->WidthCB = new DICOMMemberCallback<DICOMAppHelper>; + this->PixelRepresentationCB = new DICOMMemberCallback<DICOMAppHelper>; + this->PhotometricInterpretationCB = new DICOMMemberCallback<DICOMAppHelper>; + this->RescaleOffsetCB = new DICOMMemberCallback<DICOMAppHelper>; + this->RescaleSlopeCB = new DICOMMemberCallback<DICOMAppHelper>; + this->PixelDataCB = new DICOMMemberCallback<DICOMAppHelper>; + this->ROIContourSequenceCB = new DICOMMemberCallback<DICOMAppHelper>; + this->ContourImageSequenceCB = new DICOMMemberCallback<DICOMAppHelper>; + this->ContourSequenceCB = new DICOMMemberCallback<DICOMAppHelper>; + this->ContourDataCB = new DICOMMemberCallback<DICOMAppHelper>; + this->NumberOfContourPointsCB = new DICOMMemberCallback<DICOMAppHelper>; + this->ContourGeometricTypeCB = new DICOMMemberCallback<DICOMAppHelper>; + this->ReferencedInstanceUIDCB = new DICOMMemberCallback<DICOMAppHelper>; + this->PatientNameCB = new DICOMMemberCallback<DICOMAppHelper>; + this->PatientIDCB = new DICOMMemberCallback<DICOMAppHelper>; + this->PatientSexCB = new DICOMMemberCallback<DICOMAppHelper>; + this->PatientAgeCB = new DICOMMemberCallback<DICOMAppHelper>; + this->PatientDOBCB = new DICOMMemberCallback<DICOMAppHelper>; + this->StudyIDCB = new DICOMMemberCallback<DICOMAppHelper>; + this->StudyDescriptionCB = new DICOMMemberCallback<DICOMAppHelper>; + this->BodyPartCB = new DICOMMemberCallback<DICOMAppHelper>; + this->NumberOfSeriesInStudyCB = new DICOMMemberCallback<DICOMAppHelper>; + this->NumberOfStudyRelatedSeriesCB = new DICOMMemberCallback<DICOMAppHelper>; + this->StudyDateCB = new DICOMMemberCallback<DICOMAppHelper>; + this->ModalityCB = new DICOMMemberCallback<DICOMAppHelper>; + this->ManufacturerCB = new DICOMMemberCallback<DICOMAppHelper>; + this->InstitutionCB = new DICOMMemberCallback<DICOMAppHelper>; + this->ModelCB = new DICOMMemberCallback<DICOMAppHelper>; + this->ScanOptionsCB = new DICOMMemberCallback<DICOMAppHelper>; + this->DefaultCB = new DICOMMemberCallback<DICOMAppHelper>; + + this->Implementation = new DICOMAppHelperImplementation; +} + +DICOMAppHelper::~DICOMAppHelper() +{ + this->Clear(); + + this->HeaderFile.close(); + + // + // Fix warning here. + // + if (this->ImageData) + { + delete [] (static_cast<char*> (this->ImageData)); + } + if (this->TransferSyntaxUID) + { + delete this->TransferSyntaxUID; + } + if (this->PhotometricInterpretation) + { + delete this->PhotometricInterpretation; + } + + delete this->SeriesUIDCB; + delete this->SeriesDescriptionCB; + delete this->InstanceUIDCB; + delete this->SliceNumberCB; + delete this->SliceLocationCB; + delete this->ImagePositionPatientCB; + delete this->ImageOrientationPatientCB; + delete this->TransferSyntaxCB; + delete this->ToggleSwapBytesCB; + delete this->BitsAllocatedCB; + delete this->PixelSpacingCB; + delete this->HeightCB; + delete this->WidthCB; + delete this->PixelRepresentationCB; + delete this->PhotometricInterpretationCB; + delete this->RescaleOffsetCB; + delete this->RescaleSlopeCB; + delete this->PixelDataCB; + delete this->ROIContourSequenceCB; + delete this->ContourImageSequenceCB; + delete this->ContourSequenceCB; + delete this->ContourDataCB; + delete this->NumberOfContourPointsCB; + delete this->ContourGeometricTypeCB; + delete this->ReferencedInstanceUIDCB; + delete this->PatientNameCB; + delete this->PatientIDCB; + delete this->PatientSexCB; + delete this->PatientAgeCB; + delete this->PatientDOBCB; + delete this->StudyIDCB; + delete this->StudyDescriptionCB; + delete this->BodyPartCB; + delete this->NumberOfSeriesInStudyCB; + delete this->NumberOfStudyRelatedSeriesCB; + delete this->StudyDateCB; + delete this->ModalityCB; + delete this->ManufacturerCB; + delete this->InstitutionCB; + delete this->ModelCB; + delete this->ScanOptionsCB; + + delete this->DefaultCB; + + delete this->Implementation; +} + +void DICOMAppHelper::RegisterCallbacks(DICOMParser* parser) +{ + if (!parser) + { + dicom_stream::cerr << "Null parser!" << dicom_stream::endl; + } + + // Default callback. Typically used to register a callback for + // sequences where we are not interested in the sequence itself but + // an element within the sequence. + DefaultCB->SetCallbackFunction(this, &DICOMAppHelper::DefaultCallback); + + // + // + // + SeriesUIDCB->SetCallbackFunction(this, &DICOMAppHelper::SeriesUIDCallback); + parser->AddDICOMTagCallback(0x0020, 0x000e, DICOMParser::VR_UI, SeriesUIDCB); + + InstanceUIDCB->SetCallbackFunction(this, &DICOMAppHelper::InstanceUIDCallback); + parser->AddDICOMTagCallback(0x0008, 0x0018, DICOMParser::VR_UI, InstanceUIDCB); + + SeriesDescriptionCB->SetCallbackFunction(this, &DICOMAppHelper::SeriesDescriptionCallback); + parser->AddDICOMTagCallback(0x0008, 0x103e, DICOMParser::VR_LO, SeriesDescriptionCB); + + SliceNumberCB->SetCallbackFunction(this, &DICOMAppHelper::SliceNumberCallback); + parser->AddDICOMTagCallback(0x0020, 0x0013, DICOMParser::VR_IS, SliceNumberCB); + + SliceLocationCB->SetCallbackFunction(this, &DICOMAppHelper::SliceLocationCallback); + parser->AddDICOMTagCallback(0x0020, 0x1041, DICOMParser::VR_DS, SliceLocationCB); + + ImagePositionPatientCB->SetCallbackFunction(this, &DICOMAppHelper::ImagePositionPatientCallback); + parser->AddDICOMTagCallback(0x0020, 0x0032, DICOMParser::VR_SH, ImagePositionPatientCB); + + ImageOrientationPatientCB->SetCallbackFunction(this, &DICOMAppHelper::ImageOrientationPatientCallback); + parser->AddDICOMTagCallback(0x0020, 0x0037, DICOMParser::VR_SH, ImageOrientationPatientCB); + + TransferSyntaxCB->SetCallbackFunction(this, &DICOMAppHelper::TransferSyntaxCallback); + parser->AddDICOMTagCallback(0x0002, 0x0010, DICOMParser::VR_UI, TransferSyntaxCB); + + ToggleSwapBytesCB->SetCallbackFunction(this, &DICOMAppHelper::ToggleSwapBytesCallback); + + BitsAllocatedCB->SetCallbackFunction(this, &DICOMAppHelper::BitsAllocatedCallback); + parser->AddDICOMTagCallback(0x0028, 0x0100, DICOMParser::VR_US, BitsAllocatedCB); + + PixelSpacingCB->SetCallbackFunction(this, &DICOMAppHelper::PixelSpacingCallback); + parser->AddDICOMTagCallback(0x0028, 0x0030, DICOMParser::VR_FL, PixelSpacingCB); + parser->AddDICOMTagCallback(0x0018, 0x0050, DICOMParser::VR_FL, PixelSpacingCB); + + WidthCB->SetCallbackFunction(this, &DICOMAppHelper::WidthCallback); + parser->AddDICOMTagCallback(0x0028, 0x0011, DICOMParser::VR_US, WidthCB); + + HeightCB->SetCallbackFunction(this, &DICOMAppHelper::HeightCallback); + parser->AddDICOMTagCallback(0x0028, 0x0010, DICOMParser::VR_US, HeightCB); + + PixelRepresentationCB->SetCallbackFunction(this, &DICOMAppHelper::PixelRepresentationCallback); + parser->AddDICOMTagCallback(0x0028, 0x0103, DICOMParser::VR_US, PixelRepresentationCB); + + PhotometricInterpretationCB->SetCallbackFunction(this, &DICOMAppHelper::PhotometricInterpretationCallback); + parser->AddDICOMTagCallback(0x0028, 0x0004, DICOMParser::VR_CS, PhotometricInterpretationCB); + + RescaleOffsetCB->SetCallbackFunction(this, &DICOMAppHelper::RescaleOffsetCallback); + parser->AddDICOMTagCallback(0x0028, 0x1052, DICOMParser::VR_DS, RescaleOffsetCB); + + RescaleSlopeCB->SetCallbackFunction(this, &DICOMAppHelper::RescaleSlopeCallback); + parser->AddDICOMTagCallback(0x0028, 0x1053, DICOMParser::VR_DS, RescaleSlopeCB); + + ROIContourSequenceCB->SetCallbackFunction(this, &DICOMAppHelper::ROIContourSequenceCallback); + parser->AddDICOMTagCallback(0x3006, 0x0039, DICOMParser::VR_SQ, ROIContourSequenceCB); + + ContourSequenceCB->SetCallbackFunction(this, &DICOMAppHelper::ContourSequenceCallback); + parser->AddDICOMTagCallback(0x3006, 0x0040, DICOMParser::VR_SQ, ContourSequenceCB); + + ContourGeometricTypeCB->SetCallbackFunction(this, &DICOMAppHelper::ContourGeometricTypeCallback); + parser->AddDICOMTagCallback(0x3006, 0x0042, DICOMParser::VR_CS, ContourGeometricTypeCB); + + NumberOfContourPointsCB->SetCallbackFunction(this, &DICOMAppHelper::NumberOfContourPointsCallback); + parser->AddDICOMTagCallback(0x3006, 0x0046, DICOMParser::VR_IS, NumberOfContourPointsCB); + + ContourDataCB->SetCallbackFunction(this, &DICOMAppHelper::ContourDataCallback); + parser->AddDICOMTagCallback(0x3006, 0x0050, DICOMParser::VR_DS, ContourDataCB); + + ContourImageSequenceCB->SetCallbackFunction(this, &DICOMAppHelper::ContourImageSequenceCallback); + parser->AddDICOMTagCallback(0x3006, 0x0016, DICOMParser::VR_SQ, ContourImageSequenceCB); + + ReferencedInstanceUIDCB->SetCallbackFunction(this, &DICOMAppHelper::ReferencedInstanceUIDCallback); + parser->AddDICOMTagCallback(0x0008, 0x1155, DICOMParser::VR_UI, ReferencedInstanceUIDCB); + + PatientNameCB->SetCallbackFunction(this, &DICOMAppHelper::PatientNameCallback); + parser->AddDICOMTagCallback(0x0010, 0x0010, DICOMParser::VR_PN, PatientNameCB); + + PatientIDCB->SetCallbackFunction(this, &DICOMAppHelper::PatientIDCallback); + parser->AddDICOMTagCallback(0x0010, 0x0020, DICOMParser::VR_LO, PatientIDCB); + + PatientSexCB->SetCallbackFunction(this, &DICOMAppHelper::PatientSexCallback); + parser->AddDICOMTagCallback(0x0010, 0x0040, DICOMParser::VR_CS, PatientSexCB); + + PatientAgeCB->SetCallbackFunction(this, &DICOMAppHelper::PatientAgeCallback); + parser->AddDICOMTagCallback(0x0010, 0x1010, DICOMParser::VR_AS, PatientAgeCB); + + PatientDOBCB->SetCallbackFunction(this, &DICOMAppHelper::PatientDOBCallback); + parser->AddDICOMTagCallback(0x0010, 0x0030, DICOMParser::VR_DA, PatientDOBCB); + + StudyIDCB->SetCallbackFunction(this, &DICOMAppHelper::StudyIDCallback); + parser->AddDICOMTagCallback(0x0020, 0x0010, DICOMParser::VR_SH, StudyIDCB); + + StudyDescriptionCB->SetCallbackFunction(this, &DICOMAppHelper::StudyDescriptionCallback); + parser->AddDICOMTagCallback(0x0008, 0x1030, DICOMParser::VR_LO, StudyDescriptionCB); + + BodyPartCB->SetCallbackFunction(this, &DICOMAppHelper::BodyPartCallback); + parser->AddDICOMTagCallback(0x0018, 0x0015, DICOMParser::VR_CS, BodyPartCB); + + NumberOfSeriesInStudyCB->SetCallbackFunction(this, &DICOMAppHelper::NumberOfSeriesInStudyCallback); + parser->AddDICOMTagCallback(0x0020, 0x1000, DICOMParser::VR_IS, NumberOfSeriesInStudyCB); + + NumberOfStudyRelatedSeriesCB->SetCallbackFunction(this, &DICOMAppHelper::NumberOfStudyRelatedSeriesCallback); + parser->AddDICOMTagCallback(0x0020, 0x1206, DICOMParser::VR_IS, NumberOfStudyRelatedSeriesCB); + + StudyDateCB->SetCallbackFunction(this, &DICOMAppHelper::StudyDateCallback); + parser->AddDICOMTagCallback(0x0008, 0x0020, DICOMParser::VR_DA, StudyDateCB); + + ModalityCB->SetCallbackFunction(this, &DICOMAppHelper::ModalityCallback); + parser->AddDICOMTagCallback(0x0008, 0x0060, DICOMParser::VR_CS, ModalityCB); + + ManufacturerCB->SetCallbackFunction(this, &DICOMAppHelper::ManufacturerCallback); + parser->AddDICOMTagCallback(0x0008, 0x0070, DICOMParser::VR_LO, ManufacturerCB); + + InstitutionCB->SetCallbackFunction(this, &DICOMAppHelper::InstitutionCallback); + parser->AddDICOMTagCallback(0x0008, 0x0080, DICOMParser::VR_LO, InstitutionCB); + + ModelCB->SetCallbackFunction(this, &DICOMAppHelper::ModelCallback); + parser->AddDICOMTagCallback(0x0008, 0x1090, DICOMParser::VR_LO, ModelCB); + + ScanOptionsCB->SetCallbackFunction(this, &DICOMAppHelper::ScanOptionsCallback); + parser->AddDICOMTagCallback(0x0018, 0x0022, DICOMParser::VR_CS, ScanOptionsCB); + + // Add in default callbacks for tags we need to see but not cache + //parser->AddDICOMTagCallback(0x3006, 0x0012, DICOMParser::VR_DS, DefaultCB); + DICOMTagInfo dicom_tags[] = { + {0x0002, 0x0002, DICOMParser::VR_UI, "Media storage SOP class uid"}, + {0x0002, 0x0003, DICOMParser::VR_UI, "Media storage SOP inst uid"}, + {0x0002, 0x0010, DICOMParser::VR_UI, "Transfer syntax uid"}, + {0x0002, 0x0012, DICOMParser::VR_UI, "Implementation class uid"}, + {0x0008, 0x0018, DICOMParser::VR_UI, "Image UID"}, + {0x0008, 0x0020, DICOMParser::VR_DA, "Series date"}, + {0x0008, 0x0030, DICOMParser::VR_TM, "Series time"}, + {0x0008, 0x0060, DICOMParser::VR_SH, "Modality"}, + {0x0008, 0x0070, DICOMParser::VR_SH, "Manufacturer"}, + {0x0008, 0x0080, DICOMParser::VR_LO, "Institution"}, + {0x0008, 0x1060, DICOMParser::VR_SH, "Physician"}, + {0x0008, 0x1090, DICOMParser::VR_LO, "Model"}, + {0x0008, 0x103E, DICOMParser::VR_LO, "Series description"}, + {0x0010, 0x0010, DICOMParser::VR_PN, "Patient name"}, + {0x0010, 0x0020, DICOMParser::VR_LO, "Patient ID"}, + {0x0010, 0x0040, DICOMParser::VR_CS, "Patient sex"}, + {0x0010, 0x1010, DICOMParser::VR_AS, "Patient age"}, + {0x0010, 0x0030, DICOMParser::VR_DA, "Patient Date of birth"}, + {0x0020, 0x0010, DICOMParser::VR_SH, "Study ID"}, + {0x0008, 0x1030, DICOMParser::VR_LO, "Study Description"}, + {0x0018, 0x0015, DICOMParser::VR_CS, "Body Part"}, + {0x0020, 0x1000, DICOMParser::VR_IS, "Number of series in study"}, + {0x0020, 0x1206, DICOMParser::VR_IS, "Number of study related series"}, + {0x0018, 0x0022, DICOMParser::VR_FL, "Scan options"}, + {0x0018, 0x0050, DICOMParser::VR_FL, "slice thickness"}, + {0x0018, 0x0060, DICOMParser::VR_FL, "kV"}, + {0x0018, 0x0088, DICOMParser::VR_FL, "slice spacing"}, + {0x0018, 0x1100, DICOMParser::VR_SH, "Recon diameter"}, + {0x0018, 0x1151, DICOMParser::VR_FL, "mA"}, + {0x0018, 0x1210, DICOMParser::VR_SH, "Recon kernel"}, + {0x0020, 0x000d, DICOMParser::VR_UI, "Study UID"}, + {0x0020, 0x000e, DICOMParser::VR_UI, "Series UID"}, + {0x0020, 0x0013, DICOMParser::VR_IS, "Image number"}, + {0x0020, 0x0032, DICOMParser::VR_SH, "Patient position"}, + {0x0020, 0x0037, DICOMParser::VR_SH, "Patient position cosines"}, + {0x0020, 0x1041, DICOMParser::VR_SS, "Slice location"}, + {0x0028, 0x0010, DICOMParser::VR_FL, "Num rows"}, + {0x0028, 0x0011, DICOMParser::VR_FL, "Num cols"}, + {0x0028, 0x0030, DICOMParser::VR_FL, "pixel spacing"}, + {0x0028, 0x0100, DICOMParser::VR_US, "Bits allocated"}, + {0x0028, 0x0120, DICOMParser::VR_UL, "pixel padding"}, + {0x0028, 0x1052, DICOMParser::VR_FL, "pixel offset"}, + {0x3006, 0x0039, DICOMParser::VR_SQ, "ROI Contour Sequence"}, + {0x3006, 0x0040, DICOMParser::VR_SQ, "Contour Sequence"}, + {0x3006, 0x0046, DICOMParser::VR_IS, "Number Of Contour Points"}, + {0x3006, 0x0050, DICOMParser::VR_DS, "Contour Data"} + }; + + int num_tags = sizeof(dicom_tags)/sizeof(DICOMTagInfo); + +#ifdef DEBUG_DICOM_APP_HELPER + DICOMMemberCallback<DICOMAppHelper>** callbackArray = new DICOMMemberCallback<DICOMAppHelper>*[num_tags]; +#endif + + for (int j = 0; j < num_tags; j++) + { + // + // Setup internal map. + // + DICOMTagInfo tagStruct = dicom_tags[j]; + doublebyte group = tagStruct.group; + doublebyte element = tagStruct.element; + + dicom_stl::pair<doublebyte, doublebyte> gePair(group, element); + dicom_stl::pair<const dicom_stl::pair<doublebyte, doublebyte>, DICOMTagInfo> mapPair(gePair, tagStruct); + this->Implementation->TagMap.insert(mapPair); + +#ifdef aDEBUG_DICOM_APP_HELPER + // + // Make callback + // + callbackArray[j] = new DICOMMemberCallback<DICOMAppHelper>; + callbackArray[j]->SetCallbackFunction(this, &DICOMAppHelper::ArrayCallback); + // + // Set callback on parser. + // + parser->AddDICOMTagCallback(group, element,datatype, callbackArray[j]); +#endif + + } + +} + +void DICOMAppHelper::DefaultCallback(DICOMParser *, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char*, + quadbyte) +{ +#ifdef DEBUG_DICOM_APP_HELPER + dicom_stream::cout << "Default callback " << dicom_stream::endl; +#endif +} + +void DICOMAppHelper::InstanceUIDCallback(DICOMParser *parser, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte len) +{ + if (len == 0) + { +#ifdef DEBUG_DICOM_APP_HELPER + dicom_stream::cout << "Instance UID: (EMPTY)" << dicom_stream::endl; +#endif + + // empty the string + this->InstanceUID = dicom_stl::string(); + + // just return, don't bother updating the internal databases of UID's + return; + } + + char* newString = (char*) val; + dicom_stl::string newStdString(newString); + + // An anonymized UID, generate one + if (newStdString == "0.0.0.0") + { + char fakeUID[2048]; + sprintf (fakeUID, "%d.%d.%d.%d", 0, 0, 0, ++this->FileCount); + newStdString = fakeUID; + } + // cache the instance UID + this->InstanceUID = newStdString; + +#ifdef DEBUG_DICOM_APP_HELPER + dicom_stream::cout << "Instance UID: " << newStdString << dicom_stream::endl; +#endif + + // Put the instance UID into the internal database mapping instance UIDs + // to filenames + this->Implementation + ->InstanceUIDToFileNameMap.insert(dicom_stl::pair<const dicom_stl::string, dicom_stl::string>(this->InstanceUID, parser->GetFileName() )); +} + + +void DICOMAppHelper::ReferencedInstanceUIDCallback(DICOMParser *, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte len) +{ + if (len == 0) + { +#ifdef DEBUG_DICOM_APP_HELPER + dicom_stream::cout << "Referenced Instance UID: (EMPTY)" << dicom_stream::endl; +#endif + + // just return, don't bother updating the internal databases of UID's + return; + } + + char* newString = (char*) val; + dicom_stl::string newStdString(newString); + +#ifdef DEBUG_DICOM_APP_HELPER + dicom_stream::cout << "Referenced Instance UID: " << newStdString << dicom_stream::endl; +#endif + + // store the referenced instance UID in the map for this series. + // This vector of referenced instance UIDs should be in lock step + // with the contours + this->Implementation->SeriesUIDToReferencedInstanceUIDMap[this->CurrentSeriesUID].push_back( newStdString ); +} + +void DICOMAppHelper::ContourImageSequenceCallback(DICOMParser *, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char*, + quadbyte) +{ + // Add a contour to the list of contours + DICOMAppHelperImplementation::ContourType contour; + this->Implementation->SeriesUIDToContoursMap[this->CurrentSeriesUID].push_back(contour); + +#ifdef DEBUG_DICOM_APP_HELPER + dicom_stream::cout << "Contour Image Sequence. " << dicom_stream::endl; +#endif +} + +void DICOMAppHelper::SeriesUIDCallback(DICOMParser *, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte len) +{ + if (len == 0) + { +#ifdef DEBUG_DICOM_APP_HELPER + dicom_stream::cout << "Series UID: (EMPTY)" << dicom_stream::endl; +#endif + + // clear the cached series uid + this->CurrentSeriesUID = dicom_stl::string(); + + // just return, don't bother updating the internal databases of UID's + return; + } + + char* newString = (char*) val; + dicom_stl::string newStdString(newString); + + // An anonymized UID, set the the UID to 0.0.0,1 + if (newStdString == "0.0.0.0") + { + char fakeUID[2048]; + sprintf (fakeUID, "%d.%d.%d.%d", 0, 0, 0, 1); + newStdString = fakeUID; + } + +#ifdef DEBUG_DICOM_APP_HELPER + dicom_stream::cout << "Series UID: " << newStdString << dicom_stream::endl; +#endif + + // Put the series UID into the internal database mapping instance + // UIDs to SeriesUIDs + this->Implementation + ->InstanceUIDToSeriesUIDMap.insert(dicom_stl::pair<const dicom_stl::string, dicom_stl::string>(this->InstanceUID, newStdString )); + + // Put the series UID into the internal database mapping series UIDs + // to InstanceUIDs + DICOMAppHelperImplementation::SeriesUIDToInstanceUIDMapType::iterator iiter = this->Implementation->SeriesUIDToInstanceUIDMap.find(newStdString); + if ( iiter == this->Implementation->SeriesUIDToInstanceUIDMap.end()) + { + dicom_stl::vector<dicom_stl::string> newVector; + + newVector.push_back(this->InstanceUID); + this->Implementation->SeriesUIDToInstanceUIDMap.insert(dicom_stl::pair<const dicom_stl::string, dicom_stl::vector<dicom_stl::string> > (newStdString, newVector)); + } + else + { + (*iiter).second.push_back(this->InstanceUID); + } + + // Put the series UID into the internal database mapping series UIDs + // to contours + DICOMAppHelperImplementation::SeriesUIDToContoursMapType::iterator citer = this->Implementation->SeriesUIDToContoursMap.find(newStdString); + if ( citer == this->Implementation->SeriesUIDToContoursMap.end()) + { + DICOMAppHelperImplementation::ContoursVectorType newVector; + + this->Implementation->SeriesUIDToContoursMap.insert(dicom_stl::pair<const dicom_stl::string, DICOMAppHelperImplementation::ContoursVectorType> (newStdString, newVector)); + } + // Put the series UID into the internal database mapping series UIDs + // to referenced instance UIDs + DICOMAppHelperImplementation::SeriesUIDToReferencedInstanceUIDMapType::iterator riter = this->Implementation->SeriesUIDToReferencedInstanceUIDMap.find(newStdString); + if ( riter == this->Implementation->SeriesUIDToReferencedInstanceUIDMap.end()) + { + DICOMAppHelperImplementation::InstanceUIDVectorType newVector; + + this->Implementation->SeriesUIDToReferencedInstanceUIDMap.insert(dicom_stl::pair<const dicom_stl::string, DICOMAppHelperImplementation::InstanceUIDVectorType> (newStdString, newVector)); + } + // cache the current series UID + this->CurrentSeriesUID = newStdString; +} + + +void DICOMAppHelper::SeriesDescriptionCallback(DICOMParser *, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte len ) +{ + if (len == 0) + { +#ifdef DEBUG_DICOM_APP_HELPER + dicom_stream::cout << "Series Description: (EMPTY)" << dicom_stream::endl; +#endif + + // clear the cached series uid + this->CurrentSeriesDescription = dicom_stl::string(); + + // just return, don't bother updating the internal databases of UID's + return; + } + + char* newString = (char*) val; + dicom_stl::string newStdString(newString); + +#ifdef DEBUG_DICOM_APP_HELPER + dicom_stream::cout << "Series Description: " << newStdString << dicom_stream::endl; +#endif + // Put the series description into the internal database mapping series UIDs + // to InstanceUIDs + DICOMAppHelperImplementation::SeriesUIDToSeriesDescriptionMapType::iterator iiter = this->Implementation->SeriesUIDToSeriesDescriptionMap.find(this->CurrentSeriesUID); + if ( iiter == this->Implementation->SeriesUIDToSeriesDescriptionMap.end()) // if not found we insert + { + this->Implementation->SeriesUIDToSeriesDescriptionMap.insert(dicom_stl::pair<const dicom_stl::string, dicom_stl::string> (this->CurrentSeriesUID, newStdString)); + } + this->CurrentSeriesDescription = newStdString; +} + +void DICOMAppHelper::OutputSeries() +{ + dicom_stream::cout << dicom_stream::endl << dicom_stream::endl; + + for (DICOMAppHelperImplementation::SeriesUIDToInstanceUIDMapType::iterator iter = this->Implementation->SeriesUIDToInstanceUIDMap.begin(); + iter != this->Implementation->SeriesUIDToInstanceUIDMap.end(); + iter++) + { + dicom_stream::cout << "SERIES: " << (*iter).first.c_str() << dicom_stream::endl; + dicom_stl::vector<dicom_stl::string>& v_ref = (*iter).second; + + for (dicom_stl::vector<dicom_stl::string>::iterator v_iter = v_ref.begin(); + v_iter != v_ref.end(); + v_iter++) + { + DICOMAppHelperImplementation::InstanceUIDToSliceOrderingMapType::iterator sn_iter = Implementation->InstanceUIDToSliceOrderingMap.find(*v_iter); + + int slice = -1; + if (sn_iter != Implementation->InstanceUIDToSliceOrderingMap.end()) + { + slice = (*sn_iter).second.SliceNumber; + } + dicom_stream::cout << "\t" << (*v_iter).c_str() << " : " + << this->Implementation->InstanceUIDToFileNameMap[*v_iter] << " : "; + if (slice != -1) + { + dicom_stream::cout << " [SliceNumber = " << slice<< "] "; + } + if (this->Implementation->SeriesUIDToContoursMap[(*iter).first].size() != 0) + { + dicom_stream::cout << " [Number of contours = " + << this->Implementation->SeriesUIDToContoursMap[(*iter).first].size() << "] "; + } + dicom_stream::cout << dicom_stream::endl; + } + + } +} + + + + + +void DICOMAppHelper::ArrayCallback(DICOMParser *parser, + doublebyte group, + doublebyte element, + DICOMParser::VRTypes datatype, + unsigned char* val, + quadbyte len) +{ + const char* desc = "No description"; + + TagMapType::iterator iter = this->Implementation->TagMap.find(dicom_stl::pair<doublebyte, doublebyte> (group, element)); + if (iter != this->Implementation->TagMap.end()) + { + desc = (*iter).second.description; + } + + int t2 = int((0x0000FF00 & datatype) >> 8); + int t1 = int((0x000000FF & datatype)); + + char ct2(t2); + char ct1(t1); + + + HeaderFile << "(0x"; + + HeaderFile.width(4); + char prev = HeaderFile.fill('0'); + + HeaderFile << dicom_stream::hex << group; + HeaderFile << ",0x"; + + HeaderFile.width(4); + HeaderFile.fill('0'); + + HeaderFile << dicom_stream::hex << element; + HeaderFile << ") "; + + HeaderFile.fill(prev); + HeaderFile << dicom_stream::dec; + HeaderFile << " " << ct1 << ct2 << " "; + HeaderFile << "[" << len << " bytes] "; + + HeaderFile << desc << " : "; + + unsigned int uival = 0; + float fval = 0; + double dval = 0; + int ival = 0; + + if (val) + { + switch (datatype) + { + case DICOMParser::VR_AE: + case DICOMParser::VR_AS: + case DICOMParser::VR_CS: + case DICOMParser::VR_UI: + case DICOMParser::VR_DA: + case DICOMParser::VR_DS: + case DICOMParser::VR_DT: + case DICOMParser::VR_LO: + case DICOMParser::VR_LT: + case DICOMParser::VR_OB: // ordered bytes + case DICOMParser::VR_OW: // ordered words + case DICOMParser::VR_PN: + case DICOMParser::VR_ST: + case DICOMParser::VR_TM: + case DICOMParser::VR_UN: + case DICOMParser::VR_UT: + case DICOMParser::VR_SQ: // sequence + case DICOMParser::VR_SH: // strings + case DICOMParser::VR_IS: + HeaderFile << val; + break; + case DICOMParser::VR_FL: // float + fval = static_cast<float> (atof((char*) val)); + HeaderFile << fval; + break; + case DICOMParser::VR_FD: // float double + fval = static_cast<float> (atof((char*) val)); + HeaderFile << dval; + break; + case DICOMParser::VR_UL: // unsigned long + case DICOMParser::VR_SL: // signed long + case DICOMParser::VR_AT: + HeaderFile << uival; + break; + //case DICOMParser::VR_IS: + // ival = DICOMFile::ReturnAsSignedLong(val, parser->GetDICOMFile()->GetPlatformIsBigEndian()); + // HeaderFile << ival; + // break; + case DICOMParser::VR_SS: + ival = DICOMFile::ReturnAsSignedShort(val, parser->GetDICOMFile()->GetPlatformIsBigEndian()); + HeaderFile << ival; + break; + case DICOMParser::VR_US: // unsigned short + uival = DICOMFile::ReturnAsUnsignedShort(val, parser->GetDICOMFile()->GetPlatformIsBigEndian()); + HeaderFile << uival; + break; + default: + HeaderFile << val << dicom_stream::endl; + break; + } + } + else + { + HeaderFile << "NULL"; + } + + HeaderFile << dicom_stream::dec << dicom_stream::endl; + HeaderFile.fill(prev); + + delete [] val; +} + +void DICOMAppHelper::SliceNumberCallback(DICOMParser *, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte len) +{ + // Look for the current instance UID in the map of slice ordering data + DICOMAppHelperImplementation::InstanceUIDToSliceOrderingMapType::iterator it; + it = this->Implementation->InstanceUIDToSliceOrderingMap.find( this->InstanceUID ); + if (it == Implementation->InstanceUIDToSliceOrderingMap.end()) + { + // instance UID not found, create a new entry + DICOMOrderingElements ord; + if (len > 0) + { + ord.SliceNumber = atoi( (char *) val); + } + + // insert into the map + this->Implementation->InstanceUIDToSliceOrderingMap.insert(dicom_stl::pair<const dicom_stl::string, DICOMOrderingElements>(this->InstanceUID, ord)); + } + else + { + // file found, add new values + if (len > 0) + { + (*it).second.SliceNumber = atoi( (char *)val ); + } + } + + // cache the slice number + if (len > 0) + { + this->SliceNumber = atoi( (char *) val); + } + else + { + this->SliceNumber = -1; // default to an unset slice number + } +} + + +void DICOMAppHelper::SliceLocationCallback(DICOMParser *, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte len) +{ + // Look for the current instance UID in the map of slice ordering data + DICOMAppHelperImplementation::InstanceUIDToSliceOrderingMapType::iterator it; + it = this->Implementation->InstanceUIDToSliceOrderingMap.find( this->InstanceUID ); + if (it == Implementation->InstanceUIDToSliceOrderingMap.end()) + { + // instance UID not found, create a new entry + DICOMOrderingElements ord; + if (len > 0) + { + ord.SliceLocation = (float)atof( (char *) val); + } + + // insert into the map + this->Implementation->InstanceUIDToSliceOrderingMap.insert(dicom_stl::pair<const dicom_stl::string, DICOMOrderingElements>(this->InstanceUID, ord)); + } + else + { + // file found, add new values + if (len > 0) + { + (*it).second.SliceLocation = (float)atof( (char *)val ); + } + } +} + +void DICOMAppHelper::ImagePositionPatientCallback(DICOMParser *, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte) +{ + // Look for the current instance UID in the map of slice ordering data + DICOMAppHelperImplementation::InstanceUIDToSliceOrderingMapType::iterator it; + it = this->Implementation->InstanceUIDToSliceOrderingMap.find( this->InstanceUID ); + if (it == Implementation->InstanceUIDToSliceOrderingMap.end()) + { + // instance UID not found, create a new entry + DICOMOrderingElements ord; + + if (val) + { + sscanf( (char*)(val), "%f\\%f\\%f", + &ord.ImagePositionPatient[0], + &ord.ImagePositionPatient[1], + &ord.ImagePositionPatient[2] ); + } + else + { + // no actual position specified, default to the origin + ord.ImagePositionPatient[0] = 0.0; + ord.ImagePositionPatient[1] = 0.0; + ord.ImagePositionPatient[2] = 0.0; + } + + // insert into the map + this->Implementation->InstanceUIDToSliceOrderingMap.insert(dicom_stl::pair<const dicom_stl::string, DICOMOrderingElements>(this->InstanceUID, ord)); + + // cache the value + memcpy( this->ImagePositionPatient, ord.ImagePositionPatient, + 3*sizeof(float) ); + } + else + { + if (val) + { + // file found, add new values + sscanf( (char*)(val), "%f\\%f\\%f", + &(*it).second.ImagePositionPatient[0], + &(*it).second.ImagePositionPatient[1], + &(*it).second.ImagePositionPatient[2] ); + } + else + { + // no actual position specified, default to the origin + (*it).second.ImagePositionPatient[0] = 0.0; + (*it).second.ImagePositionPatient[1] = 0.0; + (*it).second.ImagePositionPatient[2] = 0.0; + } + + // cache the value + memcpy( this->ImagePositionPatient, (*it).second.ImagePositionPatient, + 3*sizeof(float) ); + } +} + + +void DICOMAppHelper::ImageOrientationPatientCallback(DICOMParser *, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte) +{ + // Look for the current instance UID in the map of slice ordering data + DICOMAppHelperImplementation::InstanceUIDToSliceOrderingMapType::iterator it; + it = this->Implementation->InstanceUIDToSliceOrderingMap.find(this->InstanceUID); + if (it == Implementation->InstanceUIDToSliceOrderingMap.end()) + { + // instance UID not found, create a new entry + DICOMOrderingElements ord; + if (val) + { + sscanf( (char*)(val), "%f\\%f\\%f\\%f\\%f\\%f", + &ord.ImageOrientationPatient[0], + &ord.ImageOrientationPatient[1], + &ord.ImageOrientationPatient[2], + &ord.ImageOrientationPatient[3], + &ord.ImageOrientationPatient[4], + &ord.ImageOrientationPatient[5] ); + } + else + { + // no orientation defined, default to an standard axial orientation + ord.ImageOrientationPatient[0] = 1.0; + ord.ImageOrientationPatient[1] = 0.0; + ord.ImageOrientationPatient[2] = 0.0; + ord.ImageOrientationPatient[3] = 0.0; + ord.ImageOrientationPatient[4] = 1.0; + ord.ImageOrientationPatient[5] = 0.0; + } + + // insert into the map + this->Implementation->InstanceUIDToSliceOrderingMap.insert(dicom_stl::pair<const dicom_stl::string, DICOMOrderingElements>(this->InstanceUID, ord)); + } + else + { + // file found, add new values + if (val) + { + sscanf( (char*)(val), "%f\\%f\\%f\\%f\\%f\\%f", + &(*it).second.ImageOrientationPatient[0], + &(*it).second.ImageOrientationPatient[1], + &(*it).second.ImageOrientationPatient[2], + &(*it).second.ImageOrientationPatient[3], + &(*it).second.ImageOrientationPatient[4], + &(*it).second.ImageOrientationPatient[5] ); + } + else + { + // no orientation defined, default to an standard axial orientation + (*it).second.ImageOrientationPatient[0] = 1.0; + (*it).second.ImageOrientationPatient[1] = 0.0; + (*it).second.ImageOrientationPatient[2] = 0.0; + (*it).second.ImageOrientationPatient[3] = 0.0; + (*it).second.ImageOrientationPatient[4] = 1.0; + (*it).second.ImageOrientationPatient[5] = 0.0; + } + } +} + + +void DICOMAppHelper::TransferSyntaxCallback(DICOMParser *parser, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte) +{ + +#ifdef DEBUG_DICOM_APP_HELPER +#ifdef WIN32 + char platformByteOrder = 'L'; +#else + char platformByteOrder = 'B'; +#endif + dicom_stream::cout << "Platform byte order: " << platformByteOrder << dicom_stream::endl; +#endif + + static const char* TRANSFER_UID_EXPLICIT_BIG_ENDIAN = "1.2.840.10008.1.2.2"; + + // Only add the ToggleSwapBytes callback when we need it. + if (strcmp(TRANSFER_UID_EXPLICIT_BIG_ENDIAN, (char*) val) == 0) + { + this->ByteSwapData = true; + parser->AddDICOMTagCallback(0x0800, 0x0000, DICOMParser::VR_UNKNOWN, ToggleSwapBytesCB); +#ifdef DEBUG_DICOM_APP_HELPER + dicom_stream::cerr <<"Registering callback for swapping bytes." << dicom_stream::endl; +#endif + } + + if (this->TransferSyntaxUID) + { + delete this->TransferSyntaxUID; + } + this->TransferSyntaxUID = new dicom_stl::string((char*) val); + +#ifdef DEBUG_DICOM_APP_HELPER + dicom_stream::cout << "Transfer Syntax UID: " << *this->TransferSyntaxUID; + dicom_stream::cout << " " << this->TransferSyntaxUIDDescription(this->TransferSyntaxUID->c_str()) << dicom_stream::endl; +#endif +} + +void DICOMAppHelper::BitsAllocatedCallback(DICOMParser *parser, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte len) +{ + if (len == 0) + { + // no value, clear the cached field, return to default BitsAllocated + this->BitsAllocated = 8; + return; + } + + this->BitsAllocated = parser->GetDICOMFile()->ReturnAsUnsignedShort(val, parser->GetDICOMFile()->GetPlatformIsBigEndian()); +#ifdef DEBUG_DICOM_APP_HELPER + dicom_stream::cout << "Bits allocated: " << this->BitsAllocated << dicom_stream::endl; +#endif +} + + +void DICOMAppHelper::ToggleSwapBytesCallback(DICOMParser *parser, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* , + quadbyte len) +{ +#ifdef DEBUG_DICOM_APP_HELPER + dicom_stream::cout << "ToggleSwapBytesCallback" << dicom_stream::endl; +#endif + bool bs = parser->GetDICOMFile()->GetPlatformIsBigEndian(); + parser->GetDICOMFile()->SetPlatformIsBigEndian(!bs); + +#ifdef DEBUG_DICOM_APP_HELPER + dicom_stream::cout << "Set byte swap to: " << parser->GetDICOMFile()->GetPlatformIsBigEndian() << dicom_stream::endl; +#endif + + long pos = parser->GetDICOMFile()->Tell(); + + // + // The +4 is probably a hack, but it's a guess at the length of the previous field. + // + parser->GetDICOMFile()->SkipToPos(pos - len + 4); +} + + +void DICOMAppHelper::PixelSpacingCallback(DICOMParser *parser, + doublebyte group, + doublebyte element, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte len) +{ + + if (group == 0x0028 && element == 0x0030) + { + float fval = 1.0; // defaul of 1mm + if (len > 0) + { + fval = DICOMFile::ReturnAsFloat(val, parser->GetDICOMFile()->GetPlatformIsBigEndian()); + this->PixelSpacing[1] = fval; + unsigned char * val2 = val; // search for separator + while( *val2 != '\\' && *val2 != 0 ) val2++; + if( *val2 == 0 ) + { + dicom_stream::cerr << "Pixel spacing is missing separator!" << dicom_stream::endl; + } + else + { + val2++; // start in the character after the delimiter. + fval = DICOMFile::ReturnAsFloat(val2, parser->GetDICOMFile()->GetPlatformIsBigEndian()); + this->PixelSpacing[0] = fval; + } + } + else + { + this->PixelSpacing[0] = this->PixelSpacing[1] = fval; + } + } + else if (group == 0x0018 && element == 0x0050) + { + float fval = 1.0; // defaul of 1mm + if (len > 0) + { + fval = DICOMFile::ReturnAsFloat(val, parser->GetDICOMFile()->GetPlatformIsBigEndian()); + } + this->PixelSpacing[2] = fval; + } +} + +void DICOMAppHelper::WidthCallback(DICOMParser *parser, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte len) +{ + unsigned short uival = 0; + + if (len > 0) + { + uival = DICOMFile::ReturnAsUnsignedShort(val, parser->GetDICOMFile()->GetPlatformIsBigEndian()); + } + +#ifdef DEBUG_DICOM_APP_HELPER + dicom_stream::cout << "Width: " << uival << dicom_stream::endl; +#endif + + this->Width = uival; + this->Dimensions[0] = this->Width; +} + +void DICOMAppHelper::HeightCallback(DICOMParser *parser, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte len) +{ + unsigned short uival = 0; + + if (len > 0) + { + uival = DICOMFile::ReturnAsUnsignedShort(val, parser->GetDICOMFile()->GetPlatformIsBigEndian()); + } + +#ifdef DEBUG_DICOM_APP_HELPER + dicom_stream::cout << "Height: " << uival << dicom_stream::endl; +#endif + this->Height = uival; + this->Dimensions[1] = this->Height; +} + + +void DICOMAppHelper::PixelRepresentationCallback( DICOMParser *parser, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte len) +{ + unsigned short uival = 1; // default of unsigned + + if (len > 0) + { + uival = DICOMFile::ReturnAsUnsignedShort(val, parser->GetDICOMFile()->GetPlatformIsBigEndian()); + } + +#ifdef DEBUG_DICOM_APP_HELPER + dicom_stream::cout << "Pixel Representation: " << (uival ? "Signed" : "Unsigned") << dicom_stream::endl; +#endif + this->PixelRepresentation = uival; +} + +void DICOMAppHelper::PhotometricInterpretationCallback( DICOMParser *, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte len) +{ +#ifdef DEBUG_DICOM_APP_HELPER + dicom_stream::cout << "Photometric Interpretation: " << (char*) val << dicom_stream::endl; +#endif + if (this->PhotometricInterpretation) + { + delete this->PhotometricInterpretation; + } + + if (len > 0) + { + this->PhotometricInterpretation = new dicom_stl::string((char*) val); + } + else + { + this->PhotometricInterpretation = NULL; + } +} + +void DICOMAppHelper::PixelDataCallback( DICOMParser *, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* data, + quadbyte len) +{ + int numPixels = this->Dimensions[0] * this->Dimensions[1] * this->GetNumberOfComponents(); + + // if length was undefined, i.e. 0xffff, then use numpixels + if (len == 0xffff) + { + numPixels = numPixels; + } + else + { + // length was specified, but only read up to len bytes (as + // opposed to the image size times number of components) + if (len < numPixels) + { + numPixels = len; + } + if (numPixels < 0) + { + numPixels = 0; + } + } + +#ifdef DEBUG_DICOM_APP_HELPER + dicom_stream::cout << "numPixels : " << numPixels << dicom_stream::endl; +#endif + + int ptrIncr = int(this->BitsAllocated/8.0); + + unsigned short* ushortInputData = reinterpret_cast<unsigned short*>(data); + unsigned char* ucharInputData = data; + short* shortInputData = reinterpret_cast<short*> (data); + + float* floatOutputData; // = NULL; + + bool isFloat = this->RescaledImageDataIsFloat(); + + if (isFloat) + { +#ifdef DEBUG_DICOM_APP_HELPER + dicom_stream::cout << "Slope and offset are not integer valued : "; + dicom_stream::cout << this->RescaleSlope << ", " << this->RescaleOffset << dicom_stream::endl; +#endif + if (this->ImageData) + { + delete [] (static_cast<char*> (this->ImageData)); + } + this->ImageData = new float[numPixels]; + floatOutputData = static_cast<float*> (this->ImageData); + + this->ImageDataType = DICOMParser::VR_FL; + this->ImageDataLengthInBytes = numPixels * sizeof(float); + float newFloatPixel; + + if (ptrIncr == 1) + { + for (int i = 0; i < numPixels; i++) + { + newFloatPixel = float(this->RescaleSlope * ucharInputData[i] + this->RescaleOffset); + floatOutputData[i] = newFloatPixel; + } +#ifdef DEBUG_DICOM_APP_HELPER + dicom_stream::cout << "Did rescale, offset to float from char." << dicom_stream::endl; + dicom_stream::cout << numPixels << " pixels." << dicom_stream::endl; +#endif + } + else if (ptrIncr == 2) + { + for (int i = 0; i < numPixels; i++) + { + newFloatPixel = float(this->RescaleSlope * ushortInputData[i] + this->RescaleOffset); + floatOutputData[i] = newFloatPixel; + } +#ifdef DEBUG_DICOM_APP_HELPER + dicom_stream::cout << "Did rescale, offset to float from short." << dicom_stream::endl; + dicom_stream::cout << numPixels << " pixels." << dicom_stream::endl; +#endif + } + } + else + { +#ifdef DEBUG_DICOM_APP_HELPER + dicom_stream::cout << "Slope and offset are integer valued : "; + dicom_stream::cout << this->RescaleSlope << ", " << this->RescaleOffset << dicom_stream::endl; +#endif + + if (ptrIncr == 1) + { + if (this->ImageData) + { + delete [] (static_cast<char*> (this->ImageData)); + } + this->ImageData = new char[numPixels]; + + char* charOutputData = static_cast<char*> (this->ImageData); + + this->ImageDataType = DICOMParser::VR_OB; + this->ImageDataLengthInBytes = numPixels * sizeof(char); + char newCharPixel; + + for (int i = 0; i < numPixels; i++) + { + newCharPixel = char(this->RescaleSlope * ucharInputData[i] + this->RescaleOffset); + charOutputData[i] = newCharPixel; + } +#ifdef DEBUG_DICOM_APP_HELPER + dicom_stream::cout << "Did rescale, offset to char from char." << dicom_stream::endl; + dicom_stream::cout << numPixels << " pixels." << dicom_stream::endl; +#endif + } + else if (ptrIncr == 2) + { + if (this->ImageData) + { + delete [] (static_cast<char*> (this->ImageData)); + } + this->ImageData = new short[numPixels]; + short* shortOutputData = static_cast<short*> (this->ImageData); + + this->ImageDataType = DICOMParser::VR_OW; + this->ImageDataLengthInBytes = numPixels * sizeof(short); + short newShortPixel; + for (int i = 0; i < numPixels; i++) + { + newShortPixel = short(this->RescaleSlope * shortInputData[i] + this->RescaleOffset); + shortOutputData[i] = newShortPixel; + } +#ifdef DEBUG_DICOM_APP_HELPER + dicom_stream::cout << "Did rescale, offset to short from short." << dicom_stream::endl; + dicom_stream::cout << numPixels << " pixels." << dicom_stream::endl; +#endif + } + } +} + + +void DICOMAppHelper::ROIContourSequenceCallback( DICOMParser *, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char*, + quadbyte ) +{ + +#ifdef DEBUG_DICOM_APP_HELPER + dicom_stream::cout << "ROIContourSequence. " << dicom_stream::endl; +#endif + +} + +void DICOMAppHelper::ContourSequenceCallback( DICOMParser *, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char*, + quadbyte) +{ + +#ifdef DEBUG_DICOM_APP_HELPER + dicom_stream::cout << "ContourSequence." << dicom_stream::endl; +#endif + +} + +void DICOMAppHelper::ContourGeometricTypeCallback( DICOMParser *, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char*, + quadbyte) +{ + +#ifdef DEBUG_DICOM_APP_HELPER + dicom_stream::cout << "ContourGeometricType." << dicom_stream::endl; +#endif + +} + +void DICOMAppHelper::ContourDataCallback( DICOMParser *, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* data, + quadbyte len) +{ + + // If we haven't added a contour yet, then we must have missed the tag + // to start the contour + if (this->Implementation->SeriesUIDToContoursMap[this->CurrentSeriesUID].size() == 0) + { + dicom_stream::cerr << "DICOMAppHelper:: Found contour data tag (0x3006, 0x0050) without a matching contour sequence tag (0x3006, 0x0040)." << dicom_stream::endl; + } + // If the number of points in the contour is zero, then we were not + // expecting any data or we missed the tag for the number of contour + // points. + else if (this->Implementation->SeriesUIDToContoursMap[this->CurrentSeriesUID].back().size() == 0) // Note the test for equality + { + dicom_stream::cerr << "DICOMAppHelper:: Found contour data tag (0x3006, 0x0050) without a matching number of contour points tag (0x3006, 0x0046)." << dicom_stream::endl; + } + else + { + // read the number of points Contours.back().size() + // + // + unsigned int i; + float p; + + // get a reference to the contour + DICOMAppHelperImplementation::ContourType + &contour = this->Implementation->SeriesUIDToContoursMap[this->CurrentSeriesUID].back(); + + // read the coordinates. the space for the points has already been + // allocated in NumberOfContourPointsCallback(). we just need to + // parse the (x, y, z) values and put them in the contour vector. + // Points are stored in a vector of floats (x, y, z, x, y, z, ...) + // + + // create a temporary (null terminated) buffer that we can tokenize + unsigned char *tdata = new unsigned char[len+1]; + memcpy((char *) tdata, (char *)data, len); + tdata[len] = '\0'; + + // tokenize and parse the buffer + unsigned char *tPtr; + tPtr = (unsigned char *)strtok((char *)tdata, "\\"); + for (i=0; i < contour.size(); i += 3) + { + sscanf( (char*)(tPtr), "%f", &p); + contour[i] = p; + tPtr = (unsigned char *)strtok(NULL, "\\"); + sscanf( (char*)(tPtr), "%f", &p); + contour[i+1] = p; + tPtr = (unsigned char *)strtok(NULL, "\\"); + sscanf( (char*)(tPtr), "%f", &p); + contour[i+2] = p; + tPtr = (unsigned char *)strtok(NULL, "\\"); + } + + delete [] tdata; + } + + +#ifdef DEBUG_DICOM_APP_HELPER + DICOMAppHelperImplementation::ContourType contour = this->Implementation->SeriesUIDToContoursMap[this->CurrentSeriesUID].back(); + dicom_stream::cout << "Contour with " << contour.size() / 3 << " points." << dicom_stream::endl; + for (unsigned int i=0; i < contour.size(); i+=3) + { + dicom_stream::cout << "[" << contour[i] << ", " << contour[i+1] << ", " << contour[i+2] << "]" + << dicom_stream::endl; + } +#endif + +} + +void DICOMAppHelper::NumberOfContourPointsCallback( DICOMParser *, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* data, + quadbyte) +{ + + int n; + sscanf( (char*)(data), "%d", &n); + + + // If we haven't added a contour yet, then we must have missed the tag + // to start the contour + if (this->Implementation->SeriesUIDToContoursMap[this->CurrentSeriesUID].size() == 0) + { + dicom_stream::cerr << "DICOMAppHelper:: Found number of contour points tag (0x3006, 0x0046) without a matching contour sequence tag (0x3006, 0x0040)." << dicom_stream::endl; + } + // If the last contour is not empty, then we haven't started the + // current contour. A preceding call to ContourSequenceCallback() + // would have created an empty contour at the end of the Contour + // list. + else if (this->Implementation->SeriesUIDToContoursMap[this->CurrentSeriesUID].back().size() != 0) + { + dicom_stream::cerr << "DICOMAppHelper:: Found number of contour points tag (0x3006, 0x0046) without a matching contour geometric type tag (0x3006, 0x0042)." << dicom_stream::endl; + } + else + { + // reserve enough space for the points in the contour (3 floats + // per point). note that we trigger off this size later to parse + // the coordinates of the contours + this->Implementation->SeriesUIDToContoursMap[this->CurrentSeriesUID].back().resize( 3*n ); + } + +#ifdef DEBUG_DICOM_APP_HELPER + dicom_stream::cout << "NumberOfContourPoints : " ; + dicom_stream::cout << n << dicom_stream::endl; +#endif + +} + + +void DICOMAppHelper::RegisterPixelDataCallback(DICOMParser* parser) +{ + this->PixelDataCB->SetCallbackFunction(this, &DICOMAppHelper::PixelDataCallback); + parser->AddDICOMTagCallback(0x7FE0, 0x0010, DICOMParser::VR_OW, this->PixelDataCB); +} + + +const char* DICOMAppHelper::TransferSyntaxUIDDescription(const char* uid) +{ + static const char* DICOM_IMPLICIT_VR_LITTLE_ENDIAN = "1.2.840.10008.1.2"; + static const char* DICOM_LOSSLESS_JPEG = "1.2.840.10008.1.2.4.70"; + static const char* DICOM_LOSSY_JPEG_8BIT = "1.2.840.10008.1.2.4.50"; + static const char* DICOM_LOSSY_JPEG_16BIT = "1.2.840.10008.1.2.4.51"; + static const char* DICOM_EXPLICIT_VR_LITTLE_ENDIAN = "1.2.840.10008.1.2.1"; + static const char* DICOM_EXPLICIT_VR_BIG_ENDIAN = "1.2.840.10008.1.2.2"; + static const char* DICOM_GE_PRIVATE_IMPLICIT_BIG_ENDIAN = "1.2.840.113619.5.2"; + + if (!strcmp(DICOM_IMPLICIT_VR_LITTLE_ENDIAN, uid)) + { + return "Implicit VR, Little Endian"; + } + else if (!strcmp(DICOM_LOSSLESS_JPEG, uid)) + { + return "Lossless JPEG"; + } + else if (!strcmp(DICOM_LOSSY_JPEG_8BIT, uid)) + { + return "Lossy JPEG 8 bit"; + } + else if (!strcmp(DICOM_LOSSY_JPEG_16BIT, uid)) + { + return "Lossy JPEG 16 bit."; + } + else if (!strcmp(DICOM_EXPLICIT_VR_LITTLE_ENDIAN, uid)) + { + return "Explicit VR, Little Endian."; + } + else if (!strcmp(DICOM_EXPLICIT_VR_BIG_ENDIAN, uid)) + { + return "Explicit VR, Big Endian."; + } + else if (!strcmp(DICOM_GE_PRIVATE_IMPLICIT_BIG_ENDIAN, uid)) + { + return "GE Private, Implicit VR, Big Endian Image Data."; + } + else + { + return "Unknown."; + } + +} + + +void DICOMAppHelper::RescaleOffsetCallback( DICOMParser *parser, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte len) +{ + float fval = 0.0; + + if (len > 0) + { + fval = DICOMFile::ReturnAsFloat(val, parser->GetDICOMFile()->GetPlatformIsBigEndian()); + } + + this->RescaleOffset = fval; +#ifdef DEBUG_DICOM_APP_HELPER + dicom_stream::cout << "Pixel offset: " << this->RescaleOffset << dicom_stream::endl; +#endif +} + +void DICOMAppHelper::RescaleSlopeCallback(DICOMParser *parser, + doublebyte, + doublebyte , + DICOMParser::VRTypes , + unsigned char* val, + quadbyte len) +{ + float fval = 1.0; + + if (len > 0) + { + fval = DICOMFile::ReturnAsFloat(val, + parser->GetDICOMFile()->GetPlatformIsBigEndian ()); + } + +#ifdef DEBUG_DICOM_APP_HELPER + dicom_stream::cout << "Rescale slope: " << fval << dicom_stream::endl; +#endif + this->RescaleSlope = fval; +} + +void DICOMAppHelper::PatientNameCallback(DICOMParser *, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte len) +{ + if (val) + { + quadbyte len1 = (len<512) ? len : 511; + strncpy(m_PatientName, (const char*)val, len1); + m_PatientName[len1] = '\0'; + } + else + { + m_PatientName[0] = '\0'; + } +} + +void DICOMAppHelper::PatientIDCallback(DICOMParser *, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte len) +{ + if (val) + { + quadbyte len1 = (len<512) ? len : 511; + strncpy(m_PatientID, (const char*)val, len1); + m_PatientID[len1] = '\0'; + } + else + { + m_PatientID[0] = '\0'; + } +} + +void DICOMAppHelper::PatientSexCallback(DICOMParser *, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte len) +{ + if (val) + { + quadbyte len1 = (len<512) ? len : 511; + strncpy(m_PatientSex, (const char*)val, len1); + m_PatientSex[len1] = '\0'; + } + else + { + m_PatientSex[0] = '\0'; + } +} + +void DICOMAppHelper::PatientAgeCallback(DICOMParser *, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte len) +{ + if (val) + { + quadbyte len1 = (len<512) ? len : 511; + strncpy(m_PatientAge, (const char*)val, len1); + m_PatientAge[len1] = '\0'; + } + else + { + m_PatientAge[0] = '\0'; + } +} + +void DICOMAppHelper::PatientDOBCallback(DICOMParser *, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte len) +{ + if (val) + { + quadbyte len1 = (len<512) ? len : 511; + strncpy(m_PatientDOB, (const char*)val, len1); + m_PatientDOB[len1] = '\0'; + } + else + { + m_PatientDOB[0] = '\0'; + } +} + + +void DICOMAppHelper::StudyIDCallback(DICOMParser *, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte len) +{ + if (val) + { + quadbyte len1 = (len<512) ? len : 511; + strncpy(m_StudyID, (const char*)val, len1); + m_StudyID[len1] = '\0'; + } + else + { + m_StudyID[0] = '\0'; + } +} + + +void DICOMAppHelper::StudyDescriptionCallback(DICOMParser *, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte len) +{ + if (val) + { + quadbyte len1 = (len<512) ? len : 511; + strncpy(m_StudyDescription, (const char*)val, len1); + m_StudyDescription[len1] = '\0'; + } + else + { + m_StudyDescription[0] = '\0'; + } +} + +void DICOMAppHelper::BodyPartCallback(DICOMParser *, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte len) +{ + if (val) + { + quadbyte len1 = (len<512) ? len : 511; + strncpy(m_BodyPart, (const char*)val, len1); + m_BodyPart[len1] = '\0'; + } + else + { + m_BodyPart[0] = '\0'; + return; + } + + char* newString = (char*) val; + dicom_stl::string newStdString(newString); + +#ifdef DEBUG_DICOM_APP_HELPER + dicom_stream::cout << "Body Part: " << newStdString << dicom_stream::endl; +#endif + // Put the series description into the internal database mapping series UIDs + // to InstanceUIDs + DICOMAppHelperImplementation::SeriesUIDToBodyPartMapType::iterator iiter = this->Implementation->SeriesUIDToBodyPartMap.find(this->CurrentSeriesUID); + if ( iiter == this->Implementation->SeriesUIDToBodyPartMap.end()) // if not found we insert + { + this->Implementation->SeriesUIDToBodyPartMap.insert(dicom_stl::pair<const dicom_stl::string, dicom_stl::string> (this->CurrentSeriesUID, newStdString)); + } + this->CurrentBodyPart = newStdString; +} + + +void DICOMAppHelper::NumberOfSeriesInStudyCallback(DICOMParser *, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte len) +{ + if (val) + { + quadbyte len1 = (len<512) ? len : 511; + strncpy(m_NumberOfSeriesInStudy, (const char*)val, len1); + m_NumberOfSeriesInStudy[len1] = '\0'; + } + else + { + m_NumberOfSeriesInStudy[0] = '\0'; + } +} + +void DICOMAppHelper::NumberOfStudyRelatedSeriesCallback(DICOMParser *, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte len) +{ + if (val) + { + quadbyte len1 = (len<512) ? len : 511; + strncpy(m_NumberOfStudyRelatedSeries, (const char*)val, len1); + m_NumberOfStudyRelatedSeries[len1] = '\0'; + } + else + { + m_NumberOfStudyRelatedSeries[0] = '\0'; + } +} + +void DICOMAppHelper::StudyDateCallback(DICOMParser *, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte len) +{ + if (val) + { + quadbyte len1 = (len<512) ? len : 511; + strncpy(m_StudyDate, (const char*)val, len1); + m_StudyDate[len1] = '\0'; + } + else + { + m_StudyDate[0] = '\0'; + } +} + +void DICOMAppHelper::ModalityCallback(DICOMParser *, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte len) +{ + if (val) + { + quadbyte len1 = (len<512) ? len : 511; + strncpy(m_Modality, (const char*)val, len1); + m_Modality[len1] = '\0'; + } + else + { + m_Modality[0] = '\0'; + } +} + +void DICOMAppHelper::ManufacturerCallback(DICOMParser *, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte len) +{ + if (val) + { + quadbyte len1 = (len<512) ? len : 511; + strncpy(m_Manufacturer, (const char*)val, len1); + m_Manufacturer[len1] = '\0'; + } + else + { + m_Manufacturer[0] = '\0'; + } +} + +void DICOMAppHelper::InstitutionCallback(DICOMParser *, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte len) +{ + if (val) + { + quadbyte len1 = (len<512) ? len : 511; + strncpy(m_Institution, (const char*)val, len1); + m_Institution[len1] = '\0'; + } + else + { + m_Institution[0] = '\0'; + } +} + +void DICOMAppHelper::ModelCallback(DICOMParser *, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte len) +{ + if (val) + { + quadbyte len1 = (len<512) ? len : 511; + strncpy(m_Model, (const char*)val, len1); + m_Model[len1] = '\0'; + } + else + { + m_Model[0] = '\0'; + } +} + + +void DICOMAppHelper::ScanOptionsCallback(DICOMParser *, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte len) +{ + if (val) + { + quadbyte len1 = (len<512) ? len : 511; + strncpy(m_ScanOptions, (const char*)val, len1); + m_ScanOptions[len1] = '\0'; + } + else + { + m_ScanOptions[0] = '\0'; + return; + } + + char* newString = (char*) val; + dicom_stl::string newStdString(newString); + +#ifdef DEBUG_DICOM_APP_HELPER + dicom_stream::cout << "Scan Options: " << newStdString << dicom_stream::endl; +#endif + // Put the series description into the internal database mapping series UIDs + // to InstanceUIDs + DICOMAppHelperImplementation::SeriesUIDToScanOptionsMapType::iterator iiter = this->Implementation->SeriesUIDToScanOptionsMap.find(this->CurrentSeriesUID); + if ( iiter == this->Implementation->SeriesUIDToScanOptionsMap.end()) // if not found we insert + { + this->Implementation->SeriesUIDToScanOptionsMap.insert(dicom_stl::pair<const dicom_stl::string, dicom_stl::string> (this->CurrentSeriesUID, newStdString)); + } + this->CurrentScanOptions = newStdString; +} + +bool DICOMAppHelper::RescaledImageDataIsFloat() +{ + int s = int(this->RescaleSlope); + int o = int(this->RescaleOffset); + + float sf = float(s); + float of = float(o); + + double d1 = fabs(sf - this->RescaleSlope); + double d2 = fabs(of - this->RescaleOffset); + + if (d1 > 0.0 || d2 > 0.0) + { + return true; + } + else + { + return false; + } +} + +void DICOMAppHelper::GetImageData(void*& data, DICOMParser::VRTypes& dataType, unsigned long& len) +{ + data = this->ImageData; + dataType = this->ImageDataType; + len = this->ImageDataLengthInBytes; +} + +bool DICOMAppHelper::RescaledImageDataIsSigned() +{ + bool rescaleSigned = (this->RescaleSlope < 0.0); + bool pixelRepSigned = (this->PixelRepresentation == 1); + bool offsetSigned = (this->RescaleOffset < 0.0); + + return (rescaleSigned || pixelRepSigned || offsetSigned); +} + +dicom_stl::string +DICOMAppHelper::GetFileName( const dicom_stl::string &instanceUID ) +{ + dicom_stl::string ret(""); + + DICOMAppHelperImplementation::InstanceUIDToFileNameMapType::iterator + it = this->Implementation->InstanceUIDToFileNameMap.find( instanceUID ); + + if (it != this->Implementation->InstanceUIDToFileNameMap.end() ) + { + ret = (*it).second; + } + + return ret; +} + + +void DICOMAppHelper::GetSliceNumberFilenamePairs(const dicom_stl::string &seriesUID, + dicom_stl::vector<dicom_stl::pair<int, dicom_stl::string> >& v, + bool ascending) +{ + v.clear(); + + DICOMAppHelperImplementation::SeriesUIDToInstanceUIDMapType::iterator miter = this->Implementation->SeriesUIDToInstanceUIDMap.find(seriesUID); + + if (miter == this->Implementation->SeriesUIDToInstanceUIDMap.end() ) + { + return; + } + + // grab the instance uids for the specified series + dicom_stl::vector<dicom_stl::string> instanceUIDs = (*miter).second; + + for (dicom_stl::vector<dicom_stl::string>::iterator instanceIter = instanceUIDs.begin(); + instanceIter != instanceUIDs.end(); + instanceIter++) + { + dicom_stl::pair<int, dicom_stl::string> p; + p.second = dicom_stl::string(this->Implementation->InstanceUIDToFileNameMap[*instanceIter]); + int slice_number; + DICOMAppHelperImplementation::InstanceUIDToSliceOrderingMapType::iterator sn_iter = Implementation->InstanceUIDToSliceOrderingMap.find(*instanceIter); + // Only store files that have a valid slice number + if (sn_iter != Implementation->InstanceUIDToSliceOrderingMap.end()) + { + slice_number = (*sn_iter).second.SliceNumber; + p.first = slice_number; + v.push_back(p); + } + } + if (ascending) + { + dicom_stl::sort(v.begin(), v.end(), lt_pair_int_string()); + } + else + { + dicom_stl::sort(v.begin(), v.end(), gt_pair_int_string()); + } +} + +void DICOMAppHelper::GetSliceNumberFilenamePairs(dicom_stl::vector<dicom_stl::pair<int, dicom_stl::string> >& v, bool ascending) +{ + // Default to using the first series + if (this->Implementation->SeriesUIDToInstanceUIDMap.size() > 0) + { + this->GetSliceNumberFilenamePairs( (*this->Implementation->SeriesUIDToInstanceUIDMap.begin()).first, v, ascending ); + } + else + { + v.clear(); + } +} + +void DICOMAppHelper::GetSliceLocationFilenamePairs(const dicom_stl::string &seriesUID, + dicom_stl::vector<dicom_stl::pair<float, dicom_stl::string> >& v, + bool ascending) +{ + v.clear(); + + DICOMAppHelperImplementation::SeriesUIDToInstanceUIDMapType::iterator miter = this->Implementation->SeriesUIDToInstanceUIDMap.find(seriesUID); + + if (miter == this->Implementation->SeriesUIDToInstanceUIDMap.end() ) + { + return; + } + + // grab the instance UIDs for the specified series + dicom_stl::vector<dicom_stl::string> instanceUIDs = (*miter).second; + + for (dicom_stl::vector<dicom_stl::string>::iterator instanceIter = instanceUIDs.begin(); + instanceIter != instanceUIDs.end(); + instanceIter++) + { + dicom_stl::pair<float, dicom_stl::string> p; + p.second = dicom_stl::string(this->Implementation->InstanceUIDToFileNameMap[*instanceIter]); + float slice_location; + DICOMAppHelperImplementation::InstanceUIDToSliceOrderingMapType::iterator sn_iter = Implementation->InstanceUIDToSliceOrderingMap.find(*instanceIter); + + if (sn_iter != Implementation->InstanceUIDToSliceOrderingMap.end()) + { + slice_location = (*sn_iter).second.SliceLocation; + p.first = slice_location; + v.push_back(p); + } + } + if (ascending) + { + dicom_stl::sort(v.begin(), v.end(), lt_pair_float_string()); + } + else + { + dicom_stl::sort(v.begin(), v.end(), gt_pair_float_string()); + } +} + +void DICOMAppHelper::GetSliceLocationFilenamePairs(dicom_stl::vector<dicom_stl::pair<float, dicom_stl::string> >& v, + bool ascending) +{ + // Default to using the first series + if (this->Implementation->SeriesUIDToInstanceUIDMap.size() > 0) + { + this->GetSliceLocationFilenamePairs( (*this->Implementation->SeriesUIDToInstanceUIDMap.begin()).first, + v, + ascending ); + } + else + { + v.clear(); + } +} + +void DICOMAppHelper::GetImagePositionPatientFilenamePairs(const dicom_stl::string &seriesUID, dicom_stl::vector<dicom_stl::pair<float, dicom_stl::string> >& v, + bool ascending) +{ + v.clear(); + + DICOMAppHelperImplementation::SeriesUIDToInstanceUIDMapType::iterator miter = this->Implementation->SeriesUIDToInstanceUIDMap.find(seriesUID); + + if (miter == this->Implementation->SeriesUIDToInstanceUIDMap.end() ) + { + return; + } + + // grab the instance UIDs for the specified series + dicom_stl::vector<dicom_stl::string> instanceUIDs = (*miter).second; + + for (dicom_stl::vector<dicom_stl::string>::iterator instanceIter = instanceUIDs.begin(); + instanceIter != instanceUIDs.end(); + instanceIter++) + { + dicom_stl::pair<float, dicom_stl::string> p; + p.second = dicom_stl::string(this->Implementation->InstanceUIDToFileNameMap[*instanceIter]); + + float image_position; + float normal[3]; + + DICOMAppHelperImplementation::InstanceUIDToSliceOrderingMapType::iterator sn_iter = Implementation->InstanceUIDToSliceOrderingMap.find(*instanceIter); + + if (sn_iter != Implementation->InstanceUIDToSliceOrderingMap.end()) + { + // compute the image patient position wrt to the slice image + // plane normal + + normal[0] = ((*sn_iter).second.ImageOrientationPatient[1] + * (*sn_iter).second.ImageOrientationPatient[5]) + - ((*sn_iter).second.ImageOrientationPatient[2] + * (*sn_iter).second.ImageOrientationPatient[4]); + normal[1] = ((*sn_iter).second.ImageOrientationPatient[2] + * (*sn_iter).second.ImageOrientationPatient[3]) + - ((*sn_iter).second.ImageOrientationPatient[0] + *(*sn_iter).second.ImageOrientationPatient[5]); + normal[2] = ((*sn_iter).second.ImageOrientationPatient[0] + * (*sn_iter).second.ImageOrientationPatient[4]) + - ((*sn_iter).second.ImageOrientationPatient[1] + * (*sn_iter).second.ImageOrientationPatient[3]); + + image_position = (normal[0]*(*sn_iter).second.ImagePositionPatient[0]) + + (normal[1]*(*sn_iter).second.ImagePositionPatient[1]) + + (normal[2]*(*sn_iter).second.ImagePositionPatient[2]); + p.first = image_position; + v.push_back(p); + } + } + if (ascending) + { + dicom_stl::sort(v.begin(), v.end(), lt_pair_float_string()); + } + else + { + dicom_stl::sort(v.begin(), v.end(), gt_pair_float_string()); + } +} + +void DICOMAppHelper::GetImagePositionPatientFilenamePairs(dicom_stl::vector<dicom_stl::pair<float, dicom_stl::string> >& v, + bool ascending) +{ + // Default to using the first series + if (this->Implementation->SeriesUIDToInstanceUIDMap.size() > 0) + { + this->GetImagePositionPatientFilenamePairs( (*this->Implementation->SeriesUIDToInstanceUIDMap.begin()).first, v, ascending ); + } + else + { + v.clear(); + } +} + + +void DICOMAppHelper::GetContours(const dicom_stl::string &seriesUID, + dicom_stl::vector<dicom_stl::vector<float> >& v) +{ + v.clear(); + + DICOMAppHelperImplementation::SeriesUIDToContoursMapType::iterator iter = this->Implementation->SeriesUIDToContoursMap.find(seriesUID); + + if (iter == this->Implementation->SeriesUIDToContoursMap.end() ) + { + return; + } + + // All we need to do is copy the contours to the output + v = (*iter).second; +} + +void DICOMAppHelper::GetContours(dicom_stl::vector<dicom_stl::vector<float> >& v) +{ + // Default to using the first series + if (this->Implementation->SeriesUIDToInstanceUIDMap.size() > 0) + { + this->GetContours( (*this->Implementation->SeriesUIDToInstanceUIDMap.begin()).first, v ); + } + else + { + v.clear(); + } +} + + +void DICOMAppHelper::GetReferencedInstanceUIDs(const dicom_stl::string &seriesUID, + dicom_stl::vector<dicom_stl::string>& v) +{ + v.clear(); + + DICOMAppHelperImplementation::SeriesUIDToReferencedInstanceUIDMapType::iterator iter = this->Implementation->SeriesUIDToReferencedInstanceUIDMap.find(seriesUID); + + if (iter == this->Implementation->SeriesUIDToReferencedInstanceUIDMap.end() ) + { + return; + } + + // All we need to do is copy the referenced instanced to the output + v = (*iter).second; +} + +void DICOMAppHelper::GetReferencedInstanceUIDs(dicom_stl::vector<dicom_stl::string>& v) +{ + // Default to using the first series + if (this->Implementation->SeriesUIDToInstanceUIDMap.size() > 0) + { + this->GetReferencedInstanceUIDs( (*this->Implementation->SeriesUIDToReferencedInstanceUIDMap.begin()).first, v ); + } + else + { + v.clear(); + } +} + + +void DICOMAppHelper::GetSeriesUIDs(dicom_stl::vector<dicom_stl::string> &v) +{ + v.clear(); + + DICOMAppHelperImplementation::SeriesUIDToInstanceUIDMapType::iterator miter; + + for (miter = this->Implementation->SeriesUIDToInstanceUIDMap.begin(); miter != this->Implementation->SeriesUIDToInstanceUIDMap.end(); + ++miter) + { + v.push_back( (*miter).first ); + } +} + +void DICOMAppHelper::GetSeriesDescriptions(dicom_stl::vector<dicom_stl::string> &v) +{ + v.clear(); + + DICOMAppHelperImplementation::SeriesUIDToInstanceUIDMapType::iterator miter; + + for (miter = this->Implementation->SeriesUIDToInstanceUIDMap.begin(); miter != this->Implementation->SeriesUIDToInstanceUIDMap.end(); + ++miter) + { + DICOMAppHelperImplementation::SeriesUIDToSeriesDescriptionMapType::iterator iiter = this->Implementation->SeriesUIDToSeriesDescriptionMap.find((*miter).first); + if ( iiter != this->Implementation->SeriesUIDToSeriesDescriptionMap.end()) // if found we insert + { + v.push_back( (*iiter).second ); + } + else + { + dicom_stl::string value = ""; + v.push_back( value ); + } + } +} + + +void DICOMAppHelper::GetBodyParts(dicom_stl::vector<dicom_stl::string> &v) +{ + v.clear(); + + DICOMAppHelperImplementation::SeriesUIDToInstanceUIDMapType::iterator miter; + + for (miter = this->Implementation->SeriesUIDToInstanceUIDMap.begin(); miter != this->Implementation->SeriesUIDToInstanceUIDMap.end(); + ++miter) + { + DICOMAppHelperImplementation::SeriesUIDToBodyPartMapType::iterator iiter = this->Implementation->SeriesUIDToBodyPartMap.find((*miter).first); + if ( iiter != this->Implementation->SeriesUIDToBodyPartMap.end()) // if found we insert + { + v.push_back( (*iiter).second ); + } + else + { + dicom_stl::string value = ""; + v.push_back( value ); + } + } +} + + +void DICOMAppHelper::GetScanOptions(dicom_stl::vector<dicom_stl::string> &v) +{ + v.clear(); + + DICOMAppHelperImplementation::SeriesUIDToInstanceUIDMapType::iterator miter; + + for (miter = this->Implementation->SeriesUIDToInstanceUIDMap.begin(); miter != this->Implementation->SeriesUIDToInstanceUIDMap.end(); + ++miter) + { + DICOMAppHelperImplementation::SeriesUIDToScanOptionsMapType::iterator iiter = this->Implementation->SeriesUIDToScanOptionsMap.find((*miter).first); + if ( iiter != this->Implementation->SeriesUIDToScanOptionsMap.end()) // if found we insert + { + v.push_back( (*iiter).second ); + } + else + { + dicom_stl::string value = ""; + v.push_back( value ); + } + } +} + + + +void DICOMAppHelper::Clear() +{ + this->Implementation->InstanceUIDToSeriesUIDMap.clear(); + this->Implementation->InstanceUIDToSliceOrderingMap.clear(); + this->Implementation->SeriesUIDToInstanceUIDMap.clear(); + this->Implementation->SeriesUIDToSeriesDescriptionMap.clear(); + this->Implementation->SeriesUIDToContoursMap.clear(); + this->Implementation->SeriesUIDToBodyPartMap.clear(); + this->Implementation->SeriesUIDToScanOptionsMap.clear(); + + this->CurrentSeriesUID = ""; + this->CurrentSeriesDescription = ""; + this->InstanceUID = ""; +} +} +#ifdef _MSC_VER +#pragma warning ( pop ) +#endif + diff --git a/Utilities/ITK/Utilities/DICOMParser/DICOMAppHelper.h b/Utilities/ITK/Utilities/DICOMParser/DICOMAppHelper.h new file mode 100644 index 0000000000000000000000000000000000000000..3795154cf97156658115e09d15a5adb9e9bebacb --- /dev/null +++ b/Utilities/ITK/Utilities/DICOMParser/DICOMAppHelper.h @@ -0,0 +1,867 @@ +/*========================================================================= + + Program: DICOMParser + Module: $RCSfile: DICOMAppHelper.h,v $ + Language: C++ + Date: $Date: 2005/05/06 18:53:40 $ + Version: $Revision: 1.28 $ + + Copyright (c) 2003 Matt Turek + All rights reserved. + See Copyright.txt 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. + +=========================================================================*/ + +#ifndef __DICOM_APP_HELPER_H_ +#define __DICOM_APP_HELPER_H_ + +#ifdef _MSC_VER +#pragma warning ( disable : 4514 ) +#pragma warning ( push, 3 ) +#endif + +#include <vector> +#include <string> + +#include "DICOMConfig.h" +#include "DICOMTypes.h" +#include "DICOMCallback.h" + +namespace DICOMPARSER_NAMESPACE +{ +class DICOMParser; + +// Function object for sorting strings +struct ltstdstr +{ + bool operator()(const dicom_stl::string s1, const dicom_stl::string s2) const + { + return s1 < s2; + } +}; + + +// Helper structure for DICOM elements +struct DICOMTagInfo +{ + doublebyte group; + doublebyte element; + DICOMParser::VRTypes datatype; + const char* description; +}; + +// Helper class use for ordering DICOM images based on different +// (group, element) tags. +class DICOM_EXPORT DICOMOrderingElements +{ +public: + DICOMOrderingElements() + { + // Default values to something "valid" + SliceNumber = -1; + SliceLocation = 0.0; + ImagePositionPatient[0] = 0.0; + ImagePositionPatient[1] = 0.0; + ImagePositionPatient[2] = 0.0; + ImageOrientationPatient[0] = 1.0; + ImageOrientationPatient[1] = 0.0; + ImageOrientationPatient[2] = 0.0; + ImageOrientationPatient[3] = 0.0; + ImageOrientationPatient[4] = 1.0; + ImageOrientationPatient[5] = 0.0; + } + + int SliceNumber; + float SliceLocation; + float ImagePositionPatient[3]; + float ImageOrientationPatient[6]; +}; + +class DICOMAppHelperImplementation; + +/** + * \class DICOMAppHelper + * \brief Class to interface an application to a DICOMParser + * + * DICOMAppHelper assists an application in communicating with a + * DICOMParser. DICOMAppHelper registers a series of callbacks to the + * DICOMParser which allows it to cache the information from a DICOM + * file in a format that is appropriate for an application to + * use. Once a DICOM file is read, an application can query the + * DICOMAppHelper for the resolution, pixel size, and pixel data. + * + * If a DICOMParser scans more than one file, the DICOMAppHelper will + * group filesnames by SeriesUID. This allows an application to pass + * a series of DICOM files to the DICOMParser (which via the callback + * mechanism allows the DICOMAppHelper to cache information) and then + * query the DICOMAppHelper for the files that are from the same + * series. The application can request the filenames for a particular + * series to be sorted based on image number, slice location, or + * patient position. This allows the DICOMAppHelper to assist an + * application is collecting all the images from one series into a + * volume. + */ +class DICOM_EXPORT DICOMAppHelper +{ +public: + /** Standard constructor */ + DICOMAppHelper(); + + /** Standard destructor */ + virtual ~DICOMAppHelper(); + + /** Callbacks that are registered with the DICOMParser. The + * DICOMParser will call one of these callbacks whenever it + * encounters a (group, element) that has an associated callback */ + virtual void RescaleSlopeCallback(DICOMParser *parser, + doublebyte group, + doublebyte element, + DICOMParser::VRTypes type, + unsigned char* val, + quadbyte len); + + virtual void ArrayCallback(DICOMParser *parser, + doublebyte group, + doublebyte element, + DICOMParser::VRTypes type, + unsigned char* val, + quadbyte len); + + virtual void SliceNumberCallback(DICOMParser *parser, + doublebyte group, + doublebyte element, + DICOMParser::VRTypes type, + unsigned char* val, + quadbyte len) ; + + virtual void SliceLocationCallback(DICOMParser *parser, + doublebyte group, + doublebyte element, + DICOMParser::VRTypes type, + unsigned char* val, + quadbyte len) ; + + virtual void ImagePositionPatientCallback(DICOMParser *parser, + doublebyte group, + doublebyte element, + DICOMParser::VRTypes type, + unsigned char* val, + quadbyte len) ; + + virtual void ImageOrientationPatientCallback(DICOMParser *parser, + doublebyte group, + doublebyte element, + DICOMParser::VRTypes type, + unsigned char* val, + quadbyte len) ; + + virtual void SeriesUIDCallback(DICOMParser *parser, + doublebyte group, + doublebyte element, + DICOMParser::VRTypes type, + unsigned char* val, + quadbyte len) ; + + virtual void SeriesDescriptionCallback(DICOMParser *parser, + doublebyte group, + doublebyte element, + DICOMParser::VRTypes type, + unsigned char* val, + quadbyte len) ; + + + virtual void InstanceUIDCallback(DICOMParser *parser, + doublebyte group, + doublebyte element, + DICOMParser::VRTypes type, + unsigned char* val, + quadbyte len) ; + + virtual void TransferSyntaxCallback(DICOMParser *parser, + doublebyte group, + doublebyte element, + DICOMParser::VRTypes type, + unsigned char* val, + quadbyte len) ; + + virtual void BitsAllocatedCallback(DICOMParser *parser, + doublebyte group, + doublebyte element, + DICOMParser::VRTypes type, + unsigned char* val, + quadbyte len) ; + + virtual void ToggleSwapBytesCallback(DICOMParser *parser, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char*, + quadbyte); + + virtual void PixelSpacingCallback(DICOMParser *parser, + doublebyte group, + doublebyte element, + DICOMParser::VRTypes type, + unsigned char* val, + quadbyte len) ; + + virtual void HeightCallback(DICOMParser *parser, + doublebyte group, + doublebyte element, + DICOMParser::VRTypes type, + unsigned char* val, + quadbyte len); + + virtual void WidthCallback( DICOMParser *parser, + doublebyte group, + doublebyte element, + DICOMParser::VRTypes type, + unsigned char* val, + quadbyte len); + + virtual void PixelRepresentationCallback(DICOMParser *parser, + doublebyte group, + doublebyte element, + DICOMParser::VRTypes type, + unsigned char* val, + quadbyte len); + + virtual void PhotometricInterpretationCallback(DICOMParser *parser, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte len); + + virtual void PixelDataCallback(DICOMParser *parser, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte len); + + virtual void RescaleOffsetCallback( DICOMParser *parser, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte); + + virtual void ROIContourSequenceCallback( DICOMParser *parser, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte); + + virtual void ContourSequenceCallback( DICOMParser *parser, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte); + + virtual void ContourImageSequenceCallback( DICOMParser *parser, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte); + + virtual void ContourGeometricTypeCallback( DICOMParser *parser, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte); + + virtual void NumberOfContourPointsCallback( DICOMParser *parser, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte); + + virtual void ContourDataCallback( DICOMParser *parser, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte); + + virtual void ReferencedInstanceUIDCallback( DICOMParser *parser, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte); + + virtual void PatientNameCallback( DICOMParser *parser, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte); + + virtual void PatientIDCallback( DICOMParser *parser, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte); + + virtual void PatientSexCallback( DICOMParser *parser, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte); + + virtual void PatientAgeCallback( DICOMParser *parser, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte); + virtual void PatientDOBCallback( DICOMParser *parser, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte); + + virtual void StudyIDCallback( DICOMParser *parser, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte); + + virtual void StudyDescriptionCallback( DICOMParser *parser, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte); + + virtual void BodyPartCallback( DICOMParser *parser, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte); + + virtual void NumberOfSeriesInStudyCallback( DICOMParser *parser, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte); + + virtual void NumberOfStudyRelatedSeriesCallback( DICOMParser *parser, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte); + + virtual void StudyDateCallback( DICOMParser *parser, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte); + + virtual void ModalityCallback( DICOMParser *parser, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte); + + virtual void ManufacturerCallback( DICOMParser *parser, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte); + + virtual void InstitutionCallback( DICOMParser *parser, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte); + + virtual void ModelCallback( DICOMParser *parser, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte); + + virtual void ScanOptionsCallback( DICOMParser *parser, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte); + + virtual void DefaultCallback( DICOMParser *parser, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte); + + + + /** Register all the standard callbacks with the DICOM Parser. This + * associates a callback with each (group, element) tag pair in the + * header of the file whose data needs to be cached. */ + virtual void RegisterCallbacks(DICOMParser* parser); + + /** Register a callback for retrieving the pixel data from a DICOM + * file */ + virtual void RegisterPixelDataCallback(DICOMParser* parser); + + + /** Output information associated with a DICOM series */ + void OutputSeries(); + + + /** The next set of methods are for accessing information which is + * cached when a DICOM file is processed. This allows access to + * information from the header as well as the pixel data. */ + + + /** Get the pixel spacing of the last image processed by the + * DICOMParser */ + float* GetPixelSpacing() + { + return this->PixelSpacing; + } + + /** Get the image width of the last image processed by the + * DICOMParser */ + int GetWidth() + { + return this->Width; + } + + /** Get the image height of the last image processed by the + * DICOMParser */ + int GetHeight() + { + return this->Height; + } + + /** Get the dimensions (width, height) of the last image processed + * by the DICOMParser */ + int* GetDimensions() + { + return this->Dimensions; + } + + /** Get the (DICOM) x,y,z coordinates of the first pixel in the + * image (upper left hand corner) of the last image processed by the + * DICOMParser */ + float *GetImagePositionPatient() + { + return this->ImagePositionPatient; + } + + + /** Get the number of bits allocated per pixel of the last image + * processed by the DICOMParser */ + int GetBitsAllocated() + { + return this->BitsAllocated; + } + + /** Get the pixel representation of the last image processed by the + * DICOMParser. A zero is a unsigned quantity. A one indicates a + * signed quantity. */ + int GetPixelRepresentation() + { + return this->PixelRepresentation; + } + + /** Get the number of components of the last image processed by the + * DICOMParser. */ + unsigned int GetNumberOfComponents() + { + if (!this->PhotometricInterpretation) + { + return 1; + } + + // + // DICOM standard says that spaces (0x20) are to + // be ignored for CS types. We don't handle this + // well yet. + // + dicom_stl::string str1(*this->PhotometricInterpretation); + dicom_stl::string rgb("RGB "); + + if (str1 == rgb) + { + return 3; + } + else + { + return 1; + } + } + + /** Get the transfer syntax UID for the last image processed by the + * DICOMParser. */ + dicom_stl::string GetTransferSyntaxUID() + { + return *(this->TransferSyntaxUID); + } + + /** Get a textual description of the transfer syntax of the last + * image processed by the DICOMParser. */ + const char* TransferSyntaxUIDDescription(const char* uid); + + /** Get the image data from the last image processed by the + * DICOMParser. The data is only valid if the PixelDataCallback was + * registered. + * \sa RegisterPixelDataCallback() + */ + void GetImageData(void* & data, DICOMParser::VRTypes& dataType, unsigned long& len); + + /** Determine whether the image data was rescaled (by the + * RescaleSlope tag) to be floating point. */ + bool RescaledImageDataIsFloat(); + + /** Determine whether the image data was rescaled (by the + * RescaleSlope tag) to be a signed data type. */ + bool RescaledImageDataIsSigned(); + + /** Get the slice number of the last image processed by the + DICOMParser. */ + int GetSliceNumber() + { + return this->SliceNumber; + } + + /** Get the series UID for the current file. */ + std::string GetSeriesUID() { return this->CurrentSeriesUID; } + + /** Get the series description for the current file. */ + std::string GetSeriesDescription() { return this->CurrentSeriesDescription; } + + /** Get the patient name processed by the + DICOMParser. */ + void GetPatientName(char* name) + { + strcpy(name, m_PatientName); + } + + /** Get the patient ID processed by the + DICOMParser. */ + void GetPatientID(char* id) + { + strcpy(id, m_PatientID); + } + + /** Get the patient sex processed by the + DICOMParser. */ + void GetPatientSex(char* sex) + { + strcpy(sex, m_PatientSex); + } + + /** Get the patient age processed by the + DICOMParser. */ + void GetPatientAge(char* age) + { + strcpy(age, m_PatientAge); + } + + /** Get the patient date of birth processed by the + DICOMParser. */ + void GetPatientDOB(char* dob) + { + strcpy(dob, m_PatientDOB); + } + + /** Get the study ID processed by the + DICOMParser. */ + void GetStudyID(char* id) + { + strcpy(id, m_StudyID); + } + + /** Get the description of the study processed by the + DICOMParser. */ + void GetStudyDescription(char* desc) + { + strcpy(desc, m_StudyDescription); + } + + /** Get the body part processed by the + DICOMParser. */ + void GetBodyPart(char* part) + { + strcpy(part, m_BodyPart); + } + + /** Get the number of series in the study processed by the + DICOMParser. */ + void GetNumberOfSeriesInStudy(char* number) + { + strcpy(number, m_NumberOfSeriesInStudy); + } + + + /** Get the number of study related series processed by the + DICOMParser. */ + void GetNumberOfStudyRelatedSeries(char* number) + { + strcpy(number, m_NumberOfStudyRelatedSeries); + } + + /** Get the study date processed by the + DICOMParser. */ + void GetStudyDate(char* date) + { + strcpy(date, m_StudyDate); + } + + /** Get the modality processed by the + DICOMParser. */ + void GetModality(char* modality) + { + strcpy(modality, m_Modality); + } + + /** Get the manufacturer processed by the + DICOMParser. */ + void GetManufacturer(char* manu) + { + strcpy(manu, m_Manufacturer); + } + + /** Get the institution processed by the + DICOMParser. */ + void GetInstitution(char* ins) + { + strcpy(ins, m_Institution); + } + + /** Get the model processed by the + DICOMParser. */ + void GetModel(char* model) + { + strcpy(model, m_Model); + } + + /** Get the scan options name processed by the + DICOMParser. */ + void GetScanOptions(char* options) + { + strcpy(options, m_ScanOptions); + } + + /** Clear the internal databases. This will reset the internal + * databases that are grouping filenames based on SeriesUID's and + * ordering filenames based on image locations. */ + void Clear(); + + /** Get the series UIDs for the files processed since the last + * clearing of the cache. */ + void GetSeriesUIDs(dicom_stl::vector<dicom_stl::string> &v); + + /** Get the series Descriptions for the files processed since the last + * clearing of the cache. */ + void GetSeriesDescriptions(dicom_stl::vector<dicom_stl::string> &v); + + /** Get the body parts for the files processed since the last + * clearing of the cache. */ + void GetBodyParts(dicom_stl::vector<dicom_stl::string> &v); + + /** Get the scane options for the files processed since the last + * clearing of the cache. */ + void GetScanOptions(dicom_stl::vector<dicom_stl::string> &v); + + /** Get the filenames for a series ordered by slice number. */ + void GetSliceNumberFilenamePairs(const dicom_stl::string &seriesUID, + dicom_stl::vector<dicom_stl::pair<int, dicom_stl::string> > &v, + bool ascending = true); + + /** Get the filenames for a series order by slice number. Use the + first series by default. */ + void GetSliceNumberFilenamePairs(dicom_stl::vector<dicom_stl::pair<int, dicom_stl::string> > &v, + bool ascending = true); + + /* Get the filenames for a series ordered by slice location. */ + void GetSliceLocationFilenamePairs(const dicom_stl::string &seriesUID, + dicom_stl::vector<dicom_stl::pair<float, dicom_stl::string> > &v, + bool ascending = true); + + /* Get the filenames for a series ordered by slice location. Use the + * first series by default. */ + void GetSliceLocationFilenamePairs(dicom_stl::vector<dicom_stl::pair<float, dicom_stl::string> > &v, + bool ascending = true); + + /* Get the filenames for a series ordered by image position + patient. This is the most reliable way to order the images in a + series. */ + void GetImagePositionPatientFilenamePairs(const dicom_stl::string &seriesUID, + dicom_stl::vector<dicom_stl::pair<float, dicom_stl::string> > &v, + bool ascending = true); + + /* Get the filenames for a series ordered by image position + patient. This is the most reliable way to order the images in a + series. Use the first series by default. */ + void GetImagePositionPatientFilenamePairs(dicom_stl::vector<dicom_stl::pair<float, dicom_stl::string> > &v, + bool ascending = true); + + /* Get the contours for a series. A vector of contours is returned + where each contour is a vector of floats (x, y, z, x, y, z, x, y, + z...). */ + void GetContours(const dicom_stl::string &seriesUID, + dicom_stl::vector<dicom_stl::vector<float> > &v); + + /* Get the contours for a series. A vector of contours is returned + where each contour is a vector of floats (x, y, z, x, y, z, x, y, + z...). Use the first series by default. */ + void GetContours(dicom_stl::vector<dicom_stl::vector<float> > &v); + + /* Get the referenced instance UIDs for a series. A vector of + * strings in returned. */ + void GetReferencedInstanceUIDs(const dicom_stl::string &seriesUID, + dicom_stl::vector<dicom_stl::string> &v); + + /* Get the referenced instance UIDs for a series. A vector of + * strings in returned. Use the first series by default. */ + void GetReferencedInstanceUIDs(dicom_stl::vector<dicom_stl::string> &v); + + /** Get the filename for a specific instance UID */ + dicom_stl::string GetFileName( const dicom_stl::string &instanceUID ); + + protected: + int FileCount; + int BitsAllocated; + bool ByteSwapData; + float PixelSpacing[3]; + int Width; + int Height; + int SliceNumber; + int Dimensions[2]; + float ImagePositionPatient[3]; + + short VolumeSliceSize; + short VolumeSliceCount; + long VolumeVoxelCount; + long VolumeSegmentCount; + + char m_PatientName[512]; + char m_PatientID[512]; + char m_PatientDOB[512]; + char m_StudyID[512]; + char m_StudyDescription[512]; + char m_BodyPart[512]; + char m_NumberOfSeriesInStudy[512]; + char m_NumberOfStudyRelatedSeries[512]; + char m_PatientSex[512]; + char m_PatientAge[512]; + char m_StudyDate[512]; + char m_Modality[512]; + char m_Manufacturer[512]; + char m_Institution[512]; + char m_Model[512]; + char m_ScanOptions[512]; + + typedef dicom_stl::map<dicom_stl::pair<doublebyte, doublebyte>, DICOMTagInfo> TagMapType; + // TagMapType TagMap; + + dicom_stream::ofstream HeaderFile; + + // 0 unsigned + // 1 2s complement (signed) + int PixelRepresentation; + dicom_stl::string* PhotometricInterpretation; + dicom_stl::string* TransferSyntaxUID; + dicom_stl::string CurrentSeriesUID; + dicom_stl::string CurrentSeriesDescription; + dicom_stl::string CurrentBodyPart; + dicom_stl::string CurrentScanOptions; + dicom_stl::string InstanceUID; + + float RescaleOffset; + float RescaleSlope; + void* ImageData; + DICOMParser::VRTypes ImageDataType; + unsigned long ImageDataLengthInBytes; + + DICOMMemberCallback<DICOMAppHelper>* SeriesUIDCB; + DICOMMemberCallback<DICOMAppHelper>* SeriesDescriptionCB; + DICOMMemberCallback<DICOMAppHelper>* InstanceUIDCB; + DICOMMemberCallback<DICOMAppHelper>* SliceNumberCB; + DICOMMemberCallback<DICOMAppHelper>* SliceLocationCB; + DICOMMemberCallback<DICOMAppHelper>* ImagePositionPatientCB; + DICOMMemberCallback<DICOMAppHelper>* ImageOrientationPatientCB; + DICOMMemberCallback<DICOMAppHelper>* TransferSyntaxCB; + DICOMMemberCallback<DICOMAppHelper>* ToggleSwapBytesCB; + DICOMMemberCallback<DICOMAppHelper>* BitsAllocatedCB; + DICOMMemberCallback<DICOMAppHelper>* PixelSpacingCB; + DICOMMemberCallback<DICOMAppHelper>* HeightCB; + DICOMMemberCallback<DICOMAppHelper>* WidthCB; + DICOMMemberCallback<DICOMAppHelper>* PixelRepresentationCB; + DICOMMemberCallback<DICOMAppHelper>* PhotometricInterpretationCB; + DICOMMemberCallback<DICOMAppHelper>* RescaleOffsetCB; + DICOMMemberCallback<DICOMAppHelper>* RescaleSlopeCB; + DICOMMemberCallback<DICOMAppHelper>* PixelDataCB; + DICOMMemberCallback<DICOMAppHelper>* ROIContourSequenceCB; + DICOMMemberCallback<DICOMAppHelper>* ContourSequenceCB; + DICOMMemberCallback<DICOMAppHelper>* ContourDataCB; + DICOMMemberCallback<DICOMAppHelper>* NumberOfContourPointsCB; + DICOMMemberCallback<DICOMAppHelper>* ContourGeometricTypeCB; + DICOMMemberCallback<DICOMAppHelper>* ContourImageSequenceCB; + DICOMMemberCallback<DICOMAppHelper>* ReferencedInstanceUIDCB; + DICOMMemberCallback<DICOMAppHelper>* DefaultCB; + + DICOMMemberCallback<DICOMAppHelper>* PatientNameCB; + DICOMMemberCallback<DICOMAppHelper>* PatientIDCB; + DICOMMemberCallback<DICOMAppHelper>* PatientSexCB; + DICOMMemberCallback<DICOMAppHelper>* PatientAgeCB; + DICOMMemberCallback<DICOMAppHelper>* StudyDateCB; + DICOMMemberCallback<DICOMAppHelper>* ModalityCB; + DICOMMemberCallback<DICOMAppHelper>* ManufacturerCB; + DICOMMemberCallback<DICOMAppHelper>* InstitutionCB; + DICOMMemberCallback<DICOMAppHelper>* ModelCB; + DICOMMemberCallback<DICOMAppHelper>* ScanOptionsCB; + DICOMMemberCallback<DICOMAppHelper>* PatientDOBCB; + DICOMMemberCallback<DICOMAppHelper>* StudyIDCB; + DICOMMemberCallback<DICOMAppHelper>* StudyDescriptionCB; + DICOMMemberCallback<DICOMAppHelper>* BodyPartCB; + DICOMMemberCallback<DICOMAppHelper>* NumberOfSeriesInStudyCB; + DICOMMemberCallback<DICOMAppHelper>* NumberOfStudyRelatedSeriesCB; + + // + // Implementation contains stl templated classes that + // can't be exported from a DLL in Windows. We hide + // them in the implementation to get rid of annoying + // compile warnings. + // + DICOMAppHelperImplementation* Implementation; + + private: + DICOMAppHelper(const DICOMAppHelper&); + void operator=(const DICOMAppHelper&); + +}; +} +#ifdef _MSC_VER +#pragma warning ( pop ) +#endif + +#endif diff --git a/Utilities/ITK/Utilities/DICOMParser/DICOMBuffer.cxx b/Utilities/ITK/Utilities/DICOMParser/DICOMBuffer.cxx new file mode 100644 index 0000000000000000000000000000000000000000..79cfa8b3f0d59e2e11efeb6554f6f4def738071c --- /dev/null +++ b/Utilities/ITK/Utilities/DICOMParser/DICOMBuffer.cxx @@ -0,0 +1,100 @@ +/*========================================================================= + + Program: DICOMParser + Module: $RCSfile: DICOMBuffer.cxx,v $ + Language: C++ + Date: $Date: 2004/03/21 21:40:03 $ + Version: $Revision: 1.2 $ + + Copyright (c) 2003 Matt Turek + All rights reserved. + See Copyright.txt 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. + +=========================================================================*/ + +#ifdef _MSC_VER +#pragma warning ( disable : 4514 ) +#pragma warning ( disable : 4710 ) +#pragma warning ( push, 3 ) +#endif + +#include <iostream> +#include <fstream> +#include <iomanip> +#include <stdio.h> +#include <string> + +#include "DICOMConfig.h" +#include "DICOMBuffer.h" + +namespace DICOMPARSER_NAMESPACE +{ +DICOMBuffer::DICOMBuffer(unsigned char *buffer, long length) + : DICOMSource(), + Buffer(buffer), + Length(length), + Position(0) +{ +} + +DICOMBuffer::~DICOMBuffer() +{ +} + +DICOMBuffer::DICOMBuffer(const DICOMBuffer& in) + : DICOMSource(in) +{ + Buffer = in.Buffer; + Length = in.Length; + Position = in.Position; +} + +void DICOMBuffer::operator=(const DICOMBuffer& in) +{ + DICOMSource::operator=(in); + + Buffer = in.Buffer; + Length = in.Length; + Position = in.Position; +} + + +long DICOMBuffer::Tell() +{ + return Position; +} + +void DICOMBuffer::SkipToPos(long increment) +{ + Position = increment; +} + +long DICOMBuffer::GetSize() +{ + return Length; +} + +void DICOMBuffer::Skip(long increment) +{ + Position += increment; +} + +void DICOMBuffer::SkipToStart() +{ + Position = 0; +} + +void DICOMBuffer::Read(void* ptr, long nbytes) +{ + memcpy(ptr, Buffer+Position, nbytes); + Position += nbytes; +} + +} +#ifdef _MSC_VER +#pragma warning ( pop ) +#endif diff --git a/Utilities/ITK/Utilities/DICOMParser/DICOMBuffer.h b/Utilities/ITK/Utilities/DICOMParser/DICOMBuffer.h new file mode 100644 index 0000000000000000000000000000000000000000..1a6d9b7eb43d70aa09b446398be32d4736c08c84 --- /dev/null +++ b/Utilities/ITK/Utilities/DICOMParser/DICOMBuffer.h @@ -0,0 +1,97 @@ +/*========================================================================= + + Program: DICOMParser + Module: $RCSfile: DICOMBuffer.h,v $ + Language: C++ + Date: $Date: 2004/03/21 21:40:03 $ + Version: $Revision: 1.2 $ + + Copyright (c) 2003 Matt Turek + All rights reserved. + See Copyright.txt 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. + +=========================================================================*/ + +#ifndef __DICOMBUFFER_H_ +#define __DICOMBUFFER_H_ + +#ifdef _MSC_VER +#pragma warning ( disable : 4514 ) +#pragma warning ( push, 3 ) +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <iostream> +#include <fstream> +#include <string> + +#include "DICOMTypes.h" +#include "DICOMConfig.h" +#include "DICOMSource.h" + +namespace DICOMPARSER_NAMESPACE +{ +// +// DICOM data source that is a memory buffer. +// +class DICOM_EXPORT DICOMBuffer : public DICOMSource +{ + public: + DICOMBuffer(unsigned char *buffer, long length); + virtual ~DICOMBuffer(); + + // + // Return the position in the buffer. + // + long Tell(); + + // + // Move to a particular position in the buffer. + // + void SkipToPos(long); + + // + // Return the size of the buffer. + // + long GetSize(); + + // + // Skip a number of bytes. + // + void Skip(long); + + // + // Skip to the beginning of the buffer. + // + void SkipToStart(); + + // + // Read data of length len. + // + void Read(void* data, long len); + + protected: + DICOMBuffer(const DICOMBuffer&); + void operator=(const DICOMBuffer&); + + unsigned char *Buffer; + long Length; + long Position; + +private: + DICOMBuffer(); + +}; +} +#ifdef _MSC_VER +#pragma warning ( pop ) +#endif + +#endif // __DICOMBUFFER_H_ + + diff --git a/Utilities/ITK/Utilities/DICOMParser/DICOMCMakeConfig.h.in b/Utilities/ITK/Utilities/DICOMParser/DICOMCMakeConfig.h.in new file mode 100644 index 0000000000000000000000000000000000000000..7eaca4c45462974cc6b74fc8b45b990d23f720cb --- /dev/null +++ b/Utilities/ITK/Utilities/DICOMParser/DICOMCMakeConfig.h.in @@ -0,0 +1,11 @@ + +#ifndef __DICOMCMakeConfig_h_ +#define __DICOMCMakeConfig_h_ + +#cmakedefine DICOM_DLL +#cmakedefine DICOM_STATIC +#cmakedefine DICOM_ANSI_STDLIB +#cmakedefine DICOM_NO_STD_NAMESPACE + +#define DICOMPARSER_NAMESPACE @DICOMPARSER_NAMESPACE@ +#endif diff --git a/Utilities/ITK/Utilities/DICOMParser/DICOMCallback.h b/Utilities/ITK/Utilities/DICOMParser/DICOMCallback.h new file mode 100644 index 0000000000000000000000000000000000000000..cf04a4f1a00fbfa16c8dd38f65c16b60ec144a28 --- /dev/null +++ b/Utilities/ITK/Utilities/DICOMParser/DICOMCallback.h @@ -0,0 +1,113 @@ +/*========================================================================= + + Program: DICOMParser + Module: $RCSfile: DICOMCallback.h,v $ + Language: C++ + Date: $Date: 2005/05/13 19:44:21 $ + Version: $Revision: 1.7 $ + + Copyright (c) 2003 Matt Turek + All rights reserved. + See Copyright.txt 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. + +=========================================================================*/ + +#ifndef __DICOM_CALLBACK_H_ +#define __DICOM_CALLBACK_H_ + +#ifdef _MSC_VER +#pragma warning ( disable : 4514 ) +#pragma warning ( disable : 4786 ) +#pragma warning ( disable : 4503 ) +#pragma warning ( disable : 4710 ) +#pragma warning ( disable : 4702 ) +#pragma warning ( push, 3 ) +#endif + +#include "DICOMConfig.h" +#include "DICOMParser.h" + +namespace DICOMPARSER_NAMESPACE +{ +// +// Pure virtual class that specifies the interface +// for a DICOMCallback. +// +// The DICOMParser allows a vector of callbacks to +// be specified for each group element tag. When +// a group, element with a registered callback is +// encountered, the callback is called and passed +// the group, element, type, data, and data length. +// + +class DICOM_EXPORT DICOMCallback +{ + public: + virtual void Execute(DICOMParser *parser, + doublebyte group, + doublebyte element, + DICOMParser::VRTypes type, + unsigned char* val, + quadbyte len) = 0; + virtual ~DICOMCallback() {} +}; + +// +// Subclass of DICOMCallback which can be used +// with member functions. +// +template <class T> +class DICOMMemberCallback : public DICOMCallback +{ + public: + typedef void (T::*TMemberFunctionPointer)(DICOMParser *parser, + doublebyte group, + doublebyte element, + DICOMParser::VRTypes type, + unsigned char* val, + quadbyte len); + + + // + // Method to set the object and member function pointers + // that will be called in the callback. + // + void SetCallbackFunction(T* object, + TMemberFunctionPointer memberFunction) + { + ObjectThis = object; + MemberFunction = memberFunction; + } + + // + // Execute method implementation from DICOMCallback. + // + void Execute(DICOMParser *parser, + doublebyte group, + doublebyte element, + DICOMParser::VRTypes type, + unsigned char* val, + quadbyte len) + { + if (MemberFunction) + { + ((*ObjectThis).*(MemberFunction))(parser, group, element, type, val,len); + } + } + + protected: + T* ObjectThis; + TMemberFunctionPointer MemberFunction; + +}; +} +#ifdef _MSC_VER +#pragma warning ( pop ) +#endif + +#endif + diff --git a/Utilities/ITK/Utilities/DICOMParser/DICOMConfig.h b/Utilities/ITK/Utilities/DICOMParser/DICOMConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..c31fd7aa098b398e782faad7a9129ec1a7a3a551 --- /dev/null +++ b/Utilities/ITK/Utilities/DICOMParser/DICOMConfig.h @@ -0,0 +1,74 @@ +/*========================================================================= + + Program: DICOMParser + Module: $RCSfile: DICOMConfig.h,v $ + Language: C++ + Date: $Date: 2004/03/22 15:25:59 $ + Version: $Revision: 1.4 $ + + Copyright (c) 2003 Matt Turek + All rights reserved. + See Copyright.txt 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. + +=========================================================================*/ + +#ifndef __DICOM_CONFIG_H_ +#define __DICOM_CONFIG_H_ + +// +// CMake Hook +// +#include "DICOMCMakeConfig.h" + +// +// BEGIN Toolkit (ITK,VTK, etc) specific +// +#ifdef vtkDICOMParser_EXPORTS + #define DICOM_EXPORT_SYMBOLS +#endif + +#ifdef ITKDICOMParser_EXPORTS + #define DICOM_EXPORT_SYMBOLS +#endif + +// +// END toolkit (ITK, VTK, etc) specific +// + +#ifdef DICOM_NO_STD_NAMESPACE + #define dicom_stl +#else + #define dicom_stl std +#endif + +#ifdef DICOM_ANSI_STDLIB + #define dicom_stream std + + #include <iostream> + #include <fstream> + #include <iomanip> +#else + #define dicom_stream + + #include <iostream.h> + #include <fstream.h> + #include <iomanip.h> +#endif + +#ifdef DICOM_DLL + #ifdef DICOM_EXPORT_SYMBOLS + #define DICOM_EXPORT __declspec(dllexport) + #define DICOM_EXPIMP_TEMPLATE + #else + #define DICOM_EXPORT __declspec(dllimport) + #define DICOM_EXPIMP_TEMPLATE extern + #endif +#else + #define DICOM_EXPORT +#endif + +#endif // __DICOM_CONFIG_H_ diff --git a/Utilities/ITK/Utilities/DICOMParser/DICOMFile.cxx b/Utilities/ITK/Utilities/DICOMParser/DICOMFile.cxx new file mode 100644 index 0000000000000000000000000000000000000000..36cf29422c583b8ec84e51d2f39c6bf791c70eb6 --- /dev/null +++ b/Utilities/ITK/Utilities/DICOMParser/DICOMFile.cxx @@ -0,0 +1,128 @@ +/*========================================================================= + + Program: DICOMParser + Module: $RCSfile: DICOMFile.cxx,v $ + Language: C++ + Date: $Date: 2004/03/21 21:40:03 $ + Version: $Revision: 1.20 $ + + Copyright (c) 2003 Matt Turek + All rights reserved. + See Copyright.txt 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. + +=========================================================================*/ + +#ifdef _MSC_VER +#pragma warning ( disable : 4514 ) +#pragma warning ( disable : 4710 ) +#pragma warning ( push, 3 ) +#endif + +#include <stdio.h> +#include <string> + +#include "DICOMConfig.h" +#include "DICOMFile.h" + +namespace DICOMPARSER_NAMESPACE +{ +DICOMFile::DICOMFile() : DICOMSource(), InputStream() +{ +} + +DICOMFile::~DICOMFile() +{ + this->Close(); +} + +DICOMFile::DICOMFile(const DICOMFile& in) + : DICOMSource(in) +{ + // + // Some compilers can't handle. Comment out for now. + // + // InputStream = in.InputStream; +} + +void DICOMFile::operator=(const DICOMFile& in) +{ + DICOMSource::operator=(in); + + // + // Some compilers can't handle. Comment out for now. + // + // InputStream = in.InputStream; +} + +bool DICOMFile::Open(const dicom_stl::string& filename) +{ +#ifdef _WIN32 + InputStream.open(filename.c_str(), dicom_stream::ios::binary | dicom_stream::ios::in); +#else + InputStream.open(filename.c_str(), dicom_stream::ios::in); +#endif + + //if (InputStream.is_open()) + if (InputStream.rdbuf()->is_open()) + { + return true; + } + else + { + return false; + } +} + +void DICOMFile::Close() +{ + InputStream.close(); +} + +long DICOMFile::Tell() +{ + long loc = InputStream.tellg(); + // dicom_stream::cout << "Tell: " << loc << dicom_stream::endl; + return loc; +} + +void DICOMFile::SkipToPos(long increment) +{ + InputStream.seekg(increment, dicom_stream::ios::beg); +} + +long DICOMFile::GetSize() +{ + long curpos = this->Tell(); + + InputStream.seekg(0,dicom_stream::ios::end); + + long size = this->Tell(); + // dicom_stream::cout << "Tell says size is: " << size << dicom_stream::endl; + this->SkipToPos(curpos); + + return size; +} + +void DICOMFile::Skip(long increment) +{ + InputStream.seekg(increment, dicom_stream::ios::cur); +} + +void DICOMFile::SkipToStart() +{ + InputStream.seekg(0, dicom_stream::ios::beg); +} + +void DICOMFile::Read(void* ptr, long nbytes) +{ + InputStream.read((char*)ptr, nbytes); + // dicom_stream::cout << "DICOMFile::Read " << (char*) ptr << dicom_stream::endl; +} +} +#ifdef _MSC_VER +#pragma warning ( pop ) +#endif diff --git a/Utilities/ITK/Utilities/DICOMParser/DICOMFile.h b/Utilities/ITK/Utilities/DICOMParser/DICOMFile.h new file mode 100644 index 0000000000000000000000000000000000000000..7d4345cace9f838e189844299abd208ba119c7e5 --- /dev/null +++ b/Utilities/ITK/Utilities/DICOMParser/DICOMFile.h @@ -0,0 +1,108 @@ +/*========================================================================= + + Program: DICOMParser + Module: $RCSfile: DICOMFile.h,v $ + Language: C++ + Date: $Date: 2004/03/21 21:40:03 $ + Version: $Revision: 1.21 $ + + Copyright (c) 2003 Matt Turek + All rights reserved. + See Copyright.txt 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. + +=========================================================================*/ + +#ifndef __DICOMFILE_H_ +#define __DICOMFILE_H_ + +#ifdef _MSC_VER +#pragma warning ( disable : 4514 ) +#pragma warning ( push, 3 ) +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string> + +#include "DICOMTypes.h" +#include "DICOMConfig.h" +#include "DICOMSource.h" + +namespace DICOMPARSER_NAMESPACE +{ +// +// DICOM data source that is file. +// +class DICOM_EXPORT DICOMFile : public DICOMSource +{ + public: + DICOMFile(); + virtual ~DICOMFile(); + + // + // Open a file with filename. Returns a bool + // that is true if the file is successfully + // opened. + // + bool Open(const dicom_stl::string& filename); + + // + // Close a file. + // + void Close(); + + // + // Return the position in the file. + // + long Tell(); + + // + // Move to a particular position in the file. + // + void SkipToPos(long); + + // + // Return the size of the file. + // + long GetSize(); + + // + // Skip a number of bytes. + // + void Skip(long); + + // + // Skip to the beginning of the file. + // + void SkipToStart(); + + // + // Read data of length len. + // + void Read(void* data, long len); + + protected: + DICOMFile(const DICOMFile&); + void operator=(const DICOMFile&); + + // + // Internal storage for the file pointer. + // + dicom_stream::ifstream InputStream; + + + private: + +}; +} +#ifdef _MSC_VER +#pragma warning ( pop ) +#endif + +#endif // __DICOMFILE_H_ + + diff --git a/Utilities/ITK/Utilities/DICOMParser/DICOMParser.cxx b/Utilities/ITK/Utilities/DICOMParser/DICOMParser.cxx new file mode 100644 index 0000000000000000000000000000000000000000..c6ad302a94363037afa8bf4c81cda266dc625369 --- /dev/null +++ b/Utilities/ITK/Utilities/DICOMParser/DICOMParser.cxx @@ -0,0 +1,866 @@ +/*========================================================================= + + Program: DICOMParser + Module: $RCSfile: DICOMParser.cxx,v $ + Language: C++ + Date: $Date: 2005/07/25 00:13:49 $ + Version: $Revision: 1.37 $ + + Copyright (c) 2003 Matt Turek + All rights reserved. + See Copyright.txt 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. + +=========================================================================*/ + + +#ifdef _MSC_VER +#pragma warning ( disable : 4514 ) +#pragma warning ( disable : 4786 ) +#pragma warning ( disable : 4503 ) +#pragma warning ( disable : 4710 ) +#pragma warning ( push, 3 ) +#endif + + +#include <stdlib.h> +#if !defined(__MWERKS__) +#include <math.h> +#endif +#include <time.h> +#include <assert.h> +#if !defined(__MWERKS__) +#include <sys/types.h> +#endif + +#include <string> +#include <map> + +#include "DICOMConfig.h" +#include "DICOMParser.h" +#include "DICOMCallback.h" +#include "DICOMBuffer.h" + +namespace DICOMPARSER_NAMESPACE +{ + +// Define DEBUG_DICOM to get debug messages sent to dicom_stream::cerr +// #define DEBUG_DICOM + +#define DICOMPARSER_IGNORE_MAGIC_NUMBER + +#ifdef DEBUG_DICOM +#define DICOM_DBG_MSG(x) {dicom_stream::cout x} +#else +#define DICOM_DBG_MSG(x) +#endif + +static const char* DICOM_MAGIC = "DICM"; +static const int OPTIONAL_SKIP = 128; + +class DICOMParserImplementation +{ +public: + DICOMParserImplementation() : Groups(), Elements(), Datatypes(), Map(), TypeMap() + { + + }; + + dicom_stl::vector<doublebyte> Groups; + dicom_stl::vector<doublebyte> Elements; + dicom_stl::vector<DICOMParser::VRTypes> Datatypes; + // + // Stores a map from pair<group, element> keys to + // values of pair<vector<DICOMCallback*>, datatype> + // + DICOMParserMap Map; + + // + // Stores a map from pair<group, element> keys to + // values of datatype. We use this to store the + // datatypes for implicit keys that we are + // interested in. + // + DICOMImplicitTypeMap TypeMap; + +}; + +DICOMParser::DICOMParser() : ParserOutputFile() +{ + this->Implementation = new DICOMParserImplementation(); + this->DataFile = NULL; + this->ToggleByteSwapImageData = false; + this->TransferSyntaxCB = new DICOMMemberCallback<DICOMParser>; + this->InitTypeMap(); + this->FileName = ""; +} + +const dicom_stl::string& +DICOMParser::GetFileName() +{ + return this->FileName; +} + +bool DICOMParser::OpenFile(const dicom_stl::string& filename) +{ + if (this->DataFile) + { + // Deleting the DataFile closes the file + delete this->DataFile; + } + this->DataFile = new DICOMFile(); + bool val = this->DataFile->Open(filename); + + if (val) + { + this->FileName = filename; + } + + +#ifdef DEBUG_DICOM + if (this->ParserOutputFile.rdbuf()->is_open()) + { + this->ParserOutputFile.flush(); + this->ParserOutputFile.close(); + } + + dicom_stl::string fn(filename); + dicom_stl::string append(".parser.txt"); + dicom_stl::string parseroutput(fn + append); + // dicom_stl::string parseroutput(dicom_stl::string(dicom_stl::string(filename) + dicom_stl::string(".parser.txt"))); + this->ParserOutputFile.open(parseroutput.c_str()); //, dicom_stream::ios::app); +#endif + + return val; +} + +DICOMParser::~DICOMParser() { + // + // Delete the callbacks. + // + this->ClearAllDICOMTagCallbacks(); + + if (this->DataFile) + { + delete this->DataFile; + } + + delete this->TransferSyntaxCB; + delete this->Implementation; + +#ifdef DEBUG_DICOM + this->ParserOutputFile.flush(); + this->ParserOutputFile.close(); +#endif + +} + +bool DICOMParser::ReadHeader() +{ + return this->ReadHeader(*this->DataFile); +} + +bool DICOMParser::ReadHeader(DICOMSource &source) +{ + bool dicom = this->IsDICOMFile(source); + if (!dicom) + { + return false; + } + + this->TransferSyntaxCB->SetCallbackFunction(this, &DICOMParser::TransferSyntaxCallback); + this->AddDICOMTagCallback(0x0002, 0x0010, DICOMParser::VR_UI, this->TransferSyntaxCB); + + this->ToggleByteSwapImageData = false; + + doublebyte group = 0; + doublebyte element = 0; + DICOMParser::VRTypes datatype = DICOMParser::VR_UNKNOWN; + + this->Implementation->Groups.clear(); + this->Implementation->Elements.clear(); + this->Implementation->Datatypes.clear(); + + long fileSize = source.GetSize(); + do + { + this->ReadNextRecord(source, group, element, datatype); + + this->Implementation->Groups.push_back(group); + this->Implementation->Elements.push_back(element); + this->Implementation->Datatypes.push_back(datatype); + + } while ((source.Tell() >= 0) && (source.Tell() < fileSize)); + + return true; +} + +// +// read magic number from file +// return true if this is your image type, false if it is not +// +bool DICOMParser::IsDICOMFile(DICOMSource &source) +{ + char magic_number[4]; + magic_number[0] = magic_number[1] = magic_number[2] = magic_number[3] = 'x'; + source.SkipToStart(); + source.Read((void*)magic_number,4); + if (CheckMagic(magic_number)) + { + return(true); + } + // try with optional skip + else + { + source.Skip(OPTIONAL_SKIP-4); + source.Read((void*)magic_number,4); + if (CheckMagic(magic_number)) + { + return true; + } + else + { + +#ifndef DICOMPARSER_IGNORE_MAGIC_NUMBER + return false; +#else + // + // Try it anyways... + // + + source.SkipToStart(); + + doublebyte group = source.ReadDoubleByte(); + bool dicom; + if (group == 0x0002 || group == 0x0008) + { + dicom_stream::cerr << "No DICOM magic number found, but file appears to be DICOM." << dicom_stream::endl; + dicom_stream::cerr << "Proceeding without caution." << dicom_stream::endl; + dicom = true; + } + else + { + dicom = false; + } + source.SkipToStart(); + + return dicom; +#endif // DICOMPARSER_IGNORE_MAGIC_NUMBER + + } + } +} + + +bool DICOMParser::IsValidRepresentation(DICOMSource &source, doublebyte rep, quadbyte& len, VRTypes &mytype) +{ + switch (rep) + { + case DICOMParser::VR_AW: + case DICOMParser::VR_AE: + case DICOMParser::VR_AS: + case DICOMParser::VR_CS: + case DICOMParser::VR_UI: + case DICOMParser::VR_DA: + case DICOMParser::VR_DS: + case DICOMParser::VR_DT: + case DICOMParser::VR_IS: + case DICOMParser::VR_LO: + case DICOMParser::VR_LT: + case DICOMParser::VR_PN: + case DICOMParser::VR_ST: + case DICOMParser::VR_TM: + case DICOMParser::VR_UT: // new + case DICOMParser::VR_SH: + case DICOMParser::VR_FL: + case DICOMParser::VR_SL: + case DICOMParser::VR_AT: + case DICOMParser::VR_UL: + case DICOMParser::VR_US: + case DICOMParser::VR_SS: + case DICOMParser::VR_FD: + len = source.ReadDoubleByte(); + mytype = VRTypes(rep); + return true; + + case DICOMParser::VR_OB: // OB - LE + case DICOMParser::VR_OW: + case DICOMParser::VR_UN: + source.ReadDoubleByte(); + len = source.ReadQuadByte(); + mytype = VRTypes(rep); + return true; + case DICOMParser::VR_SQ: + source.ReadDoubleByte(); + len = source.ReadQuadByte(); + mytype = VRTypes(rep); + return true; + + default: + // + // + // Need to comment out in new paradigm. + // + source.Skip(-2); + len = source.ReadQuadByte(); + mytype = DICOMParser::VR_UNKNOWN; + return false; + } +} + + +void DICOMParser::ReadNextRecord(DICOMSource &source, doublebyte& group, doublebyte& element, + DICOMParser::VRTypes& mytype) +{ + // dicom_stream::cout << "ReadNextRecord() " << dicom_stream::endl; + + group = source.ReadDoubleByte(); + element = source.ReadDoubleByte(); + + //dicom_stream::cout << "(" << dicom_stream::hex << group << ", " << element << ") : " ; + + doublebyte representation = source.ReadDoubleByteAsLittleEndian(); + quadbyte length = 0; + mytype = DICOMParser::VR_UNKNOWN; + this->IsValidRepresentation(source, representation, length, mytype); + +// dicom_stream::cout << "representation = " << representation << dicom_stream::dec << ", length = " << length +// << dicom_stream::endl; + + DICOMParserMap::iterator iter = + Implementation->Map.find(DICOMMapKey(group,element)); + + VRTypes callbackType; + + if (iter != Implementation->Map.end()) + { + // + // Only read the data if there's a registered callback. + // + unsigned char* tempdata; + + if (static_cast<unsigned long>(length) != static_cast<unsigned long>(-1)) + { + // length was specified + tempdata = (unsigned char*) source.ReadAsciiCharArray(length); + } + else + { + // unspecified length, read block as sequence + doublebyte dataelementtag[2]; + quadbyte itemLength; + + dataelementtag[0] = source.ReadDoubleByte(); + dataelementtag[1] = source.ReadDoubleByte(); + while (dataelementtag[0] == 0xfffe && dataelementtag[1] == 0xe000) // item tag + { + //dicom_stream::cout << "Item tag: "; + + // read the length of the buffer + itemLength = source.ReadQuadByte(); + //dicom_stream::cout << itemLength << dicom_stream::endl; + + // read the buffer + if (itemLength != 0) + { + tempdata = (unsigned char *) source.ReadAsciiCharArray(itemLength); + // should accumulate the block of memory in case the image + // is broken into several items + } + + // read the delimination tag + dataelementtag[0] = source.ReadDoubleByte(); + dataelementtag[1] = source.ReadDoubleByte(); + } + // check for sequence delimination item + if (dataelementtag[0] == 0xfffe && dataelementtag[1] == 0xe0dd) + { + // read the empty length + source.ReadQuadByte(); + } + } + + + DICOMMapKey ge = (*iter).first; + callbackType = VRTypes(((*iter).second.first)); + + if (callbackType != mytype && + mytype != VR_UNKNOWN) + { + // + // mytype is not VR_UNKNOWN if the file is in Explicit format. + // + callbackType = mytype; + } + +#ifdef DEBUG_DICOM + this->DumpTag(this->ParserOutputFile, group, element, callbackType, tempdata, length); +#endif + + dicom_stl::pair<const DICOMMapKey,DICOMMapValue> p = *iter; + DICOMMapValue mv = p.second; + + bool doSwap = (this->ToggleByteSwapImageData ^ source.GetPlatformIsBigEndian()) && callbackType == VR_OW; + + if (group == 0x7FE0 && + element == 0x0010 ) + { + if (doSwap) + { + DICOMSource::swapShorts((ushort*) tempdata, (ushort*) tempdata, length/sizeof(ushort)); + } + } + else + { + if (source.GetPlatformIsBigEndian() == true) + { + switch (callbackType) + { + case DICOMParser::VR_OW: + case DICOMParser::VR_US: + case DICOMParser::VR_SS: + DICOMSource::swapShorts((ushort*) tempdata, (ushort*) tempdata, length/sizeof(ushort)); + break; + case DICOMParser::VR_FL: + case DICOMParser::VR_FD: + break; + case DICOMParser::VR_SL: + case DICOMParser::VR_UL: + DICOMSource::swapLongs((ulong*) tempdata, (ulong*) tempdata, length/sizeof(ulong)); + break; + case DICOMParser::VR_AT: + break; + default: + break; + } + } + } + + dicom_stl::vector<DICOMCallback*> * cbVector = mv.second; + for (dicom_stl::vector<DICOMCallback*>::iterator cbiter = cbVector->begin(); + cbiter != cbVector->end(); + cbiter++) + { + (*cbiter)->Execute(this, // parser + ge.first, // group + ge.second, // element + callbackType, // type + tempdata, // data + length); // length + } + + // If the datatype was a sequence, then recurse down the sequence + if (callbackType == DICOMParser::VR_SQ) + { + this->ParseSequence(tempdata, length); + } + + delete [] tempdata; + } + else + { + // + // Some lengths are negative, but we don't + // want to back up the file pointer. + // + if (length > 0) + { + source.Skip(length); + } +#ifdef DEBUG_DICOM + this->DumpTag(this->ParserOutputFile, group, element, mytype, (unsigned char*) "Unread.", length); +#endif + } +} + +void DICOMParser::ParseSequence(unsigned char *buffer, quadbyte len) +{ + // dicom_stream::cout << dicom_stream::dec << "ParseSequence(), len = " << len << dicom_stream::endl; + + // Create a DICOM wrapper around the buffer + DICOMBuffer DataBuffer(buffer, len); + + doublebyte dataelementtag[2]; + quadbyte itemLength; + + while (DataBuffer.Tell() < len) + { + // Read the data element tag. Should be FFFEE0000 + dataelementtag[0] = DataBuffer.ReadDoubleByte(); + dataelementtag[1] = DataBuffer.ReadDoubleByte(); + + if (dataelementtag[0] != 0xfffe || dataelementtag[1] != 0xe000) + { + dicom_stream::cerr << "DICOMParser:: sequence missing data element tag. Skipping rest of sequence." << dicom_stream::endl; + return; + } + + itemLength = DataBuffer.ReadQuadByte(); + //dicom_stream::cout << "itemLength = " << dicom_stream::hex << itemLength << dicom_stream::dec << dicom_stream::endl; + + if (static_cast<unsigned int>(itemLength) == 0xFFFFFFFFul) + { + // undetermined length. punt for now + dicom_stream::cerr << "DICOMParser:: sequence of undetermined length. Skipping sequence." << dicom_stream::endl; + return; + } + else + { + // Get the block of data for this item + char *itemValue; + itemValue = DataBuffer.ReadAsciiCharArray(itemLength); + + // Wrap this data block into a DICOMBuffer + DICOMBuffer tBuffer((unsigned char *)itemValue, itemLength); + + // Parse the DICOMBuffer + while (tBuffer.Tell() < itemLength) + { + doublebyte group=0; + doublebyte element=0; + DICOMParser::VRTypes datatype = DICOMParser::VR_UNKNOWN; + + this->ReadNextRecord(tBuffer, group, element, datatype); + + this->Implementation->Groups.push_back(group); + this->Implementation->Elements.push_back(element); + this->Implementation->Datatypes.push_back(datatype); + } + + delete [] itemValue; + } + } + + return; + +} + +void DICOMParser::InitTypeMap() +{ + DICOMRecord dicom_tags[] = {{0x0002, 0x0002, DICOMParser::VR_UI}, // Media storage SOP class uid + {0x0002, 0x0003, DICOMParser::VR_UI}, // Media storage SOP inst uid + {0x0002, 0x0010, DICOMParser::VR_UI}, // Transfer syntax uid + {0x0002, 0x0012, DICOMParser::VR_UI}, // Implementation class uid + {0x0008, 0x0018, DICOMParser::VR_UI}, // Image UID + {0x0008, 0x0020, DICOMParser::VR_DA}, // Series date + {0x0008, 0x0030, DICOMParser::VR_TM}, // Series time + {0x0008, 0x0060, DICOMParser::VR_SH}, // Modality + {0x0008, 0x0070, DICOMParser::VR_SH}, // Manufacturer + {0x0008, 0x0080, DICOMParser::VR_LO}, // Institution + {0x0008, 0x1060, DICOMParser::VR_SH}, // Physician + {0x0008, 0x1090, DICOMParser::VR_LO}, // Model + {0x0010, 0x0010, DICOMParser::VR_PN}, // Patient name + {0x0010, 0x0020, DICOMParser::VR_LO}, // Patient ID + {0x0010, 0x0040, DICOMParser::VR_CS}, // Patient sex + {0x0010, 0x1010, DICOMParser::VR_AS}, // Patient age + {0x0018, 0x0050, DICOMParser::VR_FL}, // slice thickness + {0x0018, 0x0060, DICOMParser::VR_FL}, // kV + {0x0018, 0x0088, DICOMParser::VR_FL}, // slice spacing + {0x0018, 0x1100, DICOMParser::VR_SH}, // Recon diameter + {0x0018, 0x1151, DICOMParser::VR_FL}, // mA + {0x0018, 0x1210, DICOMParser::VR_SH}, // Recon kernel + {0x0020, 0x000d, DICOMParser::VR_UI}, // Study UID + {0x0020, 0x000e, DICOMParser::VR_UI}, // Series UID + {0x0020, 0x0013, DICOMParser::VR_IS}, // Image number + {0x0020, 0x0032, DICOMParser::VR_SH}, // Patient position + {0x0020, 0x0037, DICOMParser::VR_SH}, // Patient position cosines + {0x0028, 0x0010, DICOMParser::VR_US}, // Num rows + {0x0028, 0x0011, DICOMParser::VR_US}, // Num cols + {0x0028, 0x0030, DICOMParser::VR_FL}, // pixel spacing + {0x0028, 0x0100, DICOMParser::VR_US}, // Bits allocated + {0x0028, 0x0120, DICOMParser::VR_UL}, // pixel padding + {0x0028, 0x1052, DICOMParser::VR_FL}, // pixel offset + {0x7FE0, 0x0010, DICOMParser::VR_OW} // pixel data + }; + + + int num_tags = sizeof(dicom_tags)/sizeof(DICOMRecord); + + doublebyte group; + doublebyte element; + VRTypes datatype; + + for (int i = 0; i < num_tags; i++) + { + group = dicom_tags[i].group; + element = dicom_tags[i].element; + datatype = (VRTypes) dicom_tags[i].datatype; + Implementation->TypeMap.insert(dicom_stl::pair<const DICOMMapKey, DICOMTypeValue>(DICOMMapKey(group, element), datatype)); + } + +} + + +void DICOMParser::SetDICOMTagCallbacks(doublebyte group, doublebyte element, VRTypes datatype, dicom_stl::vector<DICOMCallback*>* cbVector) +{ + Implementation->Map.insert(dicom_stl::pair<const DICOMMapKey, DICOMMapValue>(DICOMMapKey(group, element), DICOMMapValue((int)datatype, cbVector))); +} + + +bool DICOMParser::CheckMagic(char* magic_number) +{ + return ( + (magic_number[0] == DICOM_MAGIC[0]) && + (magic_number[1] == DICOM_MAGIC[1]) && + (magic_number[2] == DICOM_MAGIC[2]) && + (magic_number[3] == DICOM_MAGIC[3]) + ); +} + +void DICOMParser::DumpTag(dicom_stream::ostream& out, doublebyte group, doublebyte element, VRTypes vrtype, unsigned char* tempdata, quadbyte length) +{ + + int t2 = int((0x0000FF00 & vrtype) >> 8); + int t1 = int((0x000000FF & vrtype)); + + if (t1 == 0 && t2 == 0) + { + t1 = '?'; + t2 = '?'; + } + + char ct2(t2); + char ct1(t1); + + out << "(0x"; + + out.width(4); + char prev = out.fill('0'); + + out << dicom_stream::hex << group; + out << ",0x"; + + out.width(4); + out.fill('0'); + + out << dicom_stream::hex << element; + out << ") "; + + out.fill(prev); + out << dicom_stream::dec; + out << " " << ct1 << ct2 << " "; + out << "[" << length << " bytes] "; + + if (group == 0x7FE0 && element == 0x0010) + { + out << "Image data not printed." ; + } + else if (group == 0x0047 && element == 0x20d1) + { + out << "Volume segment list not printed."; + } + else if (group == 0x0047 && element == 0x20d3) + { + out << "Volume density list not printed."; + } + else + { + out << (tempdata ? (char*) tempdata : "NULL"); + } + + out << dicom_stream::dec << dicom_stream::endl; + out.fill(prev); + out << dicom_stream::dec; + + return; + +} + +void DICOMParser::ModalityTag(doublebyte, doublebyte, VRTypes, unsigned char* tempdata, quadbyte) +{ + if (!strcmp( (char*)tempdata, "MR")) + { + // this->AddMRTags(); + } + else if (!strcmp((char*) tempdata, "CT")) + { + } + else if (!strcmp((char*) tempdata, "US")) + { + } +} + +void DICOMParser::AddDICOMTagCallbacks(doublebyte group, doublebyte element, VRTypes datatype, dicom_stl::vector<DICOMCallback*>* cbVector) +{ + DICOMParserMap::iterator miter = Implementation->Map.find(DICOMMapKey(group,element)); + if (miter != Implementation->Map.end()) + { + for (dicom_stl::vector<DICOMCallback*>::iterator iter = cbVector->begin(); + iter != cbVector->end(); + iter++) + { + dicom_stl::vector<DICOMCallback*>* callbacks = (*miter).second.second; + callbacks->push_back(*iter); + } + } + else + { + this->SetDICOMTagCallbacks(group, element, datatype, cbVector); + } +} + +void DICOMParser::AddDICOMTagCallback(doublebyte group, doublebyte element, VRTypes datatype, DICOMCallback* cb) +{ + DICOMParserMap::iterator miter = Implementation->Map.find(DICOMMapKey(group,element)); + if (miter != Implementation->Map.end()) + { + dicom_stl::vector<DICOMCallback*>* callbacks = (*miter).second.second; + callbacks->push_back(cb); + } + else + { + dicom_stl::vector<DICOMCallback*>* callback = new dicom_stl::vector<DICOMCallback*>; + callback->push_back(cb); + this->SetDICOMTagCallbacks(group, element, datatype, callback); + } +} + +void DICOMParser::AddDICOMTagCallbackToAllTags(DICOMCallback* cb) +{ + DICOMParserMap::iterator miter; + for (miter = Implementation->Map.begin(); + miter != Implementation->Map.end(); + miter++); + { + dicom_stl::vector<DICOMCallback*>* callbacks = (*miter).second.second; + callbacks->push_back(cb); + } +} + +bool DICOMParser::ParseExplicitRecord(doublebyte, doublebyte, + quadbyte& length, + VRTypes& represent) +{ + doublebyte representation = this->DataFile->ReadDoubleByte(); + + bool valid = this->IsValidRepresentation(*this->DataFile, representation, length, represent); + + if (valid) + { + return true; + } + else + { + represent = VR_UNKNOWN; + length = 0; + return false; + } +} + +bool DICOMParser::ParseImplicitRecord(doublebyte group, doublebyte element, + quadbyte& length, + VRTypes& represent) +{ + DICOMImplicitTypeMap::iterator iter = + Implementation->TypeMap.find(DICOMMapKey(group,element)); + represent = VRTypes((*iter).second); + // + // length? + // + length = this->DataFile->ReadQuadByte(); + return false; +} + + + +void DICOMParser::TransferSyntaxCallback(DICOMParser *, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte) + +{ +#ifdef DEBUG_DICOM + dicom_stream::cout << "DICOMParser::TransferSyntaxCallback" << dicom_stream::endl; +#endif + + const char* TRANSFER_UID_EXPLICIT_BIG_ENDIAN = "1.2.840.10008.1.2.2"; + const char* TRANSFER_UID_GE_PRIVATE_IMPLICIT_BIG_ENDIAN = "1.2.840.113619.5.2"; + + // char* fileEndian = "LittleEndian"; + // char* dataEndian = "LittleEndian"; + + this->ToggleByteSwapImageData = false; + + if (strcmp(TRANSFER_UID_EXPLICIT_BIG_ENDIAN, (char*) val) == 0) + { +#ifdef DEBUG_DICOM + dicom_stream::cout << "EXPLICIT BIG ENDIAN" << dicom_stream::endl; +#endif + this->ToggleByteSwapImageData = true; + // + // Data byte order is big endian + // + // We're always reading little endian in the beginning, + // so now we need to swap. + } + else if (strcmp(TRANSFER_UID_GE_PRIVATE_IMPLICIT_BIG_ENDIAN, (char*) val) == 0) + { + this->ToggleByteSwapImageData = true; +#ifdef DEBUG_DICOM + dicom_stream::cout << "GE PRIVATE TRANSFER SYNTAX" << dicom_stream::endl; + dicom_stream::cout << "ToggleByteSwapImageData : " << this->ToggleByteSwapImageData << dicom_stream::endl; +#endif + } + else + { + } +} + +void DICOMParser::GetGroupsElementsDatatypes(dicom_stl::vector<doublebyte>& groups, + dicom_stl::vector<doublebyte>& elements, + dicom_stl::vector<DICOMParser::VRTypes>& datatypes) +{ + groups.clear(); + elements.clear(); + datatypes.clear(); + + dicom_stl::vector<doublebyte>::iterator giter; // = this->Groups.begin(); + dicom_stl::vector<doublebyte>::iterator eiter; // = this->Elements.begin(); + dicom_stl::vector<DICOMParser::VRTypes>::iterator diter; // = this->Datatypes.begin(); + + for (giter = this->Implementation->Groups.begin(), eiter = this->Implementation->Elements.begin(), diter = this->Implementation->Datatypes.begin(); + giter != this->Implementation->Groups.end(), eiter != this->Implementation->Elements.end(), diter != this->Implementation->Datatypes.end(); + giter++, eiter++, diter++) + { + groups.push_back(*giter); + elements.push_back(*eiter); + datatypes.push_back(*diter); + } +} + +void DICOMParser::ClearAllDICOMTagCallbacks() +{ + DICOMParserMap::iterator mapIter; + + for (mapIter = this->Implementation->Map.begin(); + mapIter != this->Implementation->Map.end(); + mapIter++) + { + dicom_stl::pair<const DICOMMapKey, DICOMMapValue> mapPair = *mapIter; + DICOMMapValue mapVal = mapPair.second; + dicom_stl::vector<DICOMCallback*>* cbVector = mapVal.second; + + delete cbVector; + } + + this->Implementation->Map.clear(); +} + +DICOMParser::DICOMParser(const DICOMParser&) +{ + dicom_stream::cerr << "DICOMParser copy constructor should not be called!" << dicom_stream::endl; +} + +void DICOMParser::operator=(const DICOMParser&) +{ + dicom_stream::cerr << "DICOMParser assignment operator should not be called!" << dicom_stream::endl; +} +} +#ifdef _MSC_VER +#pragma warning ( pop ) +#endif diff --git a/Utilities/ITK/Utilities/DICOMParser/DICOMParser.h b/Utilities/ITK/Utilities/DICOMParser/DICOMParser.h new file mode 100644 index 0000000000000000000000000000000000000000..11346115432353ecc10c6cb605ee998b69fd0cc4 --- /dev/null +++ b/Utilities/ITK/Utilities/DICOMParser/DICOMParser.h @@ -0,0 +1,279 @@ +/*========================================================================= + + Program: DICOMParser + Module: $RCSfile: DICOMParser.h,v $ + Language: C++ + Date: $Date: 2004/03/21 21:40:03 $ + Version: $Revision: 1.17 $ + + Copyright (c) 2003 Matt Turek + All rights reserved. + See Copyright.txt 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. + +=========================================================================*/ + +#ifndef __DICOMParser_h_ +#define __DICOMParser_h_ + + +#ifdef _MSC_VER +#pragma warning ( disable : 4514 ) +#pragma warning ( disable : 4786 ) +#pragma warning ( disable : 4503 ) +#pragma warning ( disable : 4710 ) +#pragma warning ( disable : 4702 ) +#pragma warning ( push, 3 ) +#endif + + +#include <map> +#include <utility> +#include <vector> + +#include "DICOMConfig.h" +#include "DICOMFile.h" +#include "DICOMTypes.h" +#include "DICOMParserMap.h" + +namespace DICOMPARSER_NAMESPACE +{ +class DICOMBuffer; +class DICOMCallback; +template <class T> class DICOMMemberCallback; + +//DICOM_EXPIMP_TEMPLATE template class DICOM_EXPORT dicom_stl::vector<doublebyte>; + +class DICOMParserImplementation; + +// +// We should keep a map with the implicit types for the groups and elements +// separate from the callbacks. We can use this for the implicit types. +// +// + +class DICOM_EXPORT DICOMParser +{ + public: + + // + // Default constructor + // + DICOMParser(); + + // + // Default destructor. + // + virtual ~DICOMParser(); + + // + // Opens a file and initializes the parser. + // + bool OpenFile(const dicom_stl::string& filename); + + // + // Return the name of the file last processed. + // + const dicom_stl::string& GetFileName(); + + // + // This method kicks off the parser. + // OpenFile needs to be called first. + // + bool ReadHeader(); + + // + // This method can kick off the parser on a provided DICOM source + // (either a DICOMFile or DICOMBuffer) + // + bool ReadHeader(DICOMSource &source); + + // + // Static method that returns true if a DICOMSource + // contains a DICOM image. + // + static bool IsDICOMFile(DICOMSource &file); + + bool IsDICOMFile() + { + if (!this->DataFile) + { + return false; + } + return DICOMParser::IsDICOMFile(*(this->DataFile)); + } + + // + // Static method that checks the DICOM magic number. + // + static bool CheckMagic(char* magic_number); + + // + // Defined DICOM types. + // + enum VRTypes + { + VR_UNKNOWN = 0x0, + VR_OB=0x424f, // Other byte string (string of bytes, insensitive to byte order) + VR_AW=0x5741, + VR_AE=0x4541, // Application Entity (char string) + VR_AS=0x5341, // Age string (char string) + VR_CS=0x5343, // Code string (char string, leading/trailing spaces insignificant) + VR_UI=0x4955, // UID (character string) + VR_DA=0x4144, // Date (char string) + VR_DS=0x5344, // Decimal string (char string representing a fixed/floating pt number) + VR_DT=0x5444, // Date Time (char string) + VR_IS=0x5349, // Integer string (char string representing an integer) + VR_LO=0x4f4c, // Long string (character string padded with leading/trailing spaces) + VR_LT=0x544c, // Long text (character string with one or more paragraphs.) + VR_OW=0x574f, // Other word string (sensitive to byte order, transfer syntax) + VR_PN=0x4e50, // Person name (character string) + VR_ST=0x5453, // Short text (character string, one or more paragraphs) + VR_TM=0x4d54, // Time (character string) + VR_UN=0x4e55, + VR_UT=0x5455, // Unlimited text (character string) + VR_SQ=0x5153, // Sequence of items + VR_SH=0x4853, // Short string (character string with leading/trailing spaces). + VR_FL=0x4c46, // Floating point single precision + VR_SL=0x4c53, // Signed long, (signed 32bits, 2's complement form.) + VR_AT=0x5441, // Attribute tag (ordered pair 16 bit unsigned) + VR_UL=0x4c55, // Unsigned long (unsigned 32 bits) + VR_US=0x5355, // Unsigned short (unsigned 16 bits) + VR_SS=0x5353, // Signed short, (signed 16bits, 2's complement) + VR_FD=0x4446 // Floating point double precision + }; + + // + // Callback for the modality tag. + // + void ModalityTag(doublebyte group, doublebyte element, VRTypes datatype, unsigned char* tempdata, quadbyte length); + + void SetDICOMTagCallbacks(doublebyte group, doublebyte element, VRTypes datatype, dicom_stl::vector<DICOMCallback*>* cbVector); + void AddDICOMTagCallbacks(doublebyte group, doublebyte element, VRTypes datatype, dicom_stl::vector<DICOMCallback*>* cbVector); + void AddDICOMTagCallback (doublebyte group, doublebyte element, VRTypes datatype, DICOMCallback* cb); + void AddDICOMTagCallbackToAllTags(DICOMCallback* cb); + + DICOMFile* GetDICOMFile() + { + return this->DataFile; + } + + void ClearAllDICOMTagCallbacks(); + + + void TransferSyntaxCallback(DICOMParser *parser, + doublebyte, + doublebyte, + DICOMParser::VRTypes, + unsigned char* val, + quadbyte) ; + + void GetGroupsElementsDatatypes(dicom_stl::vector<doublebyte>& groups, + dicom_stl::vector<doublebyte>& elements, + dicom_stl::vector<VRTypes>& datatypes); + + protected: + + bool ParseExplicitRecord(doublebyte group, doublebyte element, + quadbyte& length, + VRTypes& represent); + + bool ParseImplicitRecord(doublebyte group, doublebyte element, + quadbyte& length, + VRTypes& represent); + // + // Print a tag. + // + // void DumpTag(doublebyte group, doublebyte element, VRTypes datatype, unsigned char* data, quadbyte length); + void DumpTag(dicom_stream::ostream& out, doublebyte group, doublebyte element, VRTypes vrtype, unsigned char* tempdata, quadbyte length); + + struct DICOMRecord + { + doublebyte group; + doublebyte element; + VRTypes datatype; + }; + + // + // Check to see if the type is a valid DICOM type. If not, figure + // out the right thing to do next (i.e. compute the element length). + // + bool IsValidRepresentation(DICOMSource &source, doublebyte rep, quadbyte& len, VRTypes &mytype); + + // + // Reads a record. + // + void ReadNextRecord(DICOMSource &source, doublebyte& group, doublebyte& element, DICOMParser::VRTypes& mytype); + + // + // Parse a sequence from a memory block + // + void ParseSequence(unsigned char *buffer, quadbyte len); + + // + // Sets up the type map. + // + void InitTypeMap(); + + // + // Flags for byte swaping header values and + // image data. + // + bool ByteSwap; + bool ByteSwapData; + + // + // Stores a map from pair<group, element> keys to + // values of pair<vector<DICOMCallback*>, datatype> + // + // DICOMParserMap Map; + + // + // Stores a map from pair<group, element> keys to + // values of datatype. We use this to store the + // datatypes for implicit keys that we are + // interested in. + // + // DICOMImplicitTypeMap TypeMap; + + // + // Used for outputting debug information. + // + dicom_stream::ofstream ParserOutputFile; + + // + // Pointer to the DICOMFile we're parsing. + // + DICOMFile* DataFile; + dicom_stl::string FileName; + + bool ToggleByteSwapImageData; + + //dicom_stl::vector<doublebyte> Groups; + //dicom_stl::vector<doublebyte> Elements; + //dicom_stl::vector<VRTypes> Datatypes; + + DICOMMemberCallback<DICOMParser>* TransferSyntaxCB; + + // + // Implementation contains stl templated classes that + // can't be exported from a DLL in Windows. We hide + // them in the implementation to get rid of annoying + // compile warnings. + // + DICOMParserImplementation* Implementation; + + private: + DICOMParser(const DICOMParser&); + void operator=(const DICOMParser&); +}; + +} +#ifdef _MSC_VER +#pragma warning ( pop ) +#endif + +#endif // __DICOMParser_h_ diff --git a/Utilities/ITK/Utilities/DICOMParser/DICOMParserMap.h b/Utilities/ITK/Utilities/DICOMParser/DICOMParserMap.h new file mode 100644 index 0000000000000000000000000000000000000000..7a8eae04b6e67a5b78224b1a595fcfa45467e9c1 --- /dev/null +++ b/Utilities/ITK/Utilities/DICOMParser/DICOMParserMap.h @@ -0,0 +1,143 @@ +/*========================================================================= + + Program: DICOMParser + Module: $RCSfile: DICOMParserMap.h,v $ + Language: C++ + Date: $Date: 2004/03/21 21:40:03 $ + Version: $Revision: 1.6 $ + + Copyright (c) 2003 Matt Turek + All rights reserved. + See Copyright.txt 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. + +=========================================================================*/ + +#ifndef __DICOM_PARSER_MAP__H_ +#define __DICOM_PARSER_MAP__H_ + +#ifdef _MSC_VER +#pragma warning ( disable : 4514 ) +#pragma warning ( disable : 4786 ) +#pragma warning ( disable : 4503 ) +#pragma warning ( disable : 4710 ) +#pragma warning ( disable : 4702 ) +#pragma warning ( push, 3 ) +#endif + +#include <map> +#include <utility> + +#include "DICOMConfig.h" + +namespace DICOMPARSER_NAMESPACE +{ +class DICOMCallback; + +// +// Structure that implements a compare operator for +// a pair of doublebytes. This is used when comparing +// group, element pairs. +// +struct group_element_compare +{ + bool operator() (const dicom_stl::pair<doublebyte, doublebyte> p1, const dicom_stl::pair<doublebyte, doublebyte> p2) const + { + if (p1.first < p2.first) + { + return true; + } + else if (p1.first == p2.first) + { + if (p1.second < p2.second) + { + return true; + } + else + { + return false; + } + } + else + { + return false; + } + } +}; + +// +// Typedef a pair of doublebytes +// +typedef dicom_stl::pair<doublebyte, doublebyte> DICOMMapKeyOverride; + +// DICOM_EXPIMP_TEMPLATE template struct DICOM_MAP_EXPORT dicom_stream::pair<doublebyte, doublebyte>; +// +// Subclass of a pair of doublebytes to make +// type names shorter in the code. +// +class DICOMMapKey : public DICOMMapKeyOverride +{ + public: + DICOMMapKey(doublebyte v1, doublebyte v2) : + dicom_stl::pair<doublebyte, doublebyte> (v1, v2) + { + + } + +}; + +// +// Typedef of a pair of doublebyte, vector. +// +typedef dicom_stl::pair<doublebyte, dicom_stl::vector<DICOMCallback*>*> DICOMMapValueOverride; + + +// DICOM_EXPIMP_TEMPLATE template struct DICOM_MAP_EXPORT dicom_stream::pair<doublebyte, dicom_stream::vector<DICOMCallback*>*>; + +// +// Subclass of pair doublebyte, vector<DICOMCallback*>. +// Makes types shorter in the code. +// +class DICOMMapValue : public DICOMMapValueOverride +{ + public: + DICOMMapValue() : dicom_stl::pair<doublebyte, dicom_stl::vector<DICOMCallback*>*>() {}; + + DICOMMapValue(doublebyte v1, dicom_stl::vector<DICOMCallback*> * v2) : + dicom_stl::pair<doublebyte, dicom_stl::vector<DICOMCallback*>*>(v1, v2) + { + + } +}; + + +// DICOM_EXPIMP_TEMPLATE template class DICOM_MAP_EXPORT dicom_stream::map<DICOMMapKey, DICOMMapValue, group_element_compare>; + +// +// Subclass of the particular map we're using. Again, +// makes type specifiers shorter in the code. +// +class DICOMParserMap : + public dicom_stl::map<DICOMMapKey, DICOMMapValue, group_element_compare> +{ + +}; + +typedef doublebyte DICOMTypeValue; + +// DICOM_EXPIMP_TEMPLATE template class dicom_stream::map<DICOMMapKey, DICOMTypeValue, group_element_compare>; + +class DICOMImplicitTypeMap : + public dicom_stl::map<DICOMMapKey, DICOMTypeValue, group_element_compare> +{ + +}; +} +#ifdef _MSC_VER +#pragma warning ( pop ) +#endif + +#endif diff --git a/Utilities/ITK/Utilities/DICOMParser/DICOMSource.cxx b/Utilities/ITK/Utilities/DICOMParser/DICOMSource.cxx new file mode 100644 index 0000000000000000000000000000000000000000..d206f4127d149047ef8b64fbd0e12c4ff347ba59 --- /dev/null +++ b/Utilities/ITK/Utilities/DICOMParser/DICOMSource.cxx @@ -0,0 +1,216 @@ +/*========================================================================= + + Program: DICOMParser + Module: $RCSfile: DICOMSource.cxx,v $ + Language: C++ + Date: $Date: 2004/03/21 21:40:03 $ + Version: $Revision: 1.2 $ + + Copyright (c) 2003 Matt Turek + All rights reserved. + See Copyright.txt 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. + +=========================================================================*/ + +#ifdef _MSC_VER +#pragma warning ( disable : 4514 ) +#pragma warning ( disable : 4710 ) +#pragma warning ( push, 3 ) +#endif + +#include <iostream> +#include <fstream> +#include <iomanip> +#include <stdio.h> +#include <string> + +#include "DICOMConfig.h" +#include "DICOMSource.h" + +namespace DICOMPARSER_NAMESPACE +{ +DICOMSource::DICOMSource() +{ + /* Are we little or big endian? From Harbison&Steele. */ + union + { + long l; + char c[sizeof (long)]; + } u; + u.l = 1; + PlatformIsBigEndian = (u.c[sizeof (long) - 1] == 1); + if (PlatformIsBigEndian) + { + PlatformEndian = "BigEndian"; + } + else + { + PlatformEndian = "LittleEndian"; + } +} + +DICOMSource::~DICOMSource() +{ +} + +DICOMSource::DICOMSource(const DICOMSource& in) +{ + if (strcmp(in.PlatformEndian, "LittleEndian") == 0) + { + PlatformEndian = "LittleEndian"; + } + else + { + PlatformEndian = "BigEndian"; + } +} + +void DICOMSource::operator=(const DICOMSource& in) +{ + if (strcmp(in.PlatformEndian, "LittleEndian") == 0) + { + PlatformEndian = "LittleEndian"; + } + else + { + PlatformEndian = "BigEndian"; + } +} + +doublebyte DICOMSource::ReadDoubleByte() +{ + doublebyte sh = 0; + int sz = sizeof(doublebyte); + this->Read((char*)&(sh),sz); + if (PlatformIsBigEndian) + { + sh = swapShort(sh); + } + return(sh); +} + +doublebyte DICOMSource::ReadDoubleByteAsLittleEndian() +{ + doublebyte sh = 0; + int sz = sizeof(doublebyte); + this->Read((char*)&(sh),sz); + if (PlatformIsBigEndian) + { + sh = swapShort(sh); + } + return(sh); +} + +quadbyte DICOMSource::ReadQuadByte() +{ + quadbyte sh; + int sz = sizeof(quadbyte); + this->Read((char*)&(sh),sz); + if (PlatformIsBigEndian) + { + sh = swapLong(sh); + } + return(sh); +} + +quadbyte DICOMSource::ReadNBytes(int len) +{ + quadbyte ret = -1; + switch (len) + { + case 1: + char ch; + this->Read(&ch,1); //from Image + ret =(quadbyte) ch; + break; + case 2: + ret =(quadbyte) ReadDoubleByte(); + break; + case 4: + ret = ReadQuadByte(); + break; + default: + dicom_stream::cerr << "Unable to read " << len << " bytes" << dicom_stream::endl; + break; + } + return (ret); +} + +float DICOMSource::ReadAsciiFloat(int len) +{ + float ret=0.0; + + + char* val = new char[len+1]; + this->Read(val,len); + val[len] = '\0'; + +#if 0 + // + // istrstream destroys the data during formatted input. + // + int len2 = static_cast<int> (strlen((char*) val)); + char* val2 = new char[len2]; + strncpy(val2, (char*) val, len2); + + dicom_stream::istrstream data(val2); + data >> ret; + delete [] val2; +#else + sscanf(val,"%e",&ret); +#endif + + // dicom_stream::cout << "Read ASCII float: " << ret << dicom_stream::endl; + + delete [] val; + return (ret); +} + +int DICOMSource::ReadAsciiInt(int len) +{ + int ret=0; + + char* val = new char[len+1]; + this->Read(val,len); + val[len] = '\0'; + +#if 0 + // + // istrstream destroys the data during formatted input. + // + int len2 = static_cast<int> (strlen((char*) val)); + char* val2 = new char[len2]; + strncpy(val2, (char*) val, len2); + + dicom_stream::istrstream data(val2); + data >> ret; + delete [] val2; +#else + sscanf(val,"%d",&ret); +#endif + + // dicom_stream::cout << "Read ASCII int: " << ret << dicom_stream::endl; + + delete [] val; + return (ret); +} + +char* DICOMSource::ReadAsciiCharArray(int len) +{ + if (len <= 0) + { + return NULL; + } + char* val = new char[len + 1]; + this->Read(val, len); + val[len] = 0; // NULL terminate. + return val; +} +} +#ifdef _MSC_VER +#pragma warning ( pop ) +#endif diff --git a/Utilities/ITK/Utilities/DICOMParser/DICOMSource.h b/Utilities/ITK/Utilities/DICOMParser/DICOMSource.h new file mode 100644 index 0000000000000000000000000000000000000000..caf82c7164e8ca28d6c423604b783ffc98641c7a --- /dev/null +++ b/Utilities/ITK/Utilities/DICOMParser/DICOMSource.h @@ -0,0 +1,235 @@ +/*========================================================================= + + Program: DICOMParser + Module: $RCSfile: DICOMSource.h,v $ + Language: C++ + Date: $Date: 2004/11/10 19:22:13 $ + Version: $Revision: 1.3 $ + + Copyright (c) 2003 Matt Turek + All rights reserved. + See Copyright.txt 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. + +=========================================================================*/ + +#ifndef __DICOMSOURCE_H_ +#define __DICOMSOURCE_H_ + +#ifdef _MSC_VER +#pragma warning ( disable : 4514 ) +#pragma warning ( push, 3 ) +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <iostream> +#include <fstream> +#include <string> + +#include "DICOMTypes.h" +#include "DICOMConfig.h" + +namespace DICOMPARSER_NAMESPACE +{ +// +// Abstraction of a DICOM data source used by the DICOMParser. +// +class DICOM_EXPORT DICOMSource +{ + public: + DICOMSource(); + virtual ~DICOMSource(); + + // + // Return the position in the source + // + virtual long Tell()=0; + + // + // Move to a particular position in the source. + // + virtual void SkipToPos(long)=0; + + // + // Return the size of the source. + // + virtual long GetSize()=0; + + // + // Skip a number of bytes. + // + virtual void Skip(long)=0; + + // + // Skip to the beginning of the source. + // + virtual void SkipToStart()=0; + + // + // Read data of length len. + // + virtual void Read(void* data, long len)=0; + + // + // Read a double byte of data. + // + virtual doublebyte ReadDoubleByte(); + virtual doublebyte ReadDoubleByteAsLittleEndian(); + + // + // Read a quadbyte of data. + // + virtual quadbyte ReadQuadByte(); + + // + // Read nbytes of data up to 4 bytes. + // + virtual quadbyte ReadNBytes(int len); + + // + // Read a float an ascii. + // + virtual float ReadAsciiFloat(int len); + + // + // Read an int as ascii. + // + virtual int ReadAsciiInt(int len); + + // + // Read an array of ascii characters. + // + virtual char* ReadAsciiCharArray(int len); + + // + // Convert the data to signed long. + // + static long ReturnAsSignedLong(unsigned char* data, bool ) + { + return *((quadbyte*) data); + } + + + // + // Convert the data to unsigned long. + // + static ulong ReturnAsUnsignedLong(unsigned char* data, bool ) + { + return *((ulong*) data); + } + + // + // Convert data to unsigned short. + // + static ushort ReturnAsUnsignedShort(unsigned char* data, bool ) + { + return *((doublebyte*)data); + } + + // + // Convert data to signed short. + // + static short int ReturnAsSignedShort(unsigned char* data, bool ) + { + return *((short int*)data); + } + + // + // Convert data to int. + // + static int ReturnAsInteger(unsigned char* data, bool) + { + return static_cast<int> (atoi((const char *)data)); + } + + static float ReturnAsFloat(unsigned char* data, bool) + { + return static_cast<float> (atof((const char *)data)); + } + + bool GetPlatformIsBigEndian() + { + return PlatformIsBigEndian; + } + + void SetPlatformIsBigEndian(bool v) + { + this->PlatformIsBigEndian = v; + } + + // + // Swap the bytes in an array of unsigned shorts. + // + static void swapShorts(ushort *ip, ushort *op, int count) + { + while (count) + { + *op++ = swapShort(*ip++); + count--; + } + } + + // + // Swap the bytes in an array of unsigned longs. + // + static void swapLongs(ulong *ip, ulong *op, int count) + { + while (count) + { + *op++ = swapLong(*ip++); + count--; + } + } + + + // + // Swap the bytes in an unsigned short. + // + static ushort swapShort(ushort v) + { + return ushort((v << 8) + | (v >> 8)); + } + + // + // Swap the bytes in an unsigned long. + // + static ulong swapLong(ulong v) + { + return ulong((v << 24) + | (v << 8) & 0x00ff0000 + | (v >> 8) & 0x0000ff00 + | (v >> 24)); + } + + const char* GetPlatformEndian() {return this->PlatformEndian;} + + protected: + DICOMSource(const DICOMSource&); + void operator=(const DICOMSource&); + + // + // Flag for swaping bytes. + // + bool PlatformIsBigEndian; + + // + // Platform endianness + // + const char* PlatformEndian; + + private: + +}; +} +#ifdef _MSC_VER +#pragma warning ( pop ) +#endif + +#endif // __DICOMSOURCE_H_ + + diff --git a/Utilities/ITK/Utilities/DICOMParser/DICOMTypes.h b/Utilities/ITK/Utilities/DICOMParser/DICOMTypes.h new file mode 100644 index 0000000000000000000000000000000000000000..c32002061418e4646377dbdb093107950d0aeb91 --- /dev/null +++ b/Utilities/ITK/Utilities/DICOMParser/DICOMTypes.h @@ -0,0 +1,30 @@ + +/*========================================================================= + + Program: DICOMParser + Module: $RCSfile: DICOMTypes.h,v $ + Language: C++ + Date: $Date: 2003/10/23 17:57:35 $ + Version: $Revision: 1.4 $ + + Copyright (c) 2003 Matt Turek + All rights reserved. + See Copyright.txt 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. + +=========================================================================*/ + + +#ifndef __DICOM_TYPES_H_ +#define __DICOM_TYPES_H_ + +typedef unsigned short doublebyte; +typedef int quadbyte; +typedef unsigned short ushort; +typedef unsigned long ulong; + + +#endif diff --git a/Utilities/ITK/Utilities/Dart/AllowContinuous.bat.in b/Utilities/ITK/Utilities/Dart/AllowContinuous.bat.in new file mode 100644 index 0000000000000000000000000000000000000000..05e90f2e7722419801fc7fcaa60596d4f4454323 --- /dev/null +++ b/Utilities/ITK/Utilities/Dart/AllowContinuous.bat.in @@ -0,0 +1,11 @@ +rem +rem Allow Continuous to run +rem +c: + +cd @ITK_BINARY_DIR@ +if EXIST continuous.lock ( + del continuous.lock +) + + diff --git a/Utilities/ITK/Utilities/Dart/AllowContinuous.sh.in b/Utilities/ITK/Utilities/Dart/AllowContinuous.sh.in new file mode 100644 index 0000000000000000000000000000000000000000..1798e703e974cc32d9476832f93e1f2506010ca0 --- /dev/null +++ b/Utilities/ITK/Utilities/Dart/AllowContinuous.sh.in @@ -0,0 +1,6 @@ +#!/bin/sh +echo "Allow Continuous to run" +cd @ITK_BINARY_DIR@ +if [ -e continuous.lock ] +then rm continuous.lock; +fi diff --git a/Utilities/ITK/Utilities/Dart/BuildContinuous.bat.in b/Utilities/ITK/Utilities/Dart/BuildContinuous.bat.in new file mode 100644 index 0000000000000000000000000000000000000000..8ede24ab502f2423de9b8652b8682de6a04d9f06 --- /dev/null +++ b/Utilities/ITK/Utilities/Dart/BuildContinuous.bat.in @@ -0,0 +1,13 @@ +rem +rem Do a Build Continuously +rem +cd @ITK_BINARY_DIR@ +if EXIST continuous.lock ( + exit /B +) else ( + date /T > continuous.lock + time /T >> continuous.lock + "@TCL_TCLSH@" "@DART_ROOT@/Source/Client/DashboardManager.tcl" "@ITK_BINARY_DIR@/DartConfiguration.tcl" Continuous Start Update Configure Build Test Submit + del continuous.lock +) + diff --git a/Utilities/ITK/Utilities/Dart/BuildContinuous.sh.in b/Utilities/ITK/Utilities/Dart/BuildContinuous.sh.in new file mode 100644 index 0000000000000000000000000000000000000000..1af30f1178a92ea20c859a24cd6dd34d3333448a --- /dev/null +++ b/Utilities/ITK/Utilities/Dart/BuildContinuous.sh.in @@ -0,0 +1,11 @@ +#!/bin/sh +echo "Do a Build Continuously" +cd @ITK_BINARY_DIR@ +if [ -e continuous.lock ] +then exit; +else +date >continuous.lock +"@TCL_TCLSH@" "@DART_ROOT@/Source/Client/DashboardManager.tcl" DartConfiguration.tcl Continuous Start Update Configure Build Test Submit 2>&1 > "@ITK_BINARY_DIR@/Testing/Continuous.log" +rm continuous.lock +rm -f @ITK_BINARY_DIR@/Testing/Temporary/* +fi diff --git a/Utilities/ITK/Utilities/Dart/BuildHeaderTest.tcl b/Utilities/ITK/Utilities/Dart/BuildHeaderTest.tcl new file mode 100644 index 0000000000000000000000000000000000000000..02f5c3281beecd5e7af6d131da8c582979d8fb39 --- /dev/null +++ b/Utilities/ITK/Utilities/Dart/BuildHeaderTest.tcl @@ -0,0 +1,126 @@ +# ========================================================================= +# +# Program: Insight Segmentation & Registration Toolkit +# Module: $RCSfile: BuildHeaderTest.tcl,v $ +# Language: Tcl +# Date: $Date: 2002/12/13 12:48:51 $ +# Version: $Revision: 1.6 $ +# + +# Copyright (c) 2001 Insight Consortium +# All rights reserved. + +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: + +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. + +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. + +# * The name of the Insight Consortium, nor the names of any consortium members, +# nor of any contributors, may be used to endorse or promote products derived +# from this software without specific prior written permission. + +# * Modified source versions must be plainly marked as such, and must not be +# misrepresented as being the original software. + +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS'' +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +set Header {/*========================================================================= + + Program: Insight Segmentation & Registration Toolkit (ITK) + Module: + Language: C++ + Date: + Version: + + +Copyright (c) 2000 National Library of Medicine +All rights reserved. + +See COPYRIGHT.txt for copyright details. + +=========================================================================*/ +#if defined(_MSC_VER) +#pragma warning ( disable : 4786 ) +#endif + +#include <iostream> +// This file has been generated by BuildHeaderTest.tcl +// Test to include each header file for Insight +} + +set Trailer " +int main ( int , char* [] ) +{ + + return 0; +} +" + +set D [lsort [glob -nocomplain Code/*]] +set Directories "" +foreach d $D \ +{ + if { [file tail $d] != "CVS" && [file isdirectory $d]} \ + { + lappend Directories [file tail $d] + } +} + +foreach Directory $Directories \ +{ + if { ![file exists [file join Testing Code $Directory]] } \ + { + continue + } + set f [open [file join Testing Code $Directory itk${Directory}HeaderTest.cxx] w] + puts $f $Header + foreach File [lsort [glob -nocomplain [file join Code $Directory *.h]]] \ + { + if {[file tail $File] == "itkTestMain.h"} { + continue; + } + if {[file tail $File] == "itkWindows.h"} { + continue; + } + if {[file tail $File] == "itkWin32Header.h"} { + continue; + } + if {[file tail $File] == "itkWin32OutputWindow.h"} { + continue; + } + if {[file tail $File] == "itkImageViewerWindow.h"} { + continue; + } +# +# include the .h if there is no .txx +# otherwise include the .txx +# + set txxFile "[file rootname $File].txx" + if {[file tail $txxFile] == "itkImageViewer.txx"} { + continue; + } + if { [file exists $txxFile] } { + puts $f "#include \"[file tail $txxFile]\"" + } else { + puts $f "#include \"[file tail $File]\"" + } + } + puts $f $Trailer + close $f +} + diff --git a/Utilities/ITK/Utilities/Dart/CMakeLists.txt b/Utilities/ITK/Utilities/Dart/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..ad8a2ba34bad1bf0eb4972cc51e8166f60b42ee4 --- /dev/null +++ b/Utilities/ITK/Utilities/Dart/CMakeLists.txt @@ -0,0 +1,54 @@ +IF(WIN32) + IF(NOT MINGW) + CONFIGURE_FILE(${ITK_SOURCE_DIR}/Utilities/Dart/AllowContinuous.bat.in + ${ITK_BINARY_DIR}/AllowContinuous.bat) + CONFIGURE_FILE(${ITK_SOURCE_DIR}/Utilities/Dart/PreventContinuous.bat.in + ${ITK_BINARY_DIR}/PreventContinuous.bat) + CONFIGURE_FILE(${ITK_SOURCE_DIR}/Utilities/Dart/BuildContinuous.bat.in + ${ITK_BINARY_DIR}/BuildContinuous.bat) + ELSE(NOT MINGW) + CONFIGURE_FILE(${ITK_SOURCE_DIR}/Utilities/Dart/BuildContinuous.sh.in + ${ITK_BINARY_DIR}/BuildContinuous.sh + @ONLY IMMEDIATE) + EXEC_PROGRAM(chmod ARGS 755 \"${ITK_BINARY_DIR}/BuildContinuous.sh\" + OUTPUT_VARIABLE ITK_EXEC_PLEASE_BE_QUIET) + CONFIGURE_FILE(${ITK_SOURCE_DIR}/Utilities/Dart/AllowContinuous.sh.in + ${ITK_BINARY_DIR}/AllowContinuous.sh + @ONLY IMMEDIATE) + EXEC_PROGRAM(chmod ARGS 755 \"${ITK_BINARY_DIR}/AllowContinuous.sh\" + OUTPUT_VARIABLE ITK_EXEC_PLEASE_BE_QUIET) + CONFIGURE_FILE(${ITK_SOURCE_DIR}/Utilities/Dart/PreventContinuous.sh.in + ${ITK_BINARY_DIR}/PreventContinuous.sh + @ONLY IMMEDIATE) + EXEC_PROGRAM(chmod ARGS 755 \"${ITK_BINARY_DIR}/PreventContinuous.sh\" + OUTPUT_VARIABLE ITK_EXEC_PLEASE_BE_QUIET) + CONFIGURE_FILE(${ITK_SOURCE_DIR}/Utilities/Dart/cronentry.in + ${ITK_BINARY_DIR}/cronentry + @ONLY IMMEDIATE) + ENDIF(NOT MINGW) +ENDIF(WIN32) +IF(UNIX) + CONFIGURE_FILE(${ITK_SOURCE_DIR}/Utilities/Dart/BuildContinuous.sh.in + ${ITK_BINARY_DIR}/BuildContinuous.sh + @ONLY IMMEDIATE) + EXEC_PROGRAM(chmod ARGS 755 \"${ITK_BINARY_DIR}/BuildContinuous.sh\" + OUTPUT_VARIABLE ITK_EXEC_PLEASE_BE_QUIET) + CONFIGURE_FILE(${ITK_SOURCE_DIR}/Utilities/Dart/AllowContinuous.sh.in + ${ITK_BINARY_DIR}/AllowContinuous.sh + @ONLY IMMEDIATE) + EXEC_PROGRAM(chmod ARGS 755 \"${ITK_BINARY_DIR}/AllowContinuous.sh\" + OUTPUT_VARIABLE ITK_EXEC_PLEASE_BE_QUIET) + CONFIGURE_FILE(${ITK_SOURCE_DIR}/Utilities/Dart/PreventContinuous.sh.in + ${ITK_BINARY_DIR}/PreventContinuous.sh + @ONLY IMMEDIATE) + EXEC_PROGRAM(chmod ARGS 755 \"${ITK_BINARY_DIR}/PreventContinuous.sh\" + OUTPUT_VARIABLE ITK_EXEC_PLEASE_BE_QUIET) + CONFIGURE_FILE(${ITK_SOURCE_DIR}/Utilities/Dart/cronentry.in + ${ITK_BINARY_DIR}/cronentry + @ONLY IMMEDIATE) + CONFIGURE_FILE(${ITK_SOURCE_DIR}/Utilities/Dart/NewSince.csh.in + ${ITK_BINARY_DIR}/NewSince.csh + @ONLY IMMEDIATE) + EXEC_PROGRAM(chmod ARGS 755 \"${ITK_BINARY_DIR}/NewSince.csh\" + OUTPUT_VARIABLE ITK_EXEC_PLEASE_BE_QUIET) +ENDIF(UNIX) diff --git a/Utilities/ITK/Utilities/Dart/NewSince.csh.in b/Utilities/ITK/Utilities/Dart/NewSince.csh.in new file mode 100644 index 0000000000000000000000000000000000000000..616701e70be30cf54369521b2450b35bcc498978 --- /dev/null +++ b/Utilities/ITK/Utilities/Dart/NewSince.csh.in @@ -0,0 +1,113 @@ +#! /bin/tcsh -f +# +# Find all new files between two dates +# Usage: NewSince.csh StartDate EndDate +# + +if ($#argv != 2) then + echo "Usage: NewSince.csh StartDate EndDate" + exit (1) +endif + +echo "Changes from $1 to $2" + +set FROM="$1" +set TO="$2" + +set TEMPDIR=@ITK_BINARY_DIR@/Testing/Temporary + +(cd @ITK_SOURCE_DIR@; cvs log -d"$FROM<$TO" >${TEMPDIR}/$$.allchanges) + +gawk -f @ITK_SOURCE_DIR@/Utilities/Dart/NewSince.gawk ${TEMPDIR}/$$.allchanges | cut -d"/" -f5- >${TEMPDIR}/$$.newandremoved + +# +# remove files in the Attic +# +grep -v Attic ${TEMPDIR}/$$.newandremoved >${TEMPDIR}/$$.new + +echo "This release covers the period ${FROM} through ${TO}" > ${TEMPDIR}/$$.wikitemp +echo "== New Classes in this Release ==" >> ${TEMPDIR}/$$.wikitemp +echo "<pre>" >> ${TEMPDIR}/$$.wikitemp +grep "^Code/Algorithms" ${TEMPDIR}/$$.new | sort | uniq >> ${TEMPDIR}/$$.wikitemp +echo "" >> ${TEMPDIR}/$$.wikitemp +grep "^Code/BasicFilters" ${TEMPDIR}/$$.new | sort | uniq >> ${TEMPDIR}/$$.wikitemp +echo "" >> ${TEMPDIR}/$$.wikitemp +grep "^Code/Common" ${TEMPDIR}/$$.new | sort | uniq >> ${TEMPDIR}/$$.wikitemp +echo "" >> ${TEMPDIR}/$$.wikitemp +grep "^Code/IO" ${TEMPDIR}/$$.new | sort | uniq >> ${TEMPDIR}/$$.wikitemp +echo "" >> ${TEMPDIR}/$$.wikitemp +grep "^Code/Numerics/itk" ${TEMPDIR}/$$.new | sort | uniq >> ${TEMPDIR}/$$.wikitemp +echo "" >> ${TEMPDIR}/$$.wikitemp +grep "^Code/Numerics/NeuralNetworks" ${TEMPDIR}/$$.new | sort | uniq >> ${TEMPDIR}/$$.wikitemp +echo "" >> ${TEMPDIR}/$$.wikitemp +grep "^Code/Numerics/Statistics" ${TEMPDIR}/$$.new | sort | uniq >> ${TEMPDIR}/$$.wikitemp +echo "" >> ${TEMPDIR}/$$.wikitemp +grep "^Code/SpatialObject" ${TEMPDIR}/$$.new | sort | uniq >> ${TEMPDIR}/$$.wikitemp +echo "" >> ${TEMPDIR}/$$.wikitemp +grep "^Code/Patented" ${TEMPDIR}/$$.new | sort | uniq >> ${TEMPDIR}/$$.wikitemp +echo "</pre>" >> ${TEMPDIR}/$$.wikitemp + +echo "== New Tests in this Release ==" >> ${TEMPDIR}/$$.wikitemp +echo "<pre>" >> ${TEMPDIR}/$$.wikitemp +grep "^Testing/Code/Common" ${TEMPDIR}/$$.new | sort | uniq >> ${TEMPDIR}/$$.wikitemp +echo "" >> ${TEMPDIR}/$$.wikitemp +grep "^Testing/Code/BasicFilters" ${TEMPDIR}/$$.new | sort | uniq >> ${TEMPDIR}/$$.wikitemp +echo "" >> ${TEMPDIR}/$$.wikitemp +grep "^Testing/Code/IO" ${TEMPDIR}/$$.new | sort | uniq >> ${TEMPDIR}/$$.wikitemp +echo "" >> ${TEMPDIR}/$$.wikitemp +grep "^Testing/Code/Algorithms" ${TEMPDIR}/$$.new | sort | uniq >> ${TEMPDIR}/$$.wikitemp +echo "" >> ${TEMPDIR}/$$.wikitemp +grep "^Testing/Code/Numerics" ${TEMPDIR}/$$.new | sort | uniq >> ${TEMPDIR}/$$.wikitemp +echo "" >> ${TEMPDIR}/$$.wikitemp +grep "^Testing/Code/SpatialObject" ${TEMPDIR}/$$.new | sort | uniq >> ${TEMPDIR}/$$.wikitemp +echo "" >> ${TEMPDIR}/$$.wikitemp +grep "^Testing/Code/Patented" ${TEMPDIR}/$$.new | sort | uniq >> ${TEMPDIR}/$$.wikitemp +echo "</pre>" >> ${TEMPDIR}/$$.wikitemp + +echo "== New Examples in this Release ==" >> ${TEMPDIR}/$$.wikitemp +echo "<pre>" >> ${TEMPDIR}/$$.wikitemp +grep "^Examples/DataRepresentation" ${TEMPDIR}/$$.new | sort | uniq >> ${TEMPDIR}/$$.wikitemp +echo "" >> ${TEMPDIR}/$$.wikitemp +grep "^Examples/Filtering" ${TEMPDIR}/$$.new | sort | uniq >> ${TEMPDIR}/$$.wikitemp +echo "" >> ${TEMPDIR}/$$.wikitemp +grep "^Examples/GUI" ${TEMPDIR}/$$.new | sort | uniq >> ${TEMPDIR}/$$.wikitemp +echo "" >> ${TEMPDIR}/$$.wikitemp +grep "^Examples/Infrastructure" ${TEMPDIR}/$$.new | sort | uniq >> ${TEMPDIR}/$$.wikitemp +echo "" >> ${TEMPDIR}/$$.wikitemp +grep "^Examples/Installation" ${TEMPDIR}/$$.new | sort | uniq >> ${TEMPDIR}/$$.wikitemp +echo "" >> ${TEMPDIR}/$$.wikitemp +grep "^Examples/IO" ${TEMPDIR}/$$.new | sort | uniq >> ${TEMPDIR}/$$.wikitemp +echo "" >> ${TEMPDIR}/$$.wikitemp +grep "^Examples/Iterators" ${TEMPDIR}/$$.new | sort | uniq >> ${TEMPDIR}/$$.wikitemp +echo "" >> ${TEMPDIR}/$$.wikitemp +grep "^Examples/Numerics" ${TEMPDIR}/$$.new | sort | uniq >> ${TEMPDIR}/$$.wikitemp +echo "" >> ${TEMPDIR}/$$.wikitemp +grep "^Examples/Patented" ${TEMPDIR}/$$.new | sort | uniq >> ${TEMPDIR}/$$.wikitemp +echo "" >> ${TEMPDIR}/$$.wikitemp +grep "^Examples/Registration" ${TEMPDIR}/$$.new | sort | uniq >> ${TEMPDIR}/$$.wikitemp +echo "" >> ${TEMPDIR}/$$.wikitemp +grep "^Examples/Segmentations" ${TEMPDIR}/$$.new | sort | uniq >> ${TEMPDIR}/$$.wikitemp +echo "" >> ${TEMPDIR}/$$.wikitemp +grep "^Examples/SpatialObjects" ${TEMPDIR}/$$.new | sort | uniq >> ${TEMPDIR}/$$.wikitemp +echo "" >> ${TEMPDIR}/$$.wikitemp +grep "^Examples/Statistics" ${TEMPDIR}/$$.new | sort | uniq >> ${TEMPDIR}/$$.wikitemp +echo "" >> ${TEMPDIR}/$$.wikitemp +grep "^Examples/Visualization" ${TEMPDIR}/$$.new | sort | uniq >> ${TEMPDIR}/$$.wikitemp +echo "" >> ${TEMPDIR}/$$.wikitemp +grep "^Examples/Wrapping" ${TEMPDIR}/$$.new | sort | uniq >> ${TEMPDIR}/$$.wikitemp +echo "</pre>" >> ${TEMPDIR}/$$.wikitemp + +echo "== New Utilities in this Release ==" >> ${TEMPDIR}/$$.wikitemp +echo "<pre>" >> ${TEMPDIR}/$$.wikitemp +grep "^Utilities/" ${TEMPDIR}/$$.new | sort | uniq >> ${TEMPDIR}/$$.wikitemp +echo "</pre>" >> ${TEMPDIR}/$$.wikitemp + +# +# remove consecutive blank lines +# +cat -s ${TEMPDIR}/$$.wikitemp > ${TEMPDIR}/NewSince.txt +echo "A Wiki-compatible list of new files is in ${TEMPDIR}/NewSince.txt" +# +# cleanup +# +rm -f ${TEMPDIR}/$$.* diff --git a/Utilities/ITK/Utilities/Dart/NewSince.gawk b/Utilities/ITK/Utilities/Dart/NewSince.gawk new file mode 100644 index 0000000000000000000000000000000000000000..9e382fce2aa63c72ca35250f2270cc9cb3f6255e --- /dev/null +++ b/Utilities/ITK/Utilities/Dart/NewSince.gawk @@ -0,0 +1,8 @@ +/^RCS file/ {lastFile = $3} +/revision 1\.1$/ { + gsub(",v$","",lastFile); + gsub(".cxx$","",lastFile); + gsub(".txx$","",lastFile); + gsub(".c$","",lastFile); + gsub(".h$","",lastFile); + printf "new: %s\n", lastFile} diff --git a/Utilities/ITK/Utilities/Dart/PreventContinuous.bat.in b/Utilities/ITK/Utilities/Dart/PreventContinuous.bat.in new file mode 100644 index 0000000000000000000000000000000000000000..86900c43eaf6bdde031d6ac5ba6989f524641041 --- /dev/null +++ b/Utilities/ITK/Utilities/Dart/PreventContinuous.bat.in @@ -0,0 +1,11 @@ +rem +rem Prevent the Continuous +rem +c: + +cd @ITK_BINARY_DIR@ +if EXIST continuous.lock ( + exit /B +) else ( + echo "Locked by PreventContinuous.bat, probably for nightly" > continuous.lock +) diff --git a/Utilities/ITK/Utilities/Dart/PreventContinuous.sh.in b/Utilities/ITK/Utilities/Dart/PreventContinuous.sh.in new file mode 100644 index 0000000000000000000000000000000000000000..730b2b923e24309617f9f99c2d14fe66b8f4f65f --- /dev/null +++ b/Utilities/ITK/Utilities/Dart/PreventContinuous.sh.in @@ -0,0 +1,7 @@ +#!/bin/sh +echo "Prevent Continuous from running" +cd @ITK_BINARY_DIR@ +if [ -e continuous.lock ] +then exit +fi +echo "Locked by PreventContinuous.sh, probably for nightly" > continuous.lock diff --git a/Utilities/ITK/Utilities/Dart/PrintSelfCheck.tcl b/Utilities/ITK/Utilities/Dart/PrintSelfCheck.tcl new file mode 100644 index 0000000000000000000000000000000000000000..ade29a0aaaec623d9389d08cf98c093fffcc2713 --- /dev/null +++ b/Utilities/ITK/Utilities/Dart/PrintSelfCheck.tcl @@ -0,0 +1,687 @@ +# +# Verify that each class's PrintSelf prints all ivars that have +# a set/get. +# +# +# Verbose Levels: +# +# 0: No extra printing +# 1: Print basic extra information +# 2: Print lots of details +# +set verbose 0 + +set class_name "" + +set class_count 0 +set class_print_count 0 +set printself_miss_count 0 +set super_miss_count 0 +set ivar_count 0 +set ivar_miss_count 0 + +set total_class_count 0 +set total_class_print_count 0 +set total_ivar_count 0 +set total_printself_miss_count 0 +set total_super_miss_count 0 +set total_ivar_miss_count 0 + +# Fileid for the PrintSelfDetails.html file +set pd_id 0 + +# +# class_list contains the following for each class evaluated: +# +# <class>.p <true|false> True if printself declared +# <class>.s.<super_class> <true|false> True if superclass used in printself +# <class>.i.<ivar> <true|false> True if ivar used in printself + +set class_list(null) 1 + +proc list_contains { string } { + + global class_list + + set ivar_found 0 + set searchid [array startsearch class_list] + + while { [array anymore class_list $searchid] } { + set element [array nextelement class_list $searchid] + if { $element == $string } { + set ivar_found 1 + } + } + + array donesearch class_list $searchid + + return $ivar_found +} + +proc get_ivar { string } { + + global verbose + + set ivar_string "-1" + +#puts "Getting ivar from macro: $string" + + # Search for the first occurrence of an open parenthesis + set first [string first "(" $string]; + + if { $first > -1 } { + + set begintrim [string range $string [expr $first + 1] end]; + set begintrim [string trim $begintrim]; + + # Find the end of the ivar + set last [string wordend $begintrim 0] + + if { $last > -1 } { + + set ivar_string [string range $begintrim 0 [expr $last - 1] ]; + + set ivar_string [string trim $ivar_string]; + + if { $verbose >= 2 } { + puts " Macro: $ivar_string" + } + } + } + + return [string trim $ivar_string] +} + +proc check_header_file { filename } { + + global class_name + global class_count + global ivar_count + global class_list + global verbose + + if { $verbose >= 2 } { + puts "Processing file: $filename" + } + + set data "" + set class_name "" + + set printself_found 0 + set class_found 0 + + if { [file readable $filename] } { + set fileid [open $filename "r"] + + set private_not_found 1 + + # + # Read each line in the file + # + while { [gets $fileid data] >= 0 && $private_not_found } { + + # Search for the printSelf string + if { [string match "*PrintSelf*(*" $data] == 1 } { + set printself_found 1 + set class_list($class_name.p) 1 + } + + if { [string match "*private:*" $data] == 1 } { + set private_not_found 0 + } + + # Search for the class string + # Extract the class name from the string + if { [string match "*class *_EXPORT*" $data] == 1 } { + while { [gets $fileid rest] >= 0 && [string first "\{" $rest] == -1 } { + lappend data $rest + } + set data [join $data] + set class_found 1 + + set class_ivar_count 0 + + set first [string first "_EXPORT" $data]; + incr first 7 + if { $first > -1 } { + + set end [expr [string first ":" $data] - 1]; + + set newstring [string range $data $first $end ] + set class_name [string trim [string trimleft $newstring]]; + } + + set class_list($class_name.p) 0 + + if { $verbose >= 2 } { + puts " Class Name: $class_name" + } + + set first [string first "public" $data] + if { $first > -1 } { + set first [expr $first + 7]; + set end [ string length $data] + + set string [string range $data $first $end ] + + set first [string first "itk" $string] + set end [string wordend $string $first] + + set super_class [string range $string $first $end ] + set super_class [string trim $super_class] + + set class_list($class_name.s.Superclass) 0 + } + } + + if { $class_found == 1 } { + + # Search for Set and Get macros + set set_macro_found [string match "*itkSet*Macro*(*" $data] + set get_static_const_macro_found [string match "*itkGetStaticConstMacro*(*" $data] + set get_macro_found [string match "*itkGet*Macro*(*" $data] + + if { !$get_static_const_macro_found && ( $set_macro_found || $get_macro_found ) } { + + # Get the ivar from the Macro declaration + set ivar [get_ivar $data]; + + if { [string compare $ivar "-1"] != 0 } { + if { [list_contains "$class_name.i.$ivar"] == 0 } { + + incr ivar_count + incr class_ivar_count + + set class_list($class_name.i.$ivar) 0 + } + } + } + } + } + + # If a class was found within the file then increment the class count + if { $class_found } { + incr class_count + } + + close $fileid + + } + +} + +proc check_printself { filename } { + + global verbose + + global class_list + global class_name + + if { $verbose >= 2 } { + puts " Checking PrintSelf in file: $filename" + } + + if { [file readable $filename] } { + + set fileid [open $filename "r"] + + set search_state 0 + + set curly_open 0 + set curly_close 0 + + set line_count 0 + + # + # Read each line in the file + # + while { [gets $fileid data] >= 0 && $search_state != 3 } { + + incr line_count + + # Search for the PrintSelf string + if { $search_state == 0 && [string match "*PrintSelf*(*" $data] == 1 } { + set search_state 1 + set first [string first ")" $data] + set data [string range $data [expr $first + 1] end] + } + + # Find the first open curly bracket + if { $search_state == 1 } { + while { [string length $data] > 0 && $curly_open == 0 } { + # Check for an open curly bracket + set curly_found [string first "\{" $data] + if { $curly_found > -1 } { + set data [string range $data [expr $curly_found + 1] end ] + set curly_open 1 + set search_state 2 + } else { + set data "" + } + } + } + + # Count curly brackets in PrintSelf() method and find ivars + if { $search_state == 2 } { + + set start 0 + set end [string length $data] + if { [string match "*::PrintSelf(*)*" $data] == 1 } { + set start [string first "itk" $data] + set end [string wordend $data $start] + + set super_class [string range $data $start [expr $end -1]] + set super_class [string trim $super_class] + + if { [list_contains "$class_name.s.Superclass"] == 1 } { + set class_list($class_name.s.Superclass) 1 + } elseif { $verbose >= 2 } { + puts "\tSuperclass Issue:\tCan't find $class_name.s.$super_class" + } + } + + while { $start < $end && $curly_open > $curly_close } { + set word_end [string wordend $data $start] + set token [string range $data $start [expr $word_end -1] ] + set token [string trim $token] + set start $word_end + if { $verbose >= 2 } { + puts "\tNew Token: $token" + } + + # Check for open and close curly braces + if { [string compare "\{" $token] == 0 } { + incr curly_open + } elseif { [string compare "\}" $token] == 0 } { + incr curly_close + } elseif { [string match m_* "$token"] == 1 } { + set token_end [expr [string wordend $data $start ] - 1] + set ivar [string range $token 2 end] + set ivar [string trim $ivar] + + if { [list_contains "$class_name.i.$ivar"] == 1 } { + set class_list($class_name.i.$ivar) 1 + } elseif { $verbose } { + puts "\tIvar Issue:\t\tCan't find $class_name.i.$ivar" + } + } elseif { [string compare "this" $token] == 0 } { + set start [expr $start + 2] + set token_end [expr [string wordend $data $start ] - 1] + set ivar [string range $data $start $token_end] + if { [string first "Get" $ivar] > -1 } { + set start [expr $start + 3]; + + # Check if this is a Get*AsString() method + if { [string first "AsString" $ivar] > -1 } { + set token_end [expr $token_end - 8]; + } + + set ivar [string range $data $start $token_end] + } + set ivar [string trim $ivar] + + if { [list_contains "$class_name.i.$ivar"] == 1 } { + set class_list($class_name.i.$ivar) 1 + } elseif { $verbose } { + puts "\tIvar Issue:\t\tCan't find $class_name.i.$ivar" + } + } + } + + if { $curly_open == $curly_close } { + set search_state 3 + } + } + } + + close $fileid + } +} + +proc read_directory { dirname } { + + global class_name + global argv + + set total_defects 0 + + set files [glob -nocomplain "$dirname/itk*.h"] + + if { $files != "" } { + foreach headername $files { + + set class_name "" + + # Check that a PrintSelf() is defined + check_header_file $headername + + # Check that the PrintSelf() method accesses the appropriate ivars + if { $class_name != "" && [list_contains "$class_name.p"] == 1 } { + set length [string length $headername] + set filename [string range $headername 0 [expr $length - 3] ] + if {[file exists "$filename.txx"] == 1} { + check_printself "$filename.txx" + } elseif {[file exists "$filename.cxx"] == 1} { + check_printself "$filename.cxx" + } elseif {[file exists "$filename.h"] == 1} { + check_printself "$filename.h" + } + } + + } + } +} + +proc class_has_ivars { class } { + + global verbose + global class_list + + set searchid [array startsearch class_list] + + while { [array anymore class_list $searchid] } { + + set element [array nextelement class_list $searchid] + + if { [string match "$class.i.*" $element] == 1 } { + array donesearch class_list $searchid + return 1 + } + } + + array donesearch class_list $searchid + + return 0 +} + +proc check_for_defects { print } { + + global pd_id + + global verbose + global class_list + global class_print_count + global ivar_miss_count + global printself_miss_count + global super_miss_count + + # + # PRINTSELF CHECK + # + + # Loop through list and count printself defects, if any + set searchid [array startsearch class_list] + + while { [array anymore class_list $searchid] } { + + set element [array nextelement class_list $searchid] + # Extract strings that represent PrintSelfs + if { [string match "*.p" $element] == 1 } { + set end [expr [string wordend $element 0] - 1] + set curr_class [string range $element 0 $end] + + if { [class_has_ivars $curr_class] == 1 } { + + incr class_print_count + + if { $class_list($element) != 1 } { + + incr printself_miss_count + } + } + } + } + + array donesearch class_list $searchid + + # Loop through list and print printself defects + if { $printself_miss_count > 0 && $print } { + puts $pd_id " PrintSelf DEFECTS: " + set searchid [array startsearch class_list] + + while { [array anymore class_list $searchid] } { + + set element [array nextelement class_list $searchid] + # Extract strings that represent PrintSelfs + if { [string match "*.p" $element] == 1 } { + set end [expr [string wordend $element 0] - 1] + set curr_class [string range $element 0 $end] + + if { [class_has_ivars $curr_class] == 1 } { + if { $class_list($element) != 1 } { + puts $pd_id " $curr_class does not have a PrintSelf method" + } + } + } + } + + array donesearch class_list $searchid + } + + # + # SUPERCLASS CHECK + # + + # Loop through list and count superclass defects, if any + set searchid [array startsearch class_list] + + while { [array anymore class_list $searchid] } { + + set element [array nextelement class_list $searchid] + # Extract strings that represent superclasses + if { [string match "*.s.*" $element] == 1 } { + set end [expr [string wordend $element 0] - 1] + set curr_class [string range $element 0 $end] + + if { [class_has_ivars $curr_class] == 1 && + $class_list($element) != 1 } { + + incr super_miss_count + } + } + } + + array donesearch class_list $searchid + + # Loop through list and print superclass defects + if { $super_miss_count > 0 && $print } { + puts $pd_id " Superclass DEFECTS: " + set searchid [array startsearch class_list] + + while { [array anymore class_list $searchid] } { + + set element [array nextelement class_list $searchid] + # Extract strings that represent superclasses + if { [string match "*.s.*" $element] == 1 } { + set end [expr [string wordend $element 0] - 1] + set curr_class [string range $element 0 $end] + + if { [class_has_ivars $curr_class] == 1 && + $class_list($element) != 1 } { + + set start [expr $end + 4] + set end [expr [string wordend $element $start] - 1] + set parent [string range $element $start $end] + + puts $pd_id " $curr_class did not print superclass" + } + } + } + + array donesearch class_list $searchid + } + + # + # IVAR CHECK + # + + # Loop through list and count ivar defects, if any + set searchid [array startsearch class_list] + + while { [array anymore class_list $searchid] } { + + set element [array nextelement class_list $searchid] + + # Extract strings that represent ivars + if { [string match "*.i.*" $element] == 1 } { + if { $class_list($element) != 1 } { + incr ivar_miss_count + + } + } + } + + array donesearch class_list $searchid + + # Loop through list and print ivar defects + if { $ivar_miss_count > 0 && $print } { + puts $pd_id " Ivar DEFECTS: " + set searchid [array startsearch class_list] + + while { [array anymore class_list $searchid] } { + + set element [array nextelement class_list $searchid] + + # Extract strings that represent ivars + if { [string match "*.i.*" $element] == 1 } { + if { $class_list($element) != 1 } { + set end [expr [string wordend $element 0] - 1] + set curr_class [string range $element 0 $end] + + set start [expr $end + 4] + set end [expr [string wordend $element $start] - 1] + set ivar [string range $element $start $end] + + puts $pd_id " $curr_class does not print ivar: m_$ivar" + } + } + } + + array donesearch class_list $searchid + } + +} + +proc print_toolkit_results { toolkit } { + + global pd_id + + global class_count + global class_print_count + global printself_miss_count + global ivar_count + global ivar_miss_count + global super_miss_count + + check_for_defects 1 + + set tk [string range $toolkit 0 14 ] + +} + +proc print_totals {} { + global total_defects + global total_class_count + global total_class_print_count + global total_printself_miss_count + global total_ivar_count + global total_ivar_miss_count + global total_super_miss_count + + set total_defects [expr $total_printself_miss_count + $total_super_miss_count + $total_ivar_miss_count] + +} + +proc open_files { } { + + global pd_id + + set pd_id stdout + +} + +proc close_files { } { + + global pd_id + + close $pd_id + + set pd_id 0 +} + +proc clear_results { } { + + global class_count + global class_print_count + global printself_miss_count + global ivar_count + global ivar_miss_count + global super_miss_count + global class_list + + unset class_list + set class_list(null) 1 + + set class_count 0 + set class_print_count 0 + set ivar_count 0 + set printself_miss_count 0 + set ivar_miss_count 0 + set super_miss_count 0 +} + +proc measure_itk {kits} { + + global pd_id + + global verbose + + global class_list + global class_count + global class_print_count + global printself_miss_count + global ivar_count + global ivar_miss_count + global super_miss_count + + global total_class_count + global total_class_print_count + global total_printself_miss_count + global total_ivar_count + global total_ivar_miss_count + global total_super_miss_count + + set path "" + + open_files + + foreach toolkit $kits { + clear_results + + puts $pd_id " " + puts $pd_id "Results for directory: $toolkit" + + read_directory $path$toolkit + + print_toolkit_results $toolkit + + set total_class_count [expr $total_class_count + $class_count] + set total_class_print_count [expr $total_class_print_count + $class_print_count] + set total_printself_miss_count [expr $total_printself_miss_count + $printself_miss_count]; + set total_ivar_count [expr $total_ivar_count + $ivar_count]; + set total_ivar_miss_count [expr $total_ivar_miss_count + $ivar_miss_count]; + set total_super_miss_count [expr $total_super_miss_count + $super_miss_count]; + } + + print_totals + + + + if { $verbose } { + parray class_list + } + close_files +} +measure_itk [lindex $argv 0] + +exit $total_defects diff --git a/Utilities/ITK/Utilities/Dart/cronentry.in b/Utilities/ITK/Utilities/Dart/cronentry.in new file mode 100644 index 0000000000000000000000000000000000000000..6c627433282e8f91403e2ab5fb7c400d0f61aaf0 --- /dev/null +++ b/Utilities/ITK/Utilities/Dart/cronentry.in @@ -0,0 +1,6 @@ +# Attempt a continuous build every 10 minutes +5,15,25,35,45,55 * * * * @ITK_BINARY_DIR@/BuildContinuous.sh &> @ITK_BINARY_DIR@/Testing/Temporary/cronlog +# Prevent the continuous build +0 0 * * * @ITK_BINARY_DIR@/PreventContinuous.sh +# Allow the continuous build +0 6 * * * @ITK_BINARY_DIR@/AllowContinuous.sh diff --git a/Utilities/ITK/Utilities/Doxygen/cvsVersionFilter.sh b/Utilities/ITK/Utilities/Doxygen/cvsVersionFilter.sh new file mode 100644 index 0000000000000000000000000000000000000000..3ae7d6010992c0659c9dcfcf5e59083093ff8174 --- /dev/null +++ b/Utilities/ITK/Utilities/Doxygen/cvsVersionFilter.sh @@ -0,0 +1,3 @@ +#!/bin/sh +cvs -d :pserver:anonymous@www.itk.org:/cvsroot/Insight status $1 | sed -n 's/^[ \]*Working revision:[ \t]*\([0-9][0-9\.]*\).*/\1/p' + diff --git a/Utilities/ITK/Utilities/Doxygen/doxygen.config.in b/Utilities/ITK/Utilities/Doxygen/doxygen.config.in new file mode 100644 index 0000000000000000000000000000000000000000..dd5524b43e21a09230283a32f90d74fa86b28c33 --- /dev/null +++ b/Utilities/ITK/Utilities/Doxygen/doxygen.config.in @@ -0,0 +1,1348 @@ +# Doxyfile 1.4.3-20050530 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = ITK + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = @ITK_VERSION_MAJOR@.@ITK_VERSION_MINOR@.@ITK_VERSION_PATCH@ + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = @ITK_BINARY_DIR@/Documentation/Doxygen + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. +# ITKcommments: Links specific to ITK will then require relative paths or absolute +# paths and will create issues. +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, +# Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese, +# Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian, +# Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, +# Swedish, and Ukrainian. + +OUTPUT_LANGUAGE = English + +# This tag can be used to specify the encoding used in the generated output. +# The encoding is not always determined by the language that is chosen, +# but also whether or not the output is meant for Windows or non-Windows users. +# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES +# forces the Windows encoding (this is the default for the Windows binary), +# whereas setting the tag to NO uses a Unix-style encoding (the default for +# all platforms other than Windows). + +USE_WINDOWS_ENCODING = NO + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = NO + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = YES + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = @ITK_BINARY_DIR@/Documentation/ + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like the Qt-style comments (thus requiring an +# explicit @brief command for a brief description. + +JAVADOC_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the DETAILS_AT_TOP tag is set to YES then Doxygen +# will output the detailed description near the top, like JavaDoc. +# If set to NO, the detailed description appears after the member +# documentation. + +DETAILS_AT_TOP = YES + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 2 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources +# only. Doxygen will then generate output that is more tailored for Java. +# For instance, namespaces will be presented as packages, qualified scopes +# will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. + +SHOW_DIRECTORIES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from the +# version control system). Doxygen will invoke the program by executing (via +# popen()) the command <command> <input-file>, where <command> is the value of +# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file +# provided by doxygen. Whatever the progam writes to standard output +# is used as the file version. See the manual for examples. +# +# FILE_VERSION_FILTER = "@ITK_SOURCE_DIR@/Utilities/Doxygen/cvsVersionFilter.sh" +# + +FILE_VERSION_FILTER = + + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be abled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = "@ITK_SOURCE_DIR@/Code" "@ITK_SOURCE_DIR@/Documentation/Doxygen" + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx +# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm + +FILE_PATTERNS = *.h *.dox + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = "@ITK_SOURCE_DIR@/Code/Common/itkPixelTraits.h" \ + "@ITK_SOURCE_DIR@/Code/Common/itkNumericTraits.h" \ + "@ITK_SOURCE_DIR@/Code/Common/itkNumericTraitsRGB.h" \ + "@ITK_SOURCE_DIR@/Code/Common/itkNumericTraitsVectorPixel.h" \ + "@ITK_SOURCE_DIR@/Code/Common/itkNumericTraitsTensorPixel.h" \ + "@ITK_SOURCE_DIR@/Code/Common/itkNumericTraitsCovariantVectorPixel.h" \ + "@ITK_SOURCE_DIR@/Code/Common/itkNumericTraitsVariableLengthVectorPixel.h" \ + "@ITK_SOURCE_DIR@/Code/IO/itkPixelData.h" \ + "@ITK_SOURCE_DIR@/Code/IO/itkAnalyzeDbh.h" + + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix filesystem feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. + +EXCLUDE_PATTERNS = "*/vxl_copyright.h" "*/vcl/*" "*/dll.h" \ + "*/test*" "*/example*" "*config*" "*/contrib/*" \ + "*/Templates/*" "*_mocced.cxx" # "*impl*" + + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = "@ITK_SOURCE_DIR@/Testing/Code" "@ITK_SOURCE_DIR@/Examples" "@ITK_SOURCE_DIR@/Examples/DataRepresentation/Image" + + + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = *.cxx + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = YES + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = "@ITK_SOURCE_DIR@/Documentation/Art" + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command <filter> <input-file>, where <filter> +# is the value of the INPUT_FILTER tag, and <input-file> is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = "perl @ITK_BINARY_DIR@/itkdoxygen.pl" + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# is applied to all files. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = YES + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES (the default) +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = YES + +# If the REFERENCES_RELATION tag is set to YES (the default) +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 3 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = "@ITK_SOURCE_DIR@/Documentation/Doxygen/DoxygenHeader.html" + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = "@ITK_SOURCE_DIR@/Documentation/Doxygen/DoxygenFooter.html" + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = "@ITK_SOURCE_DIR@/Documentation/Doxygen/DoxygenStyle.css" + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = YES + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 1 + +# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be +# generated containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, +# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are +# probably better off using the HTML help feature. + +GENERATE_TREEVIEW = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = YES + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = letter + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = YES + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = YES + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_PREDEFINED tags. + +EXPAND_ONLY_PREDEF = YES + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = NO + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = "itkNotUsed(x)="\ + "itkSetMacro(name,type)= \ + virtual void Set##name (type _arg);" \ + "itkGetMacro(name,type)= \ + virtual type Get##name ();" \ + "itkGetConstMacro(name,type)= \ + virtual type Get##name () const;" \ + "itkSetStringMacro(name)= \ + virtual void Set##name (const char* _arg);" \ + "itkGetStringMacro(name)= \ + virtual const char* Get##name () const;" \ + "itkSetClampMacro(name,type,min,max)= \ + virtual void Set##name (type _arg);" \ + "itkSetObjectMacro(name,type)= \ + virtual void Set##name (type* _arg);" \ + "itkGetObjectMacro(name,type)= \ + virtual type* Get##name ();" \ + "itkSetConstObjectMacro(name,type)= \ + virtual void Set##name ( const type* _arg);" \ + "itkGetConstObjectMacro(name,type)= \ + virtual const type* Get##name ();" \ + "itkGetConstReferenceMacro(name,type)= \ + virtual const type& Get##name ();" \ + "itkGetConstReferenceObjectMacro(name,type)= \ + virtual const type::Pointer& Get##name () const;" \ + "itkBooleanMacro(name)= \ + virtual void name##On (); \ + virtual void name##Off ();" \ + "itkSetVector2Macro(name,type)= \ + virtual void Set##name (type _arg1, type _arg2) \ + virtual void Set##name (type _arg[2]);" \ + "itkGetVector2Macro(name,type)= \ + virtual type* Get##name () const; \ + virtual void Get##name (type& _arg1, type& _arg2) const; \ + virtual void Get##name (type _arg[2]) const;" \ + "itkSetVector3Macro(name,type)= \ + virtual void Set##name (type _arg1, type _arg2, type _arg3) \ + virtual void Set##name (type _arg[3]);" \ + "itkGetVector3Macro(name,type)= \ + virtual type* Get##name () const; \ + virtual void Get##name (type& _arg1, type& _arg2, type& _arg3) const; \ + virtual void Get##name (type _arg[3]) const;" \ + "itkSetVector4Macro(name,type)= \ + virtual void Set##name (type _arg1, type _arg2, type _arg3, type _arg4) \ + virtual void Set##name (type _arg[4]);" \ + "itkGetVector4Macro(name,type)= \ + virtual type* Get##name () const; \ + virtual void Get##name (type& _arg1, type& _arg2, type& _arg3, type& _arg4) const; \ + virtual void Get##name (type _arg[4]) const;" \ + "itkSetVector6Macro(name,type)= \ + virtual void Set##name (type _arg1, type _arg2, type _arg3, type _arg4, type _arg5, type _arg6) \ + virtual void Set##name (type _arg[6]);" \ + "itkGetVector6Macro(name,type)= \ + virtual type* Get##name () const; \ + virtual void Get##name (type& _arg1, type& _arg2, type& _arg3, type& _arg4, type& _arg5, type& _arg6) const; \ + virtual void Get##name (type _arg[6]) const;" \ + "itkSetVectorMacro(name,type,count)= \ + virtual void Set##name(type data[]);" \ + "itkGetVectorMacro(name,type,count)= \ + virtual type* Get##name () const;" \ + "itkNewMacro(type)= \ + static Pointer New();" \ + "itkTypeMacro(thisClass,superclass)= \ + virtual const char *GetNameOfClass() const;" \ + "itkEventMacro(thisClass,superclass)= \ + class thisClass : public superclass {};" \ + "itkConceptMacro(name,concept)= \ + enum { name = 0 };" \ + "vcl_numeric_limits= \ + std::numeric_limits" \ + "ITK_TYPENAME= \ + typename" \ + "FEM_ABSTRACT_CLASS(thisClass,parentClass)= \ + public: \ + /** Standard "Self" typedef.*/ \ + typedef thisClass Self; \ + /** Standard "Superclass" typedef. */ \ + typedef parentClass Superclass; \ + /** Pointer or SmartPointer to an object. */ \ + typedef Self* Pointer; \ + /** Const pointer or SmartPointer to an object. */ \ + typedef const Self* ConstPointer; \ + private:" \ + "FEM_CLASS(thisClass,parentClass)= \ + FEM_ABSTRACT_CLASS(thisClass,parentClass) \ + public: \ + /** Create a new object from the existing one */ \ + virtual Baseclass::Pointer Clone() const; \ + /** Class ID for FEM object factory */ \ + static const int CLID; \ + /** Virtual function to access the class ID */ \ + virtual int ClassID() const \ + { return CLID; } \ + /** Object creation in an itk compatible way */ \ + static Self::Pointer New() \ + { return new Self(); } \ + private:" \ + "FREEVERSION" "ERROR_CHECKING" \ + "HAS_TIFF" "HAS_JPEG" "HAS_NETLIB" "HAS_PNG" "HAS_ZLIB" \ + "HAS_GLUT" "HAS_QT" \ + "VCL_USE_NATIVE_STL=1" "VCL_USE_NATIVE_COMPLEX=1" \ + "VCL_HAS_BOOL=1" "VXL_BIG_ENDIAN=1" "VXL_LITTLE_ENDIAN=0"\ + "VNL_DLL_DATA=" "size_t=vcl_size_t" + + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse +# the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option is superseded by the HAVE_DOT option below. This is only a +# fallback. It is recommended to install and use dot, since it yields more +# powerful graphs. + +CLASS_DIAGRAMS = YES + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = YES + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will +# generate a call dependency graph for every global function or class method. +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable call graphs for selected +# functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_WIDTH = 1024 + +# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_HEIGHT = 1024 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that a graph may be further truncated if the graph's +# image dimensions are not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH +# and MAX_DOT_GRAPH_HEIGHT). If 0 is used for the depth value (the default), +# the graph is not depth-constrained. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, which results in a white background. +# Warning: Depending on the platform used, enabling this option may lead to +# badly anti-aliased labels on the edges of a graph (i.e. they become hard to +# read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = YES + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be +# used. If set to NO the values of all tags below this one will be ignored. + +SEARCHENGINE = NO diff --git a/Utilities/ITK/Utilities/Doxygen/itkdoxygen.pl.in b/Utilities/ITK/Utilities/Doxygen/itkdoxygen.pl.in new file mode 100644 index 0000000000000000000000000000000000000000..33054b5ea0953aea8452349f0fcec2e62589e0f2 --- /dev/null +++ b/Utilities/ITK/Utilities/Doxygen/itkdoxygen.pl.in @@ -0,0 +1,9 @@ +# for vxl files run the vxl_doxy.pl script, and use itkgroup.pl for all other files +if ( $ARGV[0] =~ /(vxl|vcl|vnl)/) +{ + system ("perl @ITK_SOURCE_DIR@/Utilities/Doxygen/vxl_doxy.pl $ARGV[0]"); +} +else +{ + system ("perl @ITK_SOURCE_DIR@/Utilities/Doxygen/itkgroup.pl $ARGV[0]"); +} diff --git a/Utilities/ITK/Utilities/Doxygen/itkgroup.pl b/Utilities/ITK/Utilities/Doxygen/itkgroup.pl new file mode 100644 index 0000000000000000000000000000000000000000..f5276d3f7f84d6eb89288ef94844c37a32ce87a6 --- /dev/null +++ b/Utilities/ITK/Utilities/Doxygen/itkgroup.pl @@ -0,0 +1,84 @@ +# if regular doxycomment add a @{ +# at next empty line add a //@} + +$ingroup = 0; +$semicount =0; +$endbracecount = 0; +$endparencount = 0; +while(<>) +{ + chomp; + $line = $_; +# if the line is not an empty line + if( $line =~ /\S+/ ) + { + if ( /\/\*\*(.*)/ ) + { + # I guess it was not a group, dump savebuffer + if($ingroup) + { + print "/**" . $savebuffer . "\n"; + } + # if it is a class or brief then output the line but + # do not start a group + if ( /(\\class|\\brief)/ ) + { + print $line . "\n"; + } + # must be a group so start saving + else + { + $savebuffer = "$1" . "\n"; + $ingroup = 1; + $semicount = 0; + $endbracecount = 0; + $endparencount = 0; + } + } + else + { + # add to save buffer if in group + if($ingroup) + { + $savebuffer = $savebuffer . $_ . "\n"; + } + else + { + # non empty line that is not the start of a doxy comment + print $_ . "\n"; + } + } + if($line =~ /;/ ) + { + $semicount = $semicount + 1; + } + if($line =~ /\}/ ) + { + $endbracecount = $endbracecount + 1; + } + if($line =~ /\)/ ) + { + $endparencount = $endparencount + 1; + } + } + else + { + if($ingroup) + { + if($endparencount > 1 && ($semicount > 1 || $endbracecount > 1)) + { + print "/**@\{" . $savebuffer . "//@}\n\n"; + } + else + { + print "/**" . $savebuffer . "\n"; + } + $savebuffer = ""; + $ingroup = 0; + } + else + { + print $line . "\n"; + } + } +} diff --git a/Utilities/ITK/Utilities/Doxygen/vxl_doxy.pl b/Utilities/ITK/Utilities/Doxygen/vxl_doxy.pl new file mode 100644 index 0000000000000000000000000000000000000000..f3590259f8b2b54921bf5db6a48cae319027cdb1 --- /dev/null +++ b/Utilities/ITK/Utilities/Doxygen/vxl_doxy.pl @@ -0,0 +1,127 @@ +#!/bin/sh +# -*- perl -*- +exec perl -w -x $0 ${1+"$@"} +#!perl +#line 6 +# If Windows barfs at line 3 here, you will need to run perl -x vxl_doxy.pl +# You can set up as a permanent file association using the following commands +# >assoc .pl-PerlScript +# >ftype PerlScript=Perl=C:\Perl\bin\Perl.exe -x "%1" %* + +# Script to change the perceps documentation format to Doxygen (JavaDoc) format +# Authors: +# Dave Cooper +# Maarten Vergauwen +# Date: +# 17/02/2000 +# Modified: +# 11 April 2001 Ian Scott. Remove support for old perceps commands +# 5 May 2001 Geoff Cross. Correctly handle end of verbatim blocks. Allow two contiguous comments +# 10 May 2001 Ian Scott. Merged Geoffs and my changes + + +# patterns to be matched +$verbpatt = '\\\\verbatim'; +$endverbpatt = '\\\\endverbatim'; +$slashslashpatt = '^\\s*//'; +$slashslashcolonpatt = '^\\s*//:'; +$slashstarstarpatt = '/**'; +$spacespacepatt = ' '; +$starpatt = '*'; +$starslashpatt = '*/'; + +# variables that keep state: + +# comment found -> first line should start with /**, next lines with *, last line with */ +$comment = 0; + +# verbatim found -> lines should not start with * (visible in Doxygen) +$verbatim = 0; +# finish verbatim mode at the end of this line. +$should_end_verbatim = 0; + +$debug = 0; + +# mainloop +while (<>) +{ + # preprocessing + s/\bVCL_SUNPRO_CLASS_SCOPE_HACK\s*\([^()]*\)//g; + s/\bVCL_SUNPRO_ALLOCATOR_HACK\s*\(([^()]*)\)/$1/g; + s/\bVCL_CAN_STATIC_CONST_INIT_(INT|FLOAT)\b/1/g; + s/\bVCL_STATIC_CONST_INIT_(INT|FLOAT)\s*\(([^()]*)\)/= $2/g; + s/\bVCL_DFL_TYPE_PARAM_STLDECL\s*\(([^,()]*),([^,()]*)\)/class $1 = $2 /g; + s/\bDECLARE_DYNCREATE\s*\([^()]*\)//g; # for MFC + + if ( $should_end_verbatim ) + { + $verbatim = 0; + $should_end_verbatim = 0; + } + + # found verbatim ? + if ( m/$verbpatt/ ) { $verbatim = 1; }; + + # found endverbatim ? + if ( m/$endverbpatt/ ) { $should_end_verbatim = 1; }; + + # found start of comment: "//:" ? + if ( s!$slashslashcolonpatt!$slashstarstarpatt! ) + { + chomp; s/\s*$//; + # escape a space following a dot, add a dot at the end, +# # and finish brief doc, unless the line is empty or only has '\file': + unless (m!^\s*\/\*\*\s*(\\file)?\s*$!) { +# s/\. /.\\ /g; s/(\.)?\s*$/. \*\/\n\/\*/; + s/\. /.\\ /g; s/(\.)?\s*$/.\n/; + } + else { s/$/\n/; } + + if ($comment) + { + # Previous comment hasn't ended--two contiguous comment blocks. + # (Should not happen.) + print STDERR "Two contiguous comment blocks -- this should not happen\n"; + print "*/\n"; + } + $comment = 1; + print; next; + } + + # Replace '$' with '\f$' (TeX math mode) + s/(\\f)?\$(.+?)(\\f)?\$/\\f\$$2\\f\$/g if ($comment); + + # found continuation of comment WITH verbatim -> no "*" + if ( m!$slashslashpatt! && $verbatim && $comment) + { + s!$slashslashpatt!$spacespacepatt!; +# # Make 'Modifications' a section title: +# s!\b(Modifications?)\b\:?!\<H2\>$1\<\/H2\>!; + # remove lines of the form ========= or +-+-+-+-+ or ********* or longer: + print unless m/^\s*[*=+-]{9,}\s*$/; next; + } + + # found continuation of comment WITHOUT verbatim -> start line with "*" + if ( m!$slashslashpatt! && $comment ) + { + s!$slashslashpatt!$starpatt!; + # remove lines of the form ========= or +-+-+-+-+ or ********* or longer: + print unless m/^\s*[*=+-]{9,}\s*$/; next; + } + + # found end of comment -> start line with */ + # NOTE that *every* line within a comment (also empty lines) *must* start with // ! + # (In an earlier version of this script, empty lines were allowed inside comments.) + if ( $comment && ! m!$slashslashpatt! ) + { + print "$starslashpatt\n"; + $comment = 0; + print; next; + } + + # just print line if not in comment or in file + if ( !$comment ) { print; next; } + + # debug - print unprocessed lines (s.b. none) + if ($debug) { print "LNP:\t"; print; } +} diff --git a/Utilities/ITK/Utilities/expat/CMakeLists.txt b/Utilities/ITK/Utilities/expat/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..0aef28bcae371ea7debd322e19befefeae097c68 --- /dev/null +++ b/Utilities/ITK/Utilities/expat/CMakeLists.txt @@ -0,0 +1,25 @@ +PROJECT(ITKEXPAT) +INCLUDE_REGULAR_EXPRESSION("^(expat|xml|ascii|utf|name|iascii|latin).*$") + +SET(expat_SRCS + xmltok.c xmlparse.c xmlrole.c +) + +INCLUDE_DIRECTORIES(BEFORE ${ITKEXPAT_SOURCE_DIR}) +INCLUDE_DIRECTORIES(BEFORE ${ITKEXPAT_BINARY_DIR}) + +IF(WIN32) + IF(NOT BUILD_SHARED_LIBS) + SET (ITK_EXPAT_STATIC 1) + ENDIF(NOT BUILD_SHARED_LIBS) +ENDIF(WIN32) + +CONFIGURE_FILE(${ITKEXPAT_SOURCE_DIR}/expatConfig.h.in + ${ITKEXPAT_BINARY_DIR}/expatConfig.h) +CONFIGURE_FILE(${ITKEXPAT_SOURCE_DIR}/expatDllConfig.h.in + ${ITKEXPAT_BINARY_DIR}/expatDllConfig.h) + +ADD_LIBRARY(ITKEXPAT ${expat_SRCS}) + +INSTALL_TARGETS(/lib/InsightToolkit ITKEXPAT) +INSTALL_FILES(/include/InsightToolkit/expat .h expat expatDllConfig) diff --git a/Utilities/ITK/Utilities/expat/COPYING b/Utilities/ITK/Utilities/expat/COPYING new file mode 100644 index 0000000000000000000000000000000000000000..fc97b02d90982cd28582dbe7ea056973bd9711af --- /dev/null +++ b/Utilities/ITK/Utilities/expat/COPYING @@ -0,0 +1,21 @@ +Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd + and Clark Cooper + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Utilities/ITK/Utilities/expat/ascii.h b/Utilities/ITK/Utilities/expat/ascii.h new file mode 100644 index 0000000000000000000000000000000000000000..6376b1f311b329df16489a3504786e670609ea05 --- /dev/null +++ b/Utilities/ITK/Utilities/expat/ascii.h @@ -0,0 +1,86 @@ +/* +Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd +See the file COPYING for copying permission. +*/ + +#define ASCII_A 0x41 +#define ASCII_B 0x42 +#define ASCII_C 0x43 +#define ASCII_D 0x44 +#define ASCII_E 0x45 +#define ASCII_F 0x46 +#define ASCII_G 0x47 +#define ASCII_H 0x48 +#define ASCII_I 0x49 +#define ASCII_J 0x4A +#define ASCII_K 0x4B +#define ASCII_L 0x4C +#define ASCII_M 0x4D +#define ASCII_N 0x4E +#define ASCII_O 0x4F +#define ASCII_P 0x50 +#define ASCII_Q 0x51 +#define ASCII_R 0x52 +#define ASCII_S 0x53 +#define ASCII_T 0x54 +#define ASCII_U 0x55 +#define ASCII_V 0x56 +#define ASCII_W 0x57 +#define ASCII_X 0x58 +#define ASCII_Y 0x59 +#define ASCII_Z 0x5A + +#define ASCII_a 0x61 +#define ASCII_b 0x62 +#define ASCII_c 0x63 +#define ASCII_d 0x64 +#define ASCII_e 0x65 +#define ASCII_f 0x66 +#define ASCII_g 0x67 +#define ASCII_h 0x68 +#define ASCII_i 0x69 +#define ASCII_j 0x6A +#define ASCII_k 0x6B +#define ASCII_l 0x6C +#define ASCII_m 0x6D +#define ASCII_n 0x6E +#define ASCII_o 0x6F +#define ASCII_p 0x70 +#define ASCII_q 0x71 +#define ASCII_r 0x72 +#define ASCII_s 0x73 +#define ASCII_t 0x74 +#define ASCII_u 0x75 +#define ASCII_v 0x76 +#define ASCII_w 0x77 +#define ASCII_x 0x78 +#define ASCII_y 0x79 +#define ASCII_z 0x7A + +#define ASCII_0 0x30 +#define ASCII_1 0x31 +#define ASCII_2 0x32 +#define ASCII_3 0x33 +#define ASCII_4 0x34 +#define ASCII_5 0x35 +#define ASCII_6 0x36 +#define ASCII_7 0x37 +#define ASCII_8 0x38 +#define ASCII_9 0x39 + +#define ASCII_TAB 0x09 +#define ASCII_SPACE 0x20 +#define ASCII_EXCL 0x21 +#define ASCII_QUOT 0x22 +#define ASCII_AMP 0x26 +#define ASCII_APOS 0x27 +#define ASCII_MINUS 0x2D +#define ASCII_PERIOD 0x2E +#define ASCII_COLON 0x3A +#define ASCII_SEMI 0x3B +#define ASCII_LT 0x3C +#define ASCII_EQUALS 0x3D +#define ASCII_GT 0x3E +#define ASCII_LSQB 0x5B +#define ASCII_RSQB 0x5D +#define ASCII_UNDERSCORE 0x5F diff --git a/Utilities/ITK/Utilities/expat/asciitab.h b/Utilities/ITK/Utilities/expat/asciitab.h new file mode 100644 index 0000000000000000000000000000000000000000..eb445cc52c15847132988397b594e0e4bae10347 --- /dev/null +++ b/Utilities/ITK/Utilities/expat/asciitab.h @@ -0,0 +1,37 @@ +/* +Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd +See the file COPYING for copying permission. +*/ + +/* 0x00 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x04 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x08 */ BT_NONXML, BT_S, BT_LF, BT_NONXML, +/* 0x0C */ BT_NONXML, BT_CR, BT_NONXML, BT_NONXML, +/* 0x10 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x14 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x18 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x1C */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x20 */ BT_S, BT_EXCL, BT_QUOT, BT_NUM, +/* 0x24 */ BT_OTHER, BT_PERCNT, BT_AMP, BT_APOS, +/* 0x28 */ BT_LPAR, BT_RPAR, BT_AST, BT_PLUS, +/* 0x2C */ BT_COMMA, BT_MINUS, BT_NAME, BT_SOL, +/* 0x30 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT, +/* 0x34 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT, +/* 0x38 */ BT_DIGIT, BT_DIGIT, BT_COLON, BT_SEMI, +/* 0x3C */ BT_LT, BT_EQUALS, BT_GT, BT_QUEST, +/* 0x40 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX, +/* 0x44 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT, +/* 0x48 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x4C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x50 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x54 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x58 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_LSQB, +/* 0x5C */ BT_OTHER, BT_RSQB, BT_OTHER, BT_NMSTRT, +/* 0x60 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX, +/* 0x64 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT, +/* 0x68 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x6C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x70 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x74 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x78 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER, +/* 0x7C */ BT_VERBAR, BT_OTHER, BT_OTHER, BT_OTHER, diff --git a/Utilities/ITK/Utilities/expat/expat.h b/Utilities/ITK/Utilities/expat/expat.h new file mode 100644 index 0000000000000000000000000000000000000000..d4eee5cdd35d7b5f14c4ecb4dccc39eeb51f1cc0 --- /dev/null +++ b/Utilities/ITK/Utilities/expat/expat.h @@ -0,0 +1,739 @@ +/* +Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd +See the file COPYING for copying permission. +*/ + +#ifndef XmlParse_INCLUDED +#define XmlParse_INCLUDED 1 + +#include <stdlib.h> + +#include "expatDllConfig.h" + +#if defined(_WIN32) && !defined(ITK_EXPAT_STATIC) +# if defined(vtkexpat_EXPORTS) +# define XMLPARSEAPI(type) __declspec( dllexport ) type __cdecl +# else +# define XMLPARSEAPI(type) __declspec( dllimport ) type __cdecl +# endif +#else +# define XMLPARSEAPI(type) type +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void *XML_Parser; + +/* Information is UTF-8 encoded. */ +typedef char XML_Char; +typedef char XML_LChar; + +enum XML_Content_Type { + XML_CTYPE_EMPTY = 1, + XML_CTYPE_ANY, + XML_CTYPE_MIXED, + XML_CTYPE_NAME, + XML_CTYPE_CHOICE, + XML_CTYPE_SEQ +}; + +enum XML_Content_Quant { + XML_CQUANT_NONE, + XML_CQUANT_OPT, + XML_CQUANT_REP, + XML_CQUANT_PLUS +}; + +/* If type == XML_CTYPE_EMPTY or XML_CTYPE_ANY, then quant will be + XML_CQUANT_NONE, and the other fields will be zero or NULL. + If type == XML_CTYPE_MIXED, then quant will be NONE or REP and + numchildren will contain number of elements that may be mixed in + and children point to an array of XML_Content cells that will be + all of XML_CTYPE_NAME type with no quantification. + + If type == XML_CTYPE_NAME, then the name points to the name, and + the numchildren field will be zero and children will be NULL. The + quant fields indicates any quantifiers placed on the name. + + CHOICE and SEQ will have name NULL, the number of children in + numchildren and children will point, recursively, to an array + of XML_Content cells. + + The EMPTY, ANY, and MIXED types will only occur at top level. +*/ + +typedef struct XML_cp XML_Content; + +struct XML_cp { + enum XML_Content_Type type; + enum XML_Content_Quant quant; + XML_Char * name; + unsigned int numchildren; + XML_Content * children; +}; + + +/* This is called for an element declaration. See above for + description of the model argument. It's the caller's responsibility + to free model when finished with it. +*/ + +typedef void (*XML_ElementDeclHandler) (void *userData, + const XML_Char *name, + XML_Content *model); + +XMLPARSEAPI(void) +XML_SetElementDeclHandler(XML_Parser parser, + XML_ElementDeclHandler eldecl); + +/* + The Attlist declaration handler is called for *each* attribute. So + a single Attlist declaration with multiple attributes declared will + generate multiple calls to this handler. The "default" parameter + may be NULL in the case of the "#IMPLIED" or "#REQUIRED" keyword. + The "isrequired" parameter will be true and the default value will + be NULL in the case of "#REQUIRED". If "isrequired" is true and + default is non-NULL, then this is a "#FIXED" default. + */ + +typedef void (*XML_AttlistDeclHandler) (void *userData, + const XML_Char *elname, + const XML_Char *attname, + const XML_Char *att_type, + const XML_Char *dflt, + int isrequired); + +XMLPARSEAPI(void) +XML_SetAttlistDeclHandler(XML_Parser parser, + XML_AttlistDeclHandler attdecl); + + + /* The XML declaration handler is called for *both* XML declarations and + text declarations. The way to distinguish is that the version parameter + will be null for text declarations. The encoding parameter may be null + for XML declarations. The standalone parameter will be -1, 0, or 1 + indicating respectively that there was no standalone parameter in + the declaration, that it was given as no, or that it was given as yes. + */ + +typedef void (*XML_XmlDeclHandler) (void *userData, + const XML_Char *version, + const XML_Char *encoding, + int standalone); + +XMLPARSEAPI(void) +XML_SetXmlDeclHandler(XML_Parser parser, + XML_XmlDeclHandler xmldecl); + + +typedef struct { + void *(*malloc_fcn)(size_t size); + void *(*realloc_fcn)(void *ptr, size_t size); + void (*free_fcn)(void *ptr); +} XML_Memory_Handling_Suite; + +/* Constructs a new parser; encoding is the encoding specified by the +external protocol or null if there is none specified. */ + +XMLPARSEAPI(XML_Parser) +XML_ParserCreate(const XML_Char *encoding); + +/* Constructs a new parser and namespace processor. Element type +names and attribute names that belong to a namespace will be expanded; +unprefixed attribute names are never expanded; unprefixed element type +names are expanded only if there is a default namespace. The expanded +name is the concatenation of the namespace URI, the namespace +separator character, and the local part of the name. If the namespace +separator is '\0' then the namespace URI and the local part will be +concatenated without any separator. When a namespace is not declared, +the name and prefix will be passed through without expansion. */ + +XMLPARSEAPI(XML_Parser) +XML_ParserCreateNS(const XML_Char *encoding, XML_Char namespaceSeparator); + + +/* Constructs a new parser using the memory management suit referred to + by memsuite. If memsuite is NULL, then use the standard library memory + suite. If namespaceSeparator is non-NULL it creates a parser with + namespace processing as described above. The character pointed at + will serve as the namespace separator. + + All further memory operations used for the created parser will come from + the given suite. +*/ + +XMLPARSEAPI(XML_Parser) +XML_ParserCreate_MM(const XML_Char *encoding, + const XML_Memory_Handling_Suite *memsuite, + const XML_Char *namespaceSeparator); + +/* atts is array of name/value pairs, terminated by 0; + names and values are 0 terminated. */ + +typedef void (*XML_StartElementHandler)(void *userData, + const XML_Char *name, + const XML_Char **atts); + +typedef void (*XML_EndElementHandler)(void *userData, + const XML_Char *name); + + +/* s is not 0 terminated. */ +typedef void (*XML_CharacterDataHandler)(void *userData, + const XML_Char *s, + int len); + +/* target and data are 0 terminated */ +typedef void (*XML_ProcessingInstructionHandler)(void *userData, + const XML_Char *target, + const XML_Char *data); + +/* data is 0 terminated */ +typedef void (*XML_CommentHandler)(void *userData, const XML_Char *data); + +typedef void (*XML_StartCdataSectionHandler)(void *userData); +typedef void (*XML_EndCdataSectionHandler)(void *userData); + +/* This is called for any characters in the XML document for +which there is no applicable handler. This includes both +characters that are part of markup which is of a kind that is +not reported (comments, markup declarations), or characters +that are part of a construct which could be reported but +for which no handler has been supplied. The characters are passed +exactly as they were in the XML document except that +they will be encoded in UTF-8. Line boundaries are not normalized. +Note that a byte order mark character is not passed to the default handler. +There are no guarantees about how characters are divided between calls +to the default handler: for example, a comment might be split between +multiple calls. */ + +typedef void (*XML_DefaultHandler)(void *userData, + const XML_Char *s, + int len); + +/* This is called for the start of the DOCTYPE declaration, before + any DTD or internal subset is parsed. */ + +typedef void (*XML_StartDoctypeDeclHandler)(void *userData, + const XML_Char *doctypeName, + const XML_Char *sysid, + const XML_Char *pubid, + int has_internal_subset); + +/* This is called for the start of the DOCTYPE declaration when the +closing > is encountered, but after processing any external subset. */ +typedef void (*XML_EndDoctypeDeclHandler)(void *userData); + +/* This is called for entity declarations. The is_parameter_entity + argument will be non-zero if the entity is a parameter entity, zero + otherwise. + + For internal entities (<!ENTITY foo "bar">), value will + be non-null and systemId, publicID, and notationName will be null. + The value string is NOT null terminated; the length is provided in + the value_length argument. Since it is legal to have zero-length + values, do not use this argument to test for internal entities. + + For external entities, value will be null and systemId will be non-null. + The publicId argument will be null unless a public identifier was + provided. The notationName argument will have a non-null value only + for unparsed entity declarations. +*/ + +typedef void (*XML_EntityDeclHandler) (void *userData, + const XML_Char *entityName, + int is_parameter_entity, + const XML_Char *value, + int value_length, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId, + const XML_Char *notationName); + +XMLPARSEAPI(void) +XML_SetEntityDeclHandler(XML_Parser parser, + XML_EntityDeclHandler handler); + +/* OBSOLETE -- OBSOLETE -- OBSOLETE + This handler has been superceded by the EntityDeclHandler above. + It is provided here for backward compatibility. +This is called for a declaration of an unparsed (NDATA) +entity. The base argument is whatever was set by XML_SetBase. +The entityName, systemId and notationName arguments will never be null. +The other arguments may be. */ + +typedef void (*XML_UnparsedEntityDeclHandler)(void *userData, + const XML_Char *entityName, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId, + const XML_Char *notationName); + +/* This is called for a declaration of notation. +The base argument is whatever was set by XML_SetBase. +The notationName will never be null. The other arguments can be. */ + +typedef void (*XML_NotationDeclHandler)(void *userData, + const XML_Char *notationName, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId); + +/* When namespace processing is enabled, these are called once for +each namespace declaration. The call to the start and end element +handlers occur between the calls to the start and end namespace +declaration handlers. For an xmlns attribute, prefix will be null. +For an xmlns="" attribute, uri will be null. */ + +typedef void (*XML_StartNamespaceDeclHandler)(void *userData, + const XML_Char *prefix, + const XML_Char *uri); + +typedef void (*XML_EndNamespaceDeclHandler)(void *userData, + const XML_Char *prefix); + +/* This is called if the document is not standalone (it has an +external subset or a reference to a parameter entity, but does not +have standalone="yes"). If this handler returns 0, then processing +will not continue, and the parser will return a +XML_ERROR_NOT_STANDALONE error. */ + +typedef int (*XML_NotStandaloneHandler)(void *userData); + +/* This is called for a reference to an external parsed general entity. +The referenced entity is not automatically parsed. +The application can parse it immediately or later using +XML_ExternalEntityParserCreate. +The parser argument is the parser parsing the entity containing the reference; +it can be passed as the parser argument to XML_ExternalEntityParserCreate. +The systemId argument is the system identifier as specified in the entity +declaration; it will not be null. +The base argument is the system identifier that should be used as the base for +resolving systemId if systemId was relative; this is set by XML_SetBase; +it may be null. +The publicId argument is the public identifier as specified in the entity +declaration, or null if none was specified; the whitespace in the public +identifier will have been normalized as required by the XML spec. +The context argument specifies the parsing context in the format +expected by the context argument to +XML_ExternalEntityParserCreate; context is valid only until the handler +returns, so if the referenced entity is to be parsed later, it must be copied. +The handler should return 0 if processing should not continue because of +a fatal error in the handling of the external entity. +In this case the calling parser will return an +XML_ERROR_EXTERNAL_ENTITY_HANDLING error. +Note that unlike other handlers the first argument is the parser, not +userData. */ + +typedef int (*XML_ExternalEntityRefHandler)(XML_Parser parser, + const XML_Char *context, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId); + +/* This structure is filled in by the XML_UnknownEncodingHandler +to provide information to the parser about encodings that are unknown +to the parser. +The map[b] member gives information about byte sequences +whose first byte is b. +If map[b] is c where c is >= 0, then b by itself encodes the Unicode scalar +value c. +If map[b] is -1, then the byte sequence is malformed. +If map[b] is -n, where n >= 2, then b is the first byte of an n-byte +sequence that encodes a single Unicode scalar value. +The data member will be passed as the first argument to the convert function. +The convert function is used to convert multibyte sequences; +s will point to a n-byte sequence where map[(unsigned char)*s] == -n. +The convert function must return the Unicode scalar value +represented by this byte sequence or -1 if the byte sequence is malformed. +The convert function may be null if the encoding is a single-byte encoding, +that is if map[b] >= -1 for all bytes b. +When the parser is finished with the encoding, then if release is not null, +it will call release passing it the data member; +once release has been called, the convert function will not be called again. + +Expat places certain restrictions on the encodings that are supported +using this mechanism. + +1. Every ASCII character that can appear in a well-formed XML document, +other than the characters + + $@\^`{}~ + +must be represented by a single byte, and that byte must be the +same byte that represents that character in ASCII. + +2. No character may require more than 4 bytes to encode. + +3. All characters encoded must have Unicode scalar values <= 0xFFFF, (i.e., +characters that would be encoded by surrogates in UTF-16 are not +allowed). Note that this restriction doesn't apply to the built-in +support for UTF-8 and UTF-16. + +4. No Unicode character may be encoded by more than one distinct sequence +of bytes. */ + +typedef struct { + int map[256]; + void *data; + int (*convert)(void *data, const char *s); + void (*release)(void *data); +} XML_Encoding; + +/* This is called for an encoding that is unknown to the parser. +The encodingHandlerData argument is that which was passed as the +second argument to XML_SetUnknownEncodingHandler. +The name argument gives the name of the encoding as specified in +the encoding declaration. +If the callback can provide information about the encoding, +it must fill in the XML_Encoding structure, and return 1. +Otherwise it must return 0. +If info does not describe a suitable encoding, +then the parser will return an XML_UNKNOWN_ENCODING error. */ + +typedef int (*XML_UnknownEncodingHandler)(void *encodingHandlerData, + const XML_Char *name, + XML_Encoding *info); + +XMLPARSEAPI(void) +XML_SetElementHandler(XML_Parser parser, + XML_StartElementHandler start, + XML_EndElementHandler end); + +XMLPARSEAPI(void) +XML_SetStartElementHandler(XML_Parser, XML_StartElementHandler); + +XMLPARSEAPI(void) +XML_SetEndElementHandler(XML_Parser, XML_EndElementHandler); + +XMLPARSEAPI(void) +XML_SetCharacterDataHandler(XML_Parser parser, + XML_CharacterDataHandler handler); + +XMLPARSEAPI(void) +XML_SetProcessingInstructionHandler(XML_Parser parser, + XML_ProcessingInstructionHandler handler); +XMLPARSEAPI(void) +XML_SetCommentHandler(XML_Parser parser, + XML_CommentHandler handler); + +XMLPARSEAPI(void) +XML_SetCdataSectionHandler(XML_Parser parser, + XML_StartCdataSectionHandler start, + XML_EndCdataSectionHandler end); + +XMLPARSEAPI(void) +XML_SetStartCdataSectionHandler(XML_Parser parser, + XML_StartCdataSectionHandler start); + +XMLPARSEAPI(void) +XML_SetEndCdataSectionHandler(XML_Parser parser, + XML_EndCdataSectionHandler end); + +/* This sets the default handler and also inhibits expansion of +internal entities. The entity reference will be passed to the default +handler. */ + +XMLPARSEAPI(void) +XML_SetDefaultHandler(XML_Parser parser, + XML_DefaultHandler handler); + +/* This sets the default handler but does not inhibit expansion of +internal entities. The entity reference will not be passed to the +default handler. */ + +XMLPARSEAPI(void) +XML_SetDefaultHandlerExpand(XML_Parser parser, + XML_DefaultHandler handler); + +XMLPARSEAPI(void) +XML_SetDoctypeDeclHandler(XML_Parser parser, + XML_StartDoctypeDeclHandler start, + XML_EndDoctypeDeclHandler end); + +XMLPARSEAPI(void) +XML_SetStartDoctypeDeclHandler(XML_Parser parser, + XML_StartDoctypeDeclHandler start); + +XMLPARSEAPI(void) +XML_SetEndDoctypeDeclHandler(XML_Parser parser, + XML_EndDoctypeDeclHandler end); + +XMLPARSEAPI(void) +XML_SetUnparsedEntityDeclHandler(XML_Parser parser, + XML_UnparsedEntityDeclHandler handler); + +XMLPARSEAPI(void) +XML_SetNotationDeclHandler(XML_Parser parser, + XML_NotationDeclHandler handler); + +XMLPARSEAPI(void) +XML_SetNamespaceDeclHandler(XML_Parser parser, + XML_StartNamespaceDeclHandler start, + XML_EndNamespaceDeclHandler end); + +XMLPARSEAPI(void) +XML_SetStartNamespaceDeclHandler(XML_Parser parser, + XML_StartNamespaceDeclHandler start); + +XMLPARSEAPI(void) +XML_SetEndNamespaceDeclHandler(XML_Parser parser, + XML_EndNamespaceDeclHandler end); + +XMLPARSEAPI(void) +XML_SetNotStandaloneHandler(XML_Parser parser, + XML_NotStandaloneHandler handler); + +XMLPARSEAPI(void) +XML_SetExternalEntityRefHandler(XML_Parser parser, + XML_ExternalEntityRefHandler handler); + +/* If a non-null value for arg is specified here, then it will be passed +as the first argument to the external entity ref handler instead +of the parser object. */ +XMLPARSEAPI(void) +XML_SetExternalEntityRefHandlerArg(XML_Parser, void *arg); + +XMLPARSEAPI(void) +XML_SetUnknownEncodingHandler(XML_Parser parser, + XML_UnknownEncodingHandler handler, + void *encodingHandlerData); + +/* This can be called within a handler for a start element, end element, +processing instruction or character data. It causes the corresponding +markup to be passed to the default handler. */ +XMLPARSEAPI(void) +XML_DefaultCurrent(XML_Parser parser); + +/* If do_nst is non-zero, and namespace processing is in effect, and + a name has a prefix (i.e. an explicit namespace qualifier) then + that name is returned as a triplet in a single + string separated by the separator character specified when the parser + was created: URI + sep + local_name + sep + prefix. + + If do_nst is zero, then namespace information is returned in the + default manner (URI + sep + local_name) whether or not the names + has a prefix. +*/ + +XMLPARSEAPI(void) +XML_SetReturnNSTriplet(XML_Parser parser, int do_nst); + +/* This value is passed as the userData argument to callbacks. */ +XMLPARSEAPI(void) +XML_SetUserData(XML_Parser parser, void *userData); + +/* Returns the last value set by XML_SetUserData or null. */ +#define XML_GetUserData(parser) (*(void **)(parser)) + +/* This is equivalent to supplying an encoding argument +to XML_ParserCreate. It must not be called after XML_Parse +or XML_ParseBuffer. */ + +XMLPARSEAPI(int) +XML_SetEncoding(XML_Parser parser, const XML_Char *encoding); + +/* If this function is called, then the parser will be passed +as the first argument to callbacks instead of userData. +The userData will still be accessible using XML_GetUserData. */ + +XMLPARSEAPI(void) +XML_UseParserAsHandlerArg(XML_Parser parser); + +/* Sets the base to be used for resolving relative URIs in system +identifiers in declarations. Resolving relative identifiers is left +to the application: this value will be passed through as the base +argument to the XML_ExternalEntityRefHandler, XML_NotationDeclHandler +and XML_UnparsedEntityDeclHandler. The base argument will be copied. +Returns zero if out of memory, non-zero otherwise. */ + +XMLPARSEAPI(int) +XML_SetBase(XML_Parser parser, const XML_Char *base); + +XMLPARSEAPI(const XML_Char *) +XML_GetBase(XML_Parser parser); + +/* Returns the number of the attribute/value pairs passed in last call +to the XML_StartElementHandler that were specified in the start-tag +rather than defaulted. Each attribute/value pair counts as 2; thus +this correspondds to an index into the atts array passed to the +XML_StartElementHandler. */ + +XMLPARSEAPI(int) +XML_GetSpecifiedAttributeCount(XML_Parser parser); + +/* Returns the index of the ID attribute passed in the last call to +XML_StartElementHandler, or -1 if there is no ID attribute. Each +attribute/value pair counts as 2; thus this correspondds to an index +into the atts array passed to the XML_StartElementHandler. */ + +XMLPARSEAPI(int) +XML_GetIdAttributeIndex(XML_Parser parser); + +/* Parses some input. Returns 0 if a fatal error is detected. +The last call to XML_Parse must have isFinal true; +len may be zero for this call (or any other). */ +XMLPARSEAPI(int) +XML_Parse(XML_Parser parser, const char *s, int len, int isFinal); + +XMLPARSEAPI(void *) +XML_GetBuffer(XML_Parser parser, int len); + +XMLPARSEAPI(int) +XML_ParseBuffer(XML_Parser parser, int len, int isFinal); + +/* Creates an XML_Parser object that can parse an external general +entity; context is a '\0'-terminated string specifying the parse +context; encoding is a '\0'-terminated string giving the name of the +externally specified encoding, or null if there is no externally +specified encoding. The context string consists of a sequence of +tokens separated by formfeeds (\f); a token consisting of a name +specifies that the general entity of the name is open; a token of the +form prefix=uri specifies the namespace for a particular prefix; a +token of the form =uri specifies the default namespace. This can be +called at any point after the first call to an +ExternalEntityRefHandler so longer as the parser has not yet been +freed. The new parser is completely independent and may safely be +used in a separate thread. The handlers and userData are initialized +from the parser argument. Returns 0 if out of memory. Otherwise +returns a new XML_Parser object. */ +XMLPARSEAPI(XML_Parser) +XML_ExternalEntityParserCreate(XML_Parser parser, + const XML_Char *context, + const XML_Char *encoding); + +enum XML_ParamEntityParsing { + XML_PARAM_ENTITY_PARSING_NEVER, + XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE, + XML_PARAM_ENTITY_PARSING_ALWAYS +}; + +/* Controls parsing of parameter entities (including the external DTD +subset). If parsing of parameter entities is enabled, then references +to external parameter entities (including the external DTD subset) +will be passed to the handler set with +XML_SetExternalEntityRefHandler. The context passed will be 0. +Unlike external general entities, external parameter entities can only +be parsed synchronously. If the external parameter entity is to be +parsed, it must be parsed during the call to the external entity ref +handler: the complete sequence of XML_ExternalEntityParserCreate, +XML_Parse/XML_ParseBuffer and XML_ParserFree calls must be made during +this call. After XML_ExternalEntityParserCreate has been called to +create the parser for the external parameter entity (context must be 0 +for this call), it is illegal to make any calls on the old parser +until XML_ParserFree has been called on the newly created parser. If +the library has been compiled without support for parameter entity +parsing (ie without XML_DTD being defined), then +XML_SetParamEntityParsing will return 0 if parsing of parameter +entities is requested; otherwise it will return non-zero. */ + +XMLPARSEAPI(int) +XML_SetParamEntityParsing(XML_Parser parser, + enum XML_ParamEntityParsing parsing); + +enum XML_Error { + XML_ERROR_NONE, + XML_ERROR_NO_MEMORY, + XML_ERROR_SYNTAX, + XML_ERROR_NO_ELEMENTS, + XML_ERROR_INVALID_TOKEN, + XML_ERROR_UNCLOSED_TOKEN, + XML_ERROR_PARTIAL_CHAR, + XML_ERROR_TAG_MISMATCH, + XML_ERROR_DUPLICATE_ATTRIBUTE, + XML_ERROR_JUNK_AFTER_DOC_ELEMENT, + XML_ERROR_PARAM_ENTITY_REF, + XML_ERROR_UNDEFINED_ENTITY, + XML_ERROR_RECURSIVE_ENTITY_REF, + XML_ERROR_ASYNC_ENTITY, + XML_ERROR_BAD_CHAR_REF, + XML_ERROR_BINARY_ENTITY_REF, + XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF, + XML_ERROR_MISPLACED_XML_PI, + XML_ERROR_UNKNOWN_ENCODING, + XML_ERROR_INCORRECT_ENCODING, + XML_ERROR_UNCLOSED_CDATA_SECTION, + XML_ERROR_EXTERNAL_ENTITY_HANDLING, + XML_ERROR_NOT_STANDALONE, + XML_ERROR_UNEXPECTED_STATE +}; + +/* If XML_Parse or XML_ParseBuffer have returned 0, then XML_GetErrorCode +returns information about the error. */ + +XMLPARSEAPI(enum XML_Error) +XML_GetErrorCode(XML_Parser parser); + +/* These functions return information about the current parse location. +They may be called when XML_Parse or XML_ParseBuffer return 0; +in this case the location is the location of the character at which +the error was detected. +They may also be called from any other callback called to report +some parse event; in this the location is the location of the first +of the sequence of characters that generated the event. */ + +XMLPARSEAPI(int) XML_GetCurrentLineNumber(XML_Parser parser); +XMLPARSEAPI(int) XML_GetCurrentColumnNumber(XML_Parser parser); +XMLPARSEAPI(long) XML_GetCurrentByteIndex(XML_Parser parser); + +/* Return the number of bytes in the current event. +Returns 0 if the event is in an internal entity. */ + +XMLPARSEAPI(int) +XML_GetCurrentByteCount(XML_Parser parser); + +/* If XML_CONTEXT_BYTES is defined, returns the input buffer, sets + the integer pointed to by offset to the offset within this buffer + of the current parse position, and sets the integer pointed to by size + to the size of this buffer (the number of input bytes). Otherwise + returns a null pointer. Also returns a null pointer if a parse isn't + active. + + NOTE: The character pointer returned should not be used outside + the handler that makes the call. */ + +XMLPARSEAPI(const char *) +XML_GetInputContext(XML_Parser parser, + int *offset, + int *size); + +/* For backwards compatibility with previous versions. */ +#define XML_GetErrorLineNumber XML_GetCurrentLineNumber +#define XML_GetErrorColumnNumber XML_GetCurrentColumnNumber +#define XML_GetErrorByteIndex XML_GetCurrentByteIndex + +/* Frees memory used by the parser. */ +XMLPARSEAPI(void) +XML_ParserFree(XML_Parser parser); + +/* Returns a string describing the error. */ +XMLPARSEAPI(const XML_LChar *) +XML_ErrorString(int code); + +/* Return a string containing the version number of this expat */ +XMLPARSEAPI(const XML_LChar *) +XML_ExpatVersion(void); + +typedef struct { + int major; + int minor; + int micro; +} XML_Expat_Version; + +/* Return an XML_Expat_Version structure containing numeric version + number information for this version of expat */ + +XMLPARSEAPI(XML_Expat_Version) +XML_ExpatVersionInfo(void); + +#define XML_MAJOR_VERSION 1 +#define XML_MINOR_VERSION 95 +#define XML_MICRO_VERSION 2 + +#ifdef __cplusplus +} +#endif + +#endif /* not XmlParse_INCLUDED */ diff --git a/Utilities/ITK/Utilities/expat/expatConfig.h.in b/Utilities/ITK/Utilities/expat/expatConfig.h.in new file mode 100644 index 0000000000000000000000000000000000000000..d6997ec25002cddb4692006e0925a75d3322bd43 --- /dev/null +++ b/Utilities/ITK/Utilities/expat/expatConfig.h.in @@ -0,0 +1,42 @@ +#if defined(_WIN32) || defined(WIN32) + +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#undef WIN32_LEAN_AND_MEAN +#include <memory.h> +#include <string.h> +#define XML_BYTE_ORDER 12 + +#else + +#cmakedefine CMAKE_WORDS_BIGENDIAN +#ifdef CMAKE_WORDS_BIGENDIAN +# define XML_BYTE_ORDER 21 +#else +# define XML_BYTE_ORDER 12 +#endif + +#endif + +#define XML_NS +#define XML_DTD +#define XML_CONTEXT_BYTES 1024 + +#if defined ( _MSC_VER ) +#pragma warning ( disable : 4100 ) +#pragma warning ( disable : 4127 ) +#pragma warning ( disable : 4244 ) +#pragma warning ( disable : 4251 ) +#pragma warning ( disable : 4305 ) +#pragma warning ( disable : 4309 ) +#pragma warning ( disable : 4702 ) +#pragma warning ( disable : 4706 ) +#pragma warning ( disable : 4786 ) +#pragma warning ( disable : 4057 ) +#pragma warning ( disable : 4189 ) +#pragma warning ( disable : 4505 ) +#endif + +#define VERSION "1.95.2" + +#define itkExpatUnused(x) (void)x diff --git a/Utilities/ITK/Utilities/expat/expatDllConfig.h.in b/Utilities/ITK/Utilities/expat/expatDllConfig.h.in new file mode 100644 index 0000000000000000000000000000000000000000..7f1986cf85eddad14be06ef6146b43a4d4fc1ad7 --- /dev/null +++ b/Utilities/ITK/Utilities/expat/expatDllConfig.h.in @@ -0,0 +1,6 @@ +#ifndef _expatDllConfig_h +#define _expatDllConfig_h + +#cmakedefine ITK_EXPAT_STATIC + +#endif diff --git a/Utilities/ITK/Utilities/expat/iasciitab.h b/Utilities/ITK/Utilities/expat/iasciitab.h new file mode 100644 index 0000000000000000000000000000000000000000..55dbc398b8779da3fbd481b7d61a1dcdaaab189a --- /dev/null +++ b/Utilities/ITK/Utilities/expat/iasciitab.h @@ -0,0 +1,38 @@ +/* +Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd +See the file COPYING for copying permission. +*/ + +/* Like asciitab.h, except that 0xD has code BT_S rather than BT_CR */ +/* 0x00 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x04 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x08 */ BT_NONXML, BT_S, BT_LF, BT_NONXML, +/* 0x0C */ BT_NONXML, BT_S, BT_NONXML, BT_NONXML, +/* 0x10 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x14 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x18 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x1C */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x20 */ BT_S, BT_EXCL, BT_QUOT, BT_NUM, +/* 0x24 */ BT_OTHER, BT_PERCNT, BT_AMP, BT_APOS, +/* 0x28 */ BT_LPAR, BT_RPAR, BT_AST, BT_PLUS, +/* 0x2C */ BT_COMMA, BT_MINUS, BT_NAME, BT_SOL, +/* 0x30 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT, +/* 0x34 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT, +/* 0x38 */ BT_DIGIT, BT_DIGIT, BT_COLON, BT_SEMI, +/* 0x3C */ BT_LT, BT_EQUALS, BT_GT, BT_QUEST, +/* 0x40 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX, +/* 0x44 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT, +/* 0x48 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x4C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x50 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x54 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x58 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_LSQB, +/* 0x5C */ BT_OTHER, BT_RSQB, BT_OTHER, BT_NMSTRT, +/* 0x60 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX, +/* 0x64 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT, +/* 0x68 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x6C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x70 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x74 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x78 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER, +/* 0x7C */ BT_VERBAR, BT_OTHER, BT_OTHER, BT_OTHER, diff --git a/Utilities/ITK/Utilities/expat/latin1tab.h b/Utilities/ITK/Utilities/expat/latin1tab.h new file mode 100644 index 0000000000000000000000000000000000000000..178b1d186dd1f4015eb899583aa6dfa9c392f50b --- /dev/null +++ b/Utilities/ITK/Utilities/expat/latin1tab.h @@ -0,0 +1,37 @@ +/* +Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd +See the file COPYING for copying permission. +*/ + +/* 0x80 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0x84 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0x88 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0x8C */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0x90 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0x94 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0x98 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0x9C */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0xA0 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0xA4 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0xA8 */ BT_OTHER, BT_OTHER, BT_NMSTRT, BT_OTHER, +/* 0xAC */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0xB0 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0xB4 */ BT_OTHER, BT_NMSTRT, BT_OTHER, BT_NAME, +/* 0xB8 */ BT_OTHER, BT_OTHER, BT_NMSTRT, BT_OTHER, +/* 0xBC */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0xC0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xC4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xC8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xCC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xD0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xD4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER, +/* 0xD8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xDC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xE0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xE4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xE8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xEC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xF0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xF4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER, +/* 0xF8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xFC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, diff --git a/Utilities/ITK/Utilities/expat/nametab.h b/Utilities/ITK/Utilities/expat/nametab.h new file mode 100644 index 0000000000000000000000000000000000000000..b05e62c77a6c624a6828dd3f4e25ba8fe841e7a0 --- /dev/null +++ b/Utilities/ITK/Utilities/expat/nametab.h @@ -0,0 +1,150 @@ +static const unsigned namingBitmap[] = { +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, +0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, +0x00000000, 0x04000000, 0x87FFFFFE, 0x07FFFFFE, +0x00000000, 0x00000000, 0xFF7FFFFF, 0xFF7FFFFF, +0xFFFFFFFF, 0x7FF3FFFF, 0xFFFFFDFE, 0x7FFFFFFF, +0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFE00F, 0xFC31FFFF, +0x00FFFFFF, 0x00000000, 0xFFFF0000, 0xFFFFFFFF, +0xFFFFFFFF, 0xF80001FF, 0x00000003, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0xFFFFD740, 0xFFFFFFFB, 0x547F7FFF, 0x000FFFFD, +0xFFFFDFFE, 0xFFFFFFFF, 0xDFFEFFFF, 0xFFFFFFFF, +0xFFFF0003, 0xFFFFFFFF, 0xFFFF199F, 0x033FCFFF, +0x00000000, 0xFFFE0000, 0x027FFFFF, 0xFFFFFFFE, +0x0000007F, 0x00000000, 0xFFFF0000, 0x000707FF, +0x00000000, 0x07FFFFFE, 0x000007FE, 0xFFFE0000, +0xFFFFFFFF, 0x7CFFFFFF, 0x002F7FFF, 0x00000060, +0xFFFFFFE0, 0x23FFFFFF, 0xFF000000, 0x00000003, +0xFFF99FE0, 0x03C5FDFF, 0xB0000000, 0x00030003, +0xFFF987E0, 0x036DFDFF, 0x5E000000, 0x001C0000, +0xFFFBAFE0, 0x23EDFDFF, 0x00000000, 0x00000001, +0xFFF99FE0, 0x23CDFDFF, 0xB0000000, 0x00000003, +0xD63DC7E0, 0x03BFC718, 0x00000000, 0x00000000, +0xFFFDDFE0, 0x03EFFDFF, 0x00000000, 0x00000003, +0xFFFDDFE0, 0x03EFFDFF, 0x40000000, 0x00000003, +0xFFFDDFE0, 0x03FFFDFF, 0x00000000, 0x00000003, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0xFFFFFFFE, 0x000D7FFF, 0x0000003F, 0x00000000, +0xFEF02596, 0x200D6CAE, 0x0000001F, 0x00000000, +0x00000000, 0x00000000, 0xFFFFFEFF, 0x000003FF, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0xFFFFFFFF, 0xFFFF003F, 0x007FFFFF, +0x0007DAED, 0x50000000, 0x82315001, 0x002C62AB, +0x40000000, 0xF580C900, 0x00000007, 0x02010800, +0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, +0x0FFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x03FFFFFF, +0x3F3FFFFF, 0xFFFFFFFF, 0xAAFF3F3F, 0x3FFFFFFF, +0xFFFFFFFF, 0x5FDFFFFF, 0x0FCF1FDC, 0x1FDC1FFF, +0x00000000, 0x00004C40, 0x00000000, 0x00000000, +0x00000007, 0x00000000, 0x00000000, 0x00000000, +0x00000080, 0x000003FE, 0xFFFFFFFE, 0xFFFFFFFF, +0x001FFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0x07FFFFFF, +0xFFFFFFE0, 0x00001FFF, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, +0xFFFFFFFF, 0x0000003F, 0x00000000, 0x00000000, +0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, +0xFFFFFFFF, 0x0000000F, 0x00000000, 0x00000000, +0x00000000, 0x07FF6000, 0x87FFFFFE, 0x07FFFFFE, +0x00000000, 0x00800000, 0xFF7FFFFF, 0xFF7FFFFF, +0x00FFFFFF, 0x00000000, 0xFFFF0000, 0xFFFFFFFF, +0xFFFFFFFF, 0xF80001FF, 0x00030003, 0x00000000, +0xFFFFFFFF, 0xFFFFFFFF, 0x0000003F, 0x00000003, +0xFFFFD7C0, 0xFFFFFFFB, 0x547F7FFF, 0x000FFFFD, +0xFFFFDFFE, 0xFFFFFFFF, 0xDFFEFFFF, 0xFFFFFFFF, +0xFFFF007B, 0xFFFFFFFF, 0xFFFF199F, 0x033FCFFF, +0x00000000, 0xFFFE0000, 0x027FFFFF, 0xFFFFFFFE, +0xFFFE007F, 0xBBFFFFFB, 0xFFFF0016, 0x000707FF, +0x00000000, 0x07FFFFFE, 0x0007FFFF, 0xFFFF03FF, +0xFFFFFFFF, 0x7CFFFFFF, 0xFFEF7FFF, 0x03FF3DFF, +0xFFFFFFEE, 0xF3FFFFFF, 0xFF1E3FFF, 0x0000FFCF, +0xFFF99FEE, 0xD3C5FDFF, 0xB080399F, 0x0003FFCF, +0xFFF987E4, 0xD36DFDFF, 0x5E003987, 0x001FFFC0, +0xFFFBAFEE, 0xF3EDFDFF, 0x00003BBF, 0x0000FFC1, +0xFFF99FEE, 0xF3CDFDFF, 0xB0C0398F, 0x0000FFC3, +0xD63DC7EC, 0xC3BFC718, 0x00803DC7, 0x0000FF80, +0xFFFDDFEE, 0xC3EFFDFF, 0x00603DDF, 0x0000FFC3, +0xFFFDDFEC, 0xC3EFFDFF, 0x40603DDF, 0x0000FFC3, +0xFFFDDFEC, 0xC3FFFDFF, 0x00803DCF, 0x0000FFC3, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0xFFFFFFFE, 0x07FF7FFF, 0x03FF7FFF, 0x00000000, +0xFEF02596, 0x3BFF6CAE, 0x03FF3F5F, 0x00000000, +0x03000000, 0xC2A003FF, 0xFFFFFEFF, 0xFFFE03FF, +0xFEBF0FDF, 0x02FE3FFF, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x1FFF0000, 0x00000002, +0x000000A0, 0x003EFFFE, 0xFFFFFFFE, 0xFFFFFFFF, +0x661FFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0x77FFFFFF, +}; +static const unsigned char nmstrtPages[] = { +0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x00, +0x00, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, +0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x13, +0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x15, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x17, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x18, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; +static const unsigned char namePages[] = { +0x19, 0x03, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x00, +0x00, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, +0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x13, +0x26, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x27, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x17, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x18, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; diff --git a/Utilities/ITK/Utilities/expat/utf8tab.h b/Utilities/ITK/Utilities/expat/utf8tab.h new file mode 100644 index 0000000000000000000000000000000000000000..9e3b6b83eb628ba53b1896ec0279f6cb67630739 --- /dev/null +++ b/Utilities/ITK/Utilities/expat/utf8tab.h @@ -0,0 +1,38 @@ +/* +Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd +See the file COPYING for copying permission. +*/ + + +/* 0x80 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0x84 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0x88 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0x8C */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0x90 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0x94 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0x98 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0x9C */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0xA0 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0xA4 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0xA8 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0xAC */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0xB0 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0xB4 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0xB8 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0xBC */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0xC0 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, +/* 0xC4 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, +/* 0xC8 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, +/* 0xCC */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, +/* 0xD0 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, +/* 0xD4 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, +/* 0xD8 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, +/* 0xDC */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, +/* 0xE0 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3, +/* 0xE4 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3, +/* 0xE8 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3, +/* 0xEC */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3, +/* 0xF0 */ BT_LEAD4, BT_LEAD4, BT_LEAD4, BT_LEAD4, +/* 0xF4 */ BT_LEAD4, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0xF8 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0xFC */ BT_NONXML, BT_NONXML, BT_MALFORM, BT_MALFORM, diff --git a/Utilities/ITK/Utilities/expat/xmlparse.c b/Utilities/ITK/Utilities/expat/xmlparse.c new file mode 100644 index 0000000000000000000000000000000000000000..7d2f72fd10eada49a8dac973da27dd5ebfac6e2c --- /dev/null +++ b/Utilities/ITK/Utilities/expat/xmlparse.c @@ -0,0 +1,4622 @@ +/* +Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd +See the file COPYING for copying permission. +*/ + +#include "expatConfig.h" +#include "expat.h" + +#include <stddef.h> +#include <string.h> + +#ifdef XML_UNICODE +#define XML_ENCODE_MAX XML_UTF16_ENCODE_MAX +#define XmlConvert XmlUtf16Convert +#define XmlGetInternalEncoding XmlGetUtf16InternalEncoding +#define XmlGetInternalEncodingNS XmlGetUtf16InternalEncodingNS +#define XmlEncode XmlUtf16Encode +#define MUST_CONVERT(enc, s) (!(enc)->isUtf16 || (((unsigned long)s) & 1)) +typedef unsigned short ICHAR; +#else +#define XML_ENCODE_MAX XML_UTF8_ENCODE_MAX +#define XmlConvert XmlUtf8Convert +#define XmlGetInternalEncoding XmlGetUtf8InternalEncoding +#define XmlGetInternalEncodingNS XmlGetUtf8InternalEncodingNS +#define XmlEncode XmlUtf8Encode +#define MUST_CONVERT(enc, s) (!(enc)->isUtf8) +typedef char ICHAR; +#endif + + +#ifndef XML_NS + +#define XmlInitEncodingNS XmlInitEncoding +#define XmlInitUnknownEncodingNS XmlInitUnknownEncoding +#undef XmlGetInternalEncodingNS +#define XmlGetInternalEncodingNS XmlGetInternalEncoding +#define XmlParseXmlDeclNS XmlParseXmlDecl + +#endif + +#ifdef XML_UNICODE_WCHAR_T +#define XML_T(x) L ## x +#else +#define XML_T(x) x +#endif + +/* Round up n to be a multiple of sz, where sz is a power of 2. */ +#define ROUND_UP(n, sz) (((n) + ((sz) - 1)) & ~((sz) - 1)) + +#include "xmltok.h" +#include "xmlrole.h" + +typedef const XML_Char *KEY; + +typedef struct { + KEY name; +} NAMED; + +typedef struct { + NAMED **v; + size_t size; + size_t used; + size_t usedLim; + XML_Memory_Handling_Suite *mem; +} HASH_TABLE; + +typedef struct { + NAMED **p; + NAMED **end; +} HASH_TABLE_ITER; + +#define INIT_TAG_BUF_SIZE 32 /* must be a multiple of sizeof(XML_Char) */ +#define INIT_DATA_BUF_SIZE 1024 +#define INIT_ATTS_SIZE 16 +#define INIT_BLOCK_SIZE 1024 +#define INIT_BUFFER_SIZE 1024 + +#define EXPAND_SPARE 24 + +typedef struct binding { + struct prefix *prefix; + struct binding *nextTagBinding; + struct binding *prevPrefixBinding; + const struct attribute_id *attId; + XML_Char *uri; + int uriLen; + int uriAlloc; +} BINDING; + +typedef struct prefix { + const XML_Char *name; + BINDING *binding; +} PREFIX; + +typedef struct { + const XML_Char *str; + const XML_Char *localPart; + int uriLen; +} TAG_NAME; + +typedef struct tag { + struct tag *parent; + const char *rawName; + int rawNameLength; + TAG_NAME name; + char *buf; + char *bufEnd; + BINDING *bindings; +} TAG; + +typedef struct { + const XML_Char *name; + const XML_Char *textPtr; + int textLen; + const XML_Char *systemId; + const XML_Char *base; + const XML_Char *publicId; + const XML_Char *notation; + char open; + char is_param; +} ENTITY; + +typedef struct { + enum XML_Content_Type type; + enum XML_Content_Quant quant; + const XML_Char * name; + int firstchild; + int lastchild; + int childcnt; + int nextsib; +} CONTENT_SCAFFOLD; + +typedef struct block { + struct block *next; + int size; + XML_Char s[1]; +} BLOCK; + +typedef struct { + BLOCK *blocks; + BLOCK *freeBlocks; + const XML_Char *end; + XML_Char *ptr; + XML_Char *start; + XML_Memory_Handling_Suite *mem; +} STRING_POOL; + +/* The XML_Char before the name is used to determine whether +an attribute has been specified. */ +typedef struct attribute_id { + XML_Char *name; + PREFIX *prefix; + char maybeTokenized; + char xmlns; +} ATTRIBUTE_ID; + +typedef struct { + const ATTRIBUTE_ID *id; + char isCdata; + const XML_Char *value; +} DEFAULT_ATTRIBUTE; + +typedef struct { + const XML_Char *name; + PREFIX *prefix; + const ATTRIBUTE_ID *idAtt; + int nDefaultAtts; + int allocDefaultAtts; + DEFAULT_ATTRIBUTE *defaultAtts; +} ELEMENT_TYPE; + +typedef struct { + HASH_TABLE generalEntities; + HASH_TABLE elementTypes; + HASH_TABLE attributeIds; + HASH_TABLE prefixes; + STRING_POOL pool; + int complete; + int standalone; +#ifdef XML_DTD + HASH_TABLE paramEntities; +#endif /* XML_DTD */ + PREFIX defaultPrefix; + /* === scaffolding for building content model === */ + int in_eldecl; + CONTENT_SCAFFOLD *scaffold; + unsigned contentStringLen; + unsigned scaffSize; + unsigned scaffCount; + int scaffLevel; + int *scaffIndex; +} DTD; + +typedef struct open_internal_entity { + const char *internalEventPtr; + const char *internalEventEndPtr; + struct open_internal_entity *next; + ENTITY *entity; +} OPEN_INTERNAL_ENTITY; + +typedef enum XML_Error Processor(XML_Parser parser, + const char *start, + const char *end, + const char **endPtr); + +static Processor prologProcessor; +static Processor prologInitProcessor; +static Processor contentProcessor; +static Processor cdataSectionProcessor; +#ifdef XML_DTD +static Processor ignoreSectionProcessor; +#endif /* XML_DTD */ +static Processor epilogProcessor; +static Processor errorProcessor; +static Processor externalEntityInitProcessor; +static Processor externalEntityInitProcessor2; +static Processor externalEntityInitProcessor3; +static Processor externalEntityContentProcessor; + +static enum XML_Error +handleUnknownEncoding(XML_Parser parser, const XML_Char *encodingName); +static enum XML_Error +processXmlDecl(XML_Parser parser, int isGeneralTextEntity, const char *, const char *); +static enum XML_Error +initializeEncoding(XML_Parser parser); +static enum XML_Error +doProlog(XML_Parser parser, const ENCODING *enc, const char *s, + const char *end, int tok, const char *next, const char **nextPtr); +static enum XML_Error +processInternalParamEntity(XML_Parser parser, ENTITY *entity); +static enum XML_Error +doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, + const char *start, const char *end, const char **endPtr); +static enum XML_Error +doCdataSection(XML_Parser parser, const ENCODING *, const char **startPtr, const char *end, const char **nextPtr); +#ifdef XML_DTD +static enum XML_Error +doIgnoreSection(XML_Parser parser, const ENCODING *, const char **startPtr, const char *end, const char **nextPtr); +#endif /* XML_DTD */ +static enum XML_Error storeAtts(XML_Parser parser, const ENCODING *, const char *s, + TAG_NAME *tagNamePtr, BINDING **bindingsPtr); +static +int addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId, const XML_Char *uri, BINDING **bindingsPtr); + +static int +defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *, + int isCdata, int isId, const XML_Char *dfltValue, + XML_Parser parser); + +static enum XML_Error +storeAttributeValue(XML_Parser parser, const ENCODING *, int isCdata, const char *, const char *, + STRING_POOL *); +static enum XML_Error +appendAttributeValue(XML_Parser parser, const ENCODING *, int isCdata, const char *, const char *, + STRING_POOL *); +static ATTRIBUTE_ID * +getAttributeId(XML_Parser parser, const ENCODING *enc, const char *start, const char *end); +static int setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *); +static enum XML_Error +storeEntityValue(XML_Parser parser, const ENCODING *enc, const char *start, const char *end); +static int +reportProcessingInstruction(XML_Parser parser, const ENCODING *enc, const char *start, const char *end); +static int +reportComment(XML_Parser parser, const ENCODING *enc, const char *start, const char *end); +static void +reportDefault(XML_Parser parser, const ENCODING *enc, const char *start, const char *end); + +static const XML_Char *getContext(XML_Parser parser); +static int setContext(XML_Parser parser, const XML_Char *context); +static void normalizePublicId(XML_Char *s); +static int dtdInit(DTD *, XML_Parser parser); + +static void dtdDestroy(DTD *, XML_Parser parser); + +static int dtdCopy(DTD *newDtd, const DTD *oldDtd, XML_Parser parser); + +static int copyEntityTable(HASH_TABLE *, STRING_POOL *, const HASH_TABLE *, + XML_Parser parser); + +#ifdef XML_DTD +static void dtdSwap(DTD *, DTD *); +#endif /* XML_DTD */ + +static NAMED *lookup(HASH_TABLE *table, KEY name, size_t createSize); + +static void hashTableInit(HASH_TABLE *, XML_Memory_Handling_Suite *ms); + +static void hashTableDestroy(HASH_TABLE *); +static void hashTableIterInit(HASH_TABLE_ITER *, const HASH_TABLE *); +static NAMED *hashTableIterNext(HASH_TABLE_ITER *); +static void poolInit(STRING_POOL *, XML_Memory_Handling_Suite *ms); +static void poolClear(STRING_POOL *); +static void poolDestroy(STRING_POOL *); +static XML_Char *poolAppend(STRING_POOL *pool, const ENCODING *enc, + const char *ptr, const char *end); +static XML_Char *poolStoreString(STRING_POOL *pool, const ENCODING *enc, + const char *ptr, const char *end); + +static int poolGrow(STRING_POOL *pool); + +static int nextScaffoldPart(XML_Parser parser); +static XML_Content *build_model(XML_Parser parser); + +static const XML_Char *poolCopyString(STRING_POOL *pool, const XML_Char *s); +static const XML_Char *poolCopyStringN(STRING_POOL *pool, const XML_Char *s, int n); +static const XML_Char *poolAppendString(STRING_POOL *pool, const XML_Char *s); +static ELEMENT_TYPE * getElementType(XML_Parser Paraser, + const ENCODING *enc, + const char *ptr, + const char *end); + +#define poolStart(pool) ((pool)->start) +#define poolEnd(pool) ((pool)->ptr) +#define poolLength(pool) ((pool)->ptr - (pool)->start) +#define poolChop(pool) ((void)--(pool->ptr)) +#define poolLastChar(pool) (((pool)->ptr)[-1]) +#define poolDiscard(pool) ((pool)->ptr = (pool)->start) +#define poolFinish(pool) ((pool)->start = (pool)->ptr) +#define poolAppendChar(pool, c) \ + (((pool)->ptr == (pool)->end && !poolGrow(pool)) \ + ? 0 \ + : ((*((pool)->ptr)++ = c), 1)) + +typedef struct { + /* The first member must be userData so that the XML_GetUserData macro works. */ + void *m_userData; + void *m_handlerArg; + char *m_buffer; + XML_Memory_Handling_Suite m_mem; + /* first character to be parsed */ + const char *m_bufferPtr; + /* past last character to be parsed */ + char *m_bufferEnd; + /* allocated end of buffer */ + const char *m_bufferLim; + long m_parseEndByteIndex; + const char *m_parseEndPtr; + XML_Char *m_dataBuf; + XML_Char *m_dataBufEnd; + XML_StartElementHandler m_startElementHandler; + XML_EndElementHandler m_endElementHandler; + XML_CharacterDataHandler m_characterDataHandler; + XML_ProcessingInstructionHandler m_processingInstructionHandler; + XML_CommentHandler m_commentHandler; + XML_StartCdataSectionHandler m_startCdataSectionHandler; + XML_EndCdataSectionHandler m_endCdataSectionHandler; + XML_DefaultHandler m_defaultHandler; + XML_StartDoctypeDeclHandler m_startDoctypeDeclHandler; + XML_EndDoctypeDeclHandler m_endDoctypeDeclHandler; + XML_UnparsedEntityDeclHandler m_unparsedEntityDeclHandler; + XML_NotationDeclHandler m_notationDeclHandler; + XML_StartNamespaceDeclHandler m_startNamespaceDeclHandler; + XML_EndNamespaceDeclHandler m_endNamespaceDeclHandler; + XML_NotStandaloneHandler m_notStandaloneHandler; + XML_ExternalEntityRefHandler m_externalEntityRefHandler; + void *m_externalEntityRefHandlerArg; + XML_UnknownEncodingHandler m_unknownEncodingHandler; + XML_ElementDeclHandler m_elementDeclHandler; + XML_AttlistDeclHandler m_attlistDeclHandler; + XML_EntityDeclHandler m_entityDeclHandler; + XML_XmlDeclHandler m_xmlDeclHandler; + const ENCODING *m_encoding; + INIT_ENCODING m_initEncoding; + const ENCODING *m_internalEncoding; + const XML_Char *m_protocolEncodingName; + int m_ns; + int m_ns_triplets; + void *m_unknownEncodingMem; + void *m_unknownEncodingData; + void *m_unknownEncodingHandlerData; + void (*m_unknownEncodingRelease)(void *); + PROLOG_STATE m_prologState; + Processor *m_processor; + enum XML_Error m_errorCode; + const char *m_eventPtr; + const char *m_eventEndPtr; + const char *m_positionPtr; + OPEN_INTERNAL_ENTITY *m_openInternalEntities; + int m_defaultExpandInternalEntities; + int m_tagLevel; + ENTITY *m_declEntity; + const XML_Char *m_doctypeName; + const XML_Char *m_doctypeSysid; + const XML_Char *m_doctypePubid; + const XML_Char *m_declAttributeType; + const XML_Char *m_declNotationName; + const XML_Char *m_declNotationPublicId; + ELEMENT_TYPE *m_declElementType; + ATTRIBUTE_ID *m_declAttributeId; + char m_declAttributeIsCdata; + char m_declAttributeIsId; + DTD m_dtd; + const XML_Char *m_curBase; + TAG *m_tagStack; + TAG *m_freeTagList; + BINDING *m_inheritedBindings; + BINDING *m_freeBindingList; + int m_attsSize; + int m_nSpecifiedAtts; + int m_idAttIndex; + ATTRIBUTE *m_atts; + POSITION m_position; + STRING_POOL m_tempPool; + STRING_POOL m_temp2Pool; + char *m_groupConnector; + unsigned m_groupSize; + int m_hadExternalDoctype; + XML_Char m_namespaceSeparator; +#ifdef XML_DTD + enum XML_ParamEntityParsing m_paramEntityParsing; + XML_Parser m_parentParser; +#endif +} Parser; + +#define MALLOC(s) (((Parser *)parser)->m_mem.malloc_fcn((s))) +#define REALLOC(p,s) (((Parser *)parser)->m_mem.realloc_fcn((p),(s))) +#define FREE(p) (((Parser *)parser)->m_mem.free_fcn((p))) + +#define userData (((Parser *)parser)->m_userData) +#define handlerArg (((Parser *)parser)->m_handlerArg) +#define startElementHandler (((Parser *)parser)->m_startElementHandler) +#define endElementHandler (((Parser *)parser)->m_endElementHandler) +#define characterDataHandler (((Parser *)parser)->m_characterDataHandler) +#define processingInstructionHandler (((Parser *)parser)->m_processingInstructionHandler) +#define commentHandler (((Parser *)parser)->m_commentHandler) +#define startCdataSectionHandler (((Parser *)parser)->m_startCdataSectionHandler) +#define endCdataSectionHandler (((Parser *)parser)->m_endCdataSectionHandler) +#define defaultHandler (((Parser *)parser)->m_defaultHandler) +#define startDoctypeDeclHandler (((Parser *)parser)->m_startDoctypeDeclHandler) +#define endDoctypeDeclHandler (((Parser *)parser)->m_endDoctypeDeclHandler) +#define unparsedEntityDeclHandler (((Parser *)parser)->m_unparsedEntityDeclHandler) +#define notationDeclHandler (((Parser *)parser)->m_notationDeclHandler) +#define startNamespaceDeclHandler (((Parser *)parser)->m_startNamespaceDeclHandler) +#define endNamespaceDeclHandler (((Parser *)parser)->m_endNamespaceDeclHandler) +#define notStandaloneHandler (((Parser *)parser)->m_notStandaloneHandler) +#define externalEntityRefHandler (((Parser *)parser)->m_externalEntityRefHandler) +#define externalEntityRefHandlerArg (((Parser *)parser)->m_externalEntityRefHandlerArg) +#define internalEntityRefHandler (((Parser *)parser)->m_internalEntityRefHandler) +#define unknownEncodingHandler (((Parser *)parser)->m_unknownEncodingHandler) +#define elementDeclHandler (((Parser *)parser)->m_elementDeclHandler) +#define attlistDeclHandler (((Parser *)parser)->m_attlistDeclHandler) +#define entityDeclHandler (((Parser *)parser)->m_entityDeclHandler) +#define xmlDeclHandler (((Parser *)parser)->m_xmlDeclHandler) +#define encoding (((Parser *)parser)->m_encoding) +#define initEncoding (((Parser *)parser)->m_initEncoding) +#define internalEncoding (((Parser *)parser)->m_internalEncoding) +#define unknownEncodingMem (((Parser *)parser)->m_unknownEncodingMem) +#define unknownEncodingData (((Parser *)parser)->m_unknownEncodingData) +#define unknownEncodingHandlerData \ + (((Parser *)parser)->m_unknownEncodingHandlerData) +#define unknownEncodingRelease (((Parser *)parser)->m_unknownEncodingRelease) +#define protocolEncodingName (((Parser *)parser)->m_protocolEncodingName) +#define ns (((Parser *)parser)->m_ns) +#define ns_triplets (((Parser *)parser)->m_ns_triplets) +#define prologState (((Parser *)parser)->m_prologState) +#define processor (((Parser *)parser)->m_processor) +#define errorCode (((Parser *)parser)->m_errorCode) +#define eventPtr (((Parser *)parser)->m_eventPtr) +#define eventEndPtr (((Parser *)parser)->m_eventEndPtr) +#define positionPtr (((Parser *)parser)->m_positionPtr) +#define position (((Parser *)parser)->m_position) +#define openInternalEntities (((Parser *)parser)->m_openInternalEntities) +#define defaultExpandInternalEntities (((Parser *)parser)->m_defaultExpandInternalEntities) +#define tagLevel (((Parser *)parser)->m_tagLevel) +#define buffer (((Parser *)parser)->m_buffer) +#define bufferPtr (((Parser *)parser)->m_bufferPtr) +#define bufferEnd (((Parser *)parser)->m_bufferEnd) +#define parseEndByteIndex (((Parser *)parser)->m_parseEndByteIndex) +#define parseEndPtr (((Parser *)parser)->m_parseEndPtr) +#define bufferLim (((Parser *)parser)->m_bufferLim) +#define dataBuf (((Parser *)parser)->m_dataBuf) +#define dataBufEnd (((Parser *)parser)->m_dataBufEnd) +#define dtd (((Parser *)parser)->m_dtd) +#define curBase (((Parser *)parser)->m_curBase) +#define declEntity (((Parser *)parser)->m_declEntity) +#define doctypeName (((Parser *)parser)->m_doctypeName) +#define doctypeSysid (((Parser *)parser)->m_doctypeSysid) +#define doctypePubid (((Parser *)parser)->m_doctypePubid) +#define declAttributeType (((Parser *)parser)->m_declAttributeType) +#define declNotationName (((Parser *)parser)->m_declNotationName) +#define declNotationPublicId (((Parser *)parser)->m_declNotationPublicId) +#define declElementType (((Parser *)parser)->m_declElementType) +#define declAttributeId (((Parser *)parser)->m_declAttributeId) +#define declAttributeIsCdata (((Parser *)parser)->m_declAttributeIsCdata) +#define declAttributeIsId (((Parser *)parser)->m_declAttributeIsId) +#define freeTagList (((Parser *)parser)->m_freeTagList) +#define freeBindingList (((Parser *)parser)->m_freeBindingList) +#define inheritedBindings (((Parser *)parser)->m_inheritedBindings) +#define tagStack (((Parser *)parser)->m_tagStack) +#define atts (((Parser *)parser)->m_atts) +#define attsSize (((Parser *)parser)->m_attsSize) +#define nSpecifiedAtts (((Parser *)parser)->m_nSpecifiedAtts) +#define idAttIndex (((Parser *)parser)->m_idAttIndex) +#define tempPool (((Parser *)parser)->m_tempPool) +#define temp2Pool (((Parser *)parser)->m_temp2Pool) +#define groupConnector (((Parser *)parser)->m_groupConnector) +#define groupSize (((Parser *)parser)->m_groupSize) +#define hadExternalDoctype (((Parser *)parser)->m_hadExternalDoctype) +#define namespaceSeparator (((Parser *)parser)->m_namespaceSeparator) +#ifdef XML_DTD +#define parentParser (((Parser *)parser)->m_parentParser) +#define paramEntityParsing (((Parser *)parser)->m_paramEntityParsing) +#endif /* XML_DTD */ + +#ifdef COMPILED_FROM_DSP +BOOL WINAPI DllMain(HINSTANCE h, DWORD r, LPVOID p) { + return TRUE; +} +#endif /* def COMPILED_FROM_DSP */ + +#ifdef _MSC_VER +#ifdef _DEBUG +Parser *asParser(XML_Parser parser) +{ + return parser; +} +#endif +#endif + +XML_Parser XML_ParserCreate(const XML_Char *encodingName) +{ + return XML_ParserCreate_MM(encodingName, NULL, NULL); +} + +XML_Parser XML_ParserCreateNS(const XML_Char *encodingName, XML_Char nsSep) +{ + XML_Char tmp[2]; + *tmp = nsSep; + return XML_ParserCreate_MM(encodingName, NULL, tmp); +} + +XML_Parser +XML_ParserCreate_MM(const XML_Char *encodingName, + const XML_Memory_Handling_Suite *memsuite, + const XML_Char *nameSep) { + + XML_Parser parser; + static + const XML_Char implicitContext[] = { + XML_T('x'), XML_T('m'), XML_T('l'), XML_T('='), + XML_T('h'), XML_T('t'), XML_T('t'), XML_T('p'), XML_T(':'), + XML_T('/'), XML_T('/'), XML_T('w'), XML_T('w'), XML_T('w'), + XML_T('.'), XML_T('w'), XML_T('3'), + XML_T('.'), XML_T('o'), XML_T('r'), XML_T('g'), + XML_T('/'), XML_T('X'), XML_T('M'), XML_T('L'), + XML_T('/'), XML_T('1'), XML_T('9'), XML_T('9'), XML_T('8'), + XML_T('/'), XML_T('n'), XML_T('a'), XML_T('m'), XML_T('e'), + XML_T('s'), XML_T('p'), XML_T('a'), XML_T('c'), XML_T('e'), + XML_T('\0') + }; + + + if (memsuite) { + XML_Memory_Handling_Suite *mtemp; + parser = memsuite->malloc_fcn(sizeof(Parser)); + mtemp = &(((Parser *) parser)->m_mem); + mtemp->malloc_fcn = memsuite->malloc_fcn; + mtemp->realloc_fcn = memsuite->realloc_fcn; + mtemp->free_fcn = memsuite->free_fcn; + } + else { + XML_Memory_Handling_Suite *mtemp; + parser = malloc(sizeof(Parser)); + mtemp = &(((Parser *) parser)->m_mem); + mtemp->malloc_fcn = malloc; + mtemp->realloc_fcn = realloc; + mtemp->free_fcn = free; + } + + if (!parser) + return parser; + processor = prologInitProcessor; + XmlPrologStateInit(&prologState); + userData = 0; + handlerArg = 0; + startElementHandler = 0; + endElementHandler = 0; + characterDataHandler = 0; + processingInstructionHandler = 0; + commentHandler = 0; + startCdataSectionHandler = 0; + endCdataSectionHandler = 0; + defaultHandler = 0; + startDoctypeDeclHandler = 0; + endDoctypeDeclHandler = 0; + unparsedEntityDeclHandler = 0; + notationDeclHandler = 0; + startNamespaceDeclHandler = 0; + endNamespaceDeclHandler = 0; + notStandaloneHandler = 0; + externalEntityRefHandler = 0; + externalEntityRefHandlerArg = parser; + unknownEncodingHandler = 0; + elementDeclHandler = 0; + attlistDeclHandler = 0; + entityDeclHandler = 0; + xmlDeclHandler = 0; + buffer = 0; + bufferPtr = 0; + bufferEnd = 0; + parseEndByteIndex = 0; + parseEndPtr = 0; + bufferLim = 0; + declElementType = 0; + declAttributeId = 0; + declEntity = 0; + doctypeName = 0; + doctypeSysid = 0; + doctypePubid = 0; + declAttributeType = 0; + declNotationName = 0; + declNotationPublicId = 0; + memset(&position, 0, sizeof(POSITION)); + errorCode = XML_ERROR_NONE; + eventPtr = 0; + eventEndPtr = 0; + positionPtr = 0; + openInternalEntities = 0; + tagLevel = 0; + tagStack = 0; + freeTagList = 0; + freeBindingList = 0; + inheritedBindings = 0; + attsSize = INIT_ATTS_SIZE; + atts = MALLOC(attsSize * sizeof(ATTRIBUTE)); + nSpecifiedAtts = 0; + dataBuf = MALLOC(INIT_DATA_BUF_SIZE * sizeof(XML_Char)); + groupSize = 0; + groupConnector = 0; + hadExternalDoctype = 0; + unknownEncodingMem = 0; + unknownEncodingRelease = 0; + unknownEncodingData = 0; + unknownEncodingHandlerData = 0; + namespaceSeparator = '!'; +#ifdef XML_DTD + parentParser = 0; + paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER; +#endif + ns = 0; + ns_triplets = 0; + poolInit(&tempPool, &(((Parser *) parser)->m_mem)); + poolInit(&temp2Pool, &(((Parser *) parser)->m_mem)); + protocolEncodingName = encodingName ? poolCopyString(&tempPool, encodingName) : 0; + curBase = 0; + if (!dtdInit(&dtd, parser) || !atts || !dataBuf + || (encodingName && !protocolEncodingName)) { + XML_ParserFree(parser); + return 0; + } + dataBufEnd = dataBuf + INIT_DATA_BUF_SIZE; + + if (nameSep) { + XmlInitEncodingNS(&initEncoding, &encoding, 0); + ns = 1; + internalEncoding = XmlGetInternalEncodingNS(); + namespaceSeparator = *nameSep; + + if (! setContext(parser, implicitContext)) { + XML_ParserFree(parser); + return 0; + } + } + else { + XmlInitEncoding(&initEncoding, &encoding, 0); + internalEncoding = XmlGetInternalEncoding(); + } + + return parser; +} /* End XML_ParserCreate_MM */ + +int XML_SetEncoding(XML_Parser parser, const XML_Char *encodingName) +{ + if (!encodingName) + protocolEncodingName = 0; + else { + protocolEncodingName = poolCopyString(&tempPool, encodingName); + if (!protocolEncodingName) + return 0; + } + return 1; +} + +XML_Parser XML_ExternalEntityParserCreate(XML_Parser oldParser, + const XML_Char *context, + const XML_Char *encodingName) +{ + XML_Parser parser = oldParser; + DTD *oldDtd = &dtd; + XML_StartElementHandler oldStartElementHandler = startElementHandler; + XML_EndElementHandler oldEndElementHandler = endElementHandler; + XML_CharacterDataHandler oldCharacterDataHandler = characterDataHandler; + XML_ProcessingInstructionHandler oldProcessingInstructionHandler = processingInstructionHandler; + XML_CommentHandler oldCommentHandler = commentHandler; + XML_StartCdataSectionHandler oldStartCdataSectionHandler = startCdataSectionHandler; + XML_EndCdataSectionHandler oldEndCdataSectionHandler = endCdataSectionHandler; + XML_DefaultHandler oldDefaultHandler = defaultHandler; + XML_UnparsedEntityDeclHandler oldUnparsedEntityDeclHandler = unparsedEntityDeclHandler; + XML_NotationDeclHandler oldNotationDeclHandler = notationDeclHandler; + XML_StartNamespaceDeclHandler oldStartNamespaceDeclHandler = startNamespaceDeclHandler; + XML_EndNamespaceDeclHandler oldEndNamespaceDeclHandler = endNamespaceDeclHandler; + XML_NotStandaloneHandler oldNotStandaloneHandler = notStandaloneHandler; + XML_ExternalEntityRefHandler oldExternalEntityRefHandler = externalEntityRefHandler; + XML_UnknownEncodingHandler oldUnknownEncodingHandler = unknownEncodingHandler; + XML_ElementDeclHandler oldElementDeclHandler = elementDeclHandler; + XML_AttlistDeclHandler oldAttlistDeclHandler = attlistDeclHandler; + XML_EntityDeclHandler oldEntityDeclHandler = entityDeclHandler; + XML_XmlDeclHandler oldXmlDeclHandler = xmlDeclHandler; + ELEMENT_TYPE * oldDeclElementType = declElementType; + + void *oldUserData = userData; + void *oldHandlerArg = handlerArg; + int oldDefaultExpandInternalEntities = defaultExpandInternalEntities; + void *oldExternalEntityRefHandlerArg = externalEntityRefHandlerArg; +#ifdef XML_DTD + enum XML_ParamEntityParsing oldParamEntityParsing = paramEntityParsing; +#endif + int oldns_triplets = ns_triplets; + + if (ns) { + XML_Char tmp[2]; + + *tmp = namespaceSeparator; + parser = XML_ParserCreate_MM(encodingName, &((Parser *)parser)->m_mem, + tmp); + } + else { + parser = XML_ParserCreate_MM(encodingName, &((Parser *)parser)->m_mem, + NULL); + } + + if (!parser) + return 0; + + startElementHandler = oldStartElementHandler; + endElementHandler = oldEndElementHandler; + characterDataHandler = oldCharacterDataHandler; + processingInstructionHandler = oldProcessingInstructionHandler; + commentHandler = oldCommentHandler; + startCdataSectionHandler = oldStartCdataSectionHandler; + endCdataSectionHandler = oldEndCdataSectionHandler; + defaultHandler = oldDefaultHandler; + unparsedEntityDeclHandler = oldUnparsedEntityDeclHandler; + notationDeclHandler = oldNotationDeclHandler; + startNamespaceDeclHandler = oldStartNamespaceDeclHandler; + endNamespaceDeclHandler = oldEndNamespaceDeclHandler; + notStandaloneHandler = oldNotStandaloneHandler; + externalEntityRefHandler = oldExternalEntityRefHandler; + unknownEncodingHandler = oldUnknownEncodingHandler; + elementDeclHandler = oldElementDeclHandler; + attlistDeclHandler = oldAttlistDeclHandler; + entityDeclHandler = oldEntityDeclHandler; + xmlDeclHandler = oldXmlDeclHandler; + declElementType = oldDeclElementType; + userData = oldUserData; + if (oldUserData == oldHandlerArg) + handlerArg = userData; + else + handlerArg = parser; + if (oldExternalEntityRefHandlerArg != oldParser) + externalEntityRefHandlerArg = oldExternalEntityRefHandlerArg; + defaultExpandInternalEntities = oldDefaultExpandInternalEntities; + ns_triplets = oldns_triplets; +#ifdef XML_DTD + paramEntityParsing = oldParamEntityParsing; + if (context) { +#endif /* XML_DTD */ + if (!dtdCopy(&dtd, oldDtd, parser) || !setContext(parser, context)) { + XML_ParserFree(parser); + return 0; + } + processor = externalEntityInitProcessor; +#ifdef XML_DTD + } + else { + dtdSwap(&dtd, oldDtd); + parentParser = oldParser; + XmlPrologStateInitExternalEntity(&prologState); + dtd.complete = 1; + hadExternalDoctype = 1; + } +#endif /* XML_DTD */ + return parser; +} + +static +void destroyBindings(BINDING *bindings, XML_Parser parser) +{ + for (;;) { + BINDING *b = bindings; + if (!b) + break; + bindings = b->nextTagBinding; + FREE(b->uri); + FREE(b); + } +} + +void XML_ParserFree(XML_Parser parser) +{ + for (;;) { + TAG *p; + if (tagStack == 0) { + if (freeTagList == 0) + break; + tagStack = freeTagList; + freeTagList = 0; + } + p = tagStack; + tagStack = tagStack->parent; + FREE(p->buf); + destroyBindings(p->bindings, parser); + FREE(p); + } + destroyBindings(freeBindingList, parser); + destroyBindings(inheritedBindings, parser); + poolDestroy(&tempPool); + poolDestroy(&temp2Pool); +#ifdef XML_DTD + if (parentParser) { + if (hadExternalDoctype) + dtd.complete = 0; + dtdSwap(&dtd, &((Parser *)parentParser)->m_dtd); + } +#endif /* XML_DTD */ + dtdDestroy(&dtd, parser); + FREE((void *)atts); + if (groupConnector) + FREE(groupConnector); + if (buffer) + FREE(buffer); + FREE(dataBuf); + if (unknownEncodingMem) + FREE(unknownEncodingMem); + if (unknownEncodingRelease) + unknownEncodingRelease(unknownEncodingData); + FREE(parser); +} + +void XML_UseParserAsHandlerArg(XML_Parser parser) +{ + handlerArg = parser; +} + +void +XML_SetReturnNSTriplet(XML_Parser parser, int do_nst) { + ns_triplets = do_nst; +} + +void XML_SetUserData(XML_Parser parser, void *p) +{ + if (handlerArg == userData) + handlerArg = userData = p; + else + userData = p; +} + +int XML_SetBase(XML_Parser parser, const XML_Char *p) +{ + if (p) { + p = poolCopyString(&dtd.pool, p); + if (!p) + return 0; + curBase = p; + } + else + curBase = 0; + return 1; +} + +const XML_Char *XML_GetBase(XML_Parser parser) +{ + return curBase; +} + +int XML_GetSpecifiedAttributeCount(XML_Parser parser) +{ + return nSpecifiedAtts; +} + +int XML_GetIdAttributeIndex(XML_Parser parser) +{ + return idAttIndex; +} + +void XML_SetElementHandler(XML_Parser parser, + XML_StartElementHandler start, + XML_EndElementHandler end) +{ + startElementHandler = start; + endElementHandler = end; +} + +void XML_SetStartElementHandler(XML_Parser parser, + XML_StartElementHandler start) { + startElementHandler = start; +} + +void XML_SetEndElementHandler(XML_Parser parser, + XML_EndElementHandler end) { + endElementHandler = end; +} + +void XML_SetCharacterDataHandler(XML_Parser parser, + XML_CharacterDataHandler handler) +{ + characterDataHandler = handler; +} + +void XML_SetProcessingInstructionHandler(XML_Parser parser, + XML_ProcessingInstructionHandler handler) +{ + processingInstructionHandler = handler; +} + +void XML_SetCommentHandler(XML_Parser parser, + XML_CommentHandler handler) +{ + commentHandler = handler; +} + +void XML_SetCdataSectionHandler(XML_Parser parser, + XML_StartCdataSectionHandler start, + XML_EndCdataSectionHandler end) +{ + startCdataSectionHandler = start; + endCdataSectionHandler = end; +} + +void XML_SetStartCdataSectionHandler(XML_Parser parser, + XML_StartCdataSectionHandler start) { + startCdataSectionHandler = start; +} + +void XML_SetEndCdataSectionHandler(XML_Parser parser, + XML_EndCdataSectionHandler end) { + endCdataSectionHandler = end; +} + +void XML_SetDefaultHandler(XML_Parser parser, + XML_DefaultHandler handler) +{ + defaultHandler = handler; + defaultExpandInternalEntities = 0; +} + +void XML_SetDefaultHandlerExpand(XML_Parser parser, + XML_DefaultHandler handler) +{ + defaultHandler = handler; + defaultExpandInternalEntities = 1; +} + +void XML_SetDoctypeDeclHandler(XML_Parser parser, + XML_StartDoctypeDeclHandler start, + XML_EndDoctypeDeclHandler end) +{ + startDoctypeDeclHandler = start; + endDoctypeDeclHandler = end; +} + +void XML_SetStartDoctypeDeclHandler(XML_Parser parser, + XML_StartDoctypeDeclHandler start) { + startDoctypeDeclHandler = start; +} + +void XML_SetEndDoctypeDeclHandler(XML_Parser parser, + XML_EndDoctypeDeclHandler end) { + endDoctypeDeclHandler = end; +} + +void XML_SetUnparsedEntityDeclHandler(XML_Parser parser, + XML_UnparsedEntityDeclHandler handler) +{ + unparsedEntityDeclHandler = handler; +} + +void XML_SetNotationDeclHandler(XML_Parser parser, + XML_NotationDeclHandler handler) +{ + notationDeclHandler = handler; +} + +void XML_SetNamespaceDeclHandler(XML_Parser parser, + XML_StartNamespaceDeclHandler start, + XML_EndNamespaceDeclHandler end) +{ + startNamespaceDeclHandler = start; + endNamespaceDeclHandler = end; +} + +void XML_SetStartNamespaceDeclHandler(XML_Parser parser, + XML_StartNamespaceDeclHandler start) { + startNamespaceDeclHandler = start; +} + +void XML_SetEndNamespaceDeclHandler(XML_Parser parser, + XML_EndNamespaceDeclHandler end) { + endNamespaceDeclHandler = end; +} + + +void XML_SetNotStandaloneHandler(XML_Parser parser, + XML_NotStandaloneHandler handler) +{ + notStandaloneHandler = handler; +} + +void XML_SetExternalEntityRefHandler(XML_Parser parser, + XML_ExternalEntityRefHandler handler) +{ + externalEntityRefHandler = handler; +} + +void XML_SetExternalEntityRefHandlerArg(XML_Parser parser, void *arg) +{ + if (arg) + externalEntityRefHandlerArg = arg; + else + externalEntityRefHandlerArg = parser; +} + +void XML_SetUnknownEncodingHandler(XML_Parser parser, + XML_UnknownEncodingHandler handler, + void *data) +{ + unknownEncodingHandler = handler; + unknownEncodingHandlerData = data; +} + +void XML_SetElementDeclHandler(XML_Parser parser, + XML_ElementDeclHandler eldecl) +{ + elementDeclHandler = eldecl; +} + +void XML_SetAttlistDeclHandler(XML_Parser parser, + XML_AttlistDeclHandler attdecl) +{ + attlistDeclHandler = attdecl; +} + +void XML_SetEntityDeclHandler(XML_Parser parser, + XML_EntityDeclHandler handler) +{ + entityDeclHandler = handler; +} + +void XML_SetXmlDeclHandler(XML_Parser parser, + XML_XmlDeclHandler handler) { + xmlDeclHandler = handler; +} + +int XML_SetParamEntityParsing(XML_Parser parser, + enum XML_ParamEntityParsing parsing) +{ +#ifdef XML_DTD + paramEntityParsing = parsing; + return 1; +#else + return parsing == XML_PARAM_ENTITY_PARSING_NEVER; +#endif +} + +int XML_Parse(XML_Parser parser, const char *s, int len, int isFinal) +{ + if (len == 0) { + if (!isFinal) + return 1; + positionPtr = bufferPtr; + errorCode = processor(parser, bufferPtr, parseEndPtr = bufferEnd, 0); + if (errorCode == XML_ERROR_NONE) + return 1; + eventEndPtr = eventPtr; + processor = errorProcessor; + return 0; + } +#ifndef XML_CONTEXT_BYTES + else if (bufferPtr == bufferEnd) { + const char *end; + int nLeftOver; + parseEndByteIndex += len; + positionPtr = s; + if (isFinal) { + errorCode = processor(parser, s, parseEndPtr = s + len, 0); + if (errorCode == XML_ERROR_NONE) + return 1; + eventEndPtr = eventPtr; + processor = errorProcessor; + return 0; + } + errorCode = processor(parser, s, parseEndPtr = s + len, &end); + if (errorCode != XML_ERROR_NONE) { + eventEndPtr = eventPtr; + processor = errorProcessor; + return 0; + } + XmlUpdatePosition(encoding, positionPtr, end, &position); + nLeftOver = s + len - end; + if (nLeftOver) { + if (buffer == 0 || nLeftOver > bufferLim - buffer) { + /* FIXME avoid integer overflow */ + buffer = buffer == 0 ? MALLOC(len * 2) : REALLOC(buffer, len * 2); + /* FIXME storage leak if realloc fails */ + if (!buffer) { + errorCode = XML_ERROR_NO_MEMORY; + eventPtr = eventEndPtr = 0; + processor = errorProcessor; + return 0; + } + bufferLim = buffer + len * 2; + } + memcpy(buffer, end, nLeftOver); + bufferPtr = buffer; + bufferEnd = buffer + nLeftOver; + } + return 1; + } +#endif /* not defined XML_CONTEXT_BYTES */ + else { + memcpy(XML_GetBuffer(parser, len), s, len); + return XML_ParseBuffer(parser, len, isFinal); + } +} + +int XML_ParseBuffer(XML_Parser parser, int len, int isFinal) +{ + const char *start = bufferPtr; + positionPtr = start; + bufferEnd += len; + parseEndByteIndex += len; + errorCode = processor(parser, start, parseEndPtr = bufferEnd, + isFinal ? (const char **)0 : &bufferPtr); + if (errorCode == XML_ERROR_NONE) { + if (!isFinal) + XmlUpdatePosition(encoding, positionPtr, bufferPtr, &position); + return 1; + } + else { + eventEndPtr = eventPtr; + processor = errorProcessor; + return 0; + } +} + +void *XML_GetBuffer(XML_Parser parser, int len) +{ + if (len > bufferLim - bufferEnd) { + /* FIXME avoid integer overflow */ + int neededSize = len + (bufferEnd - bufferPtr); +#ifdef XML_CONTEXT_BYTES + int keep = bufferPtr - buffer; + + if (keep > XML_CONTEXT_BYTES) + keep = XML_CONTEXT_BYTES; + neededSize += keep; +#endif /* defined XML_CONTEXT_BYTES */ + if (neededSize <= bufferLim - buffer) { +#ifdef XML_CONTEXT_BYTES + if (keep < bufferPtr - buffer) { + int offset = (bufferPtr - buffer) - keep; + memmove(buffer, &buffer[offset], bufferEnd - bufferPtr + keep); + bufferEnd -= offset; + bufferPtr -= offset; + } +#else + memmove(buffer, bufferPtr, bufferEnd - bufferPtr); + bufferEnd = buffer + (bufferEnd - bufferPtr); + bufferPtr = buffer; +#endif /* not defined XML_CONTEXT_BYTES */ + } + else { + char *newBuf; + int bufferSize = bufferLim - bufferPtr; + if (bufferSize == 0) + bufferSize = INIT_BUFFER_SIZE; + do { + bufferSize *= 2; + } while (bufferSize < neededSize); + newBuf = MALLOC(bufferSize); + if (newBuf == 0) { + errorCode = XML_ERROR_NO_MEMORY; + return 0; + } + bufferLim = newBuf + bufferSize; +#ifdef XML_CONTEXT_BYTES + if (bufferPtr) { + int keep = bufferPtr - buffer; + if (keep > XML_CONTEXT_BYTES) + keep = XML_CONTEXT_BYTES; + memcpy(newBuf, &bufferPtr[-keep], bufferEnd - bufferPtr + keep); + FREE(buffer); + buffer = newBuf; + bufferEnd = buffer + (bufferEnd - bufferPtr) + keep; + bufferPtr = buffer + keep; + } + else { + bufferEnd = newBuf + (bufferEnd - bufferPtr); + bufferPtr = buffer = newBuf; + } +#else + if (bufferPtr) { + memcpy(newBuf, bufferPtr, bufferEnd - bufferPtr); + FREE(buffer); + } + bufferEnd = newBuf + (bufferEnd - bufferPtr); + bufferPtr = buffer = newBuf; +#endif /* not defined XML_CONTEXT_BYTES */ + } + } + return bufferEnd; +} + +enum XML_Error XML_GetErrorCode(XML_Parser parser) +{ + return errorCode; +} + +long XML_GetCurrentByteIndex(XML_Parser parser) +{ + if (eventPtr) + return parseEndByteIndex - (parseEndPtr - eventPtr); + return -1; +} + +int XML_GetCurrentByteCount(XML_Parser parser) +{ + if (eventEndPtr && eventPtr) + return eventEndPtr - eventPtr; + return 0; +} + +const char * XML_GetInputContext(XML_Parser parser, int *offset, int *size) +{ +#ifdef XML_CONTEXT_BYTES + if (eventPtr && buffer) { + *offset = eventPtr - buffer; + *size = bufferEnd - buffer; + return buffer; + } +#endif /* defined XML_CONTEXT_BYTES */ + return (char *) 0; +} + +int XML_GetCurrentLineNumber(XML_Parser parser) +{ + if (eventPtr) { + XmlUpdatePosition(encoding, positionPtr, eventPtr, &position); + positionPtr = eventPtr; + } + return position.lineNumber + 1; +} + +int XML_GetCurrentColumnNumber(XML_Parser parser) +{ + if (eventPtr) { + XmlUpdatePosition(encoding, positionPtr, eventPtr, &position); + positionPtr = eventPtr; + } + return position.columnNumber; +} + +void XML_DefaultCurrent(XML_Parser parser) +{ + if (defaultHandler) { + if (openInternalEntities) + reportDefault(parser, + internalEncoding, + openInternalEntities->internalEventPtr, + openInternalEntities->internalEventEndPtr); + else + reportDefault(parser, encoding, eventPtr, eventEndPtr); + } +} + +const XML_LChar *XML_ErrorString(int code) +{ + static const XML_LChar *message[] = { + 0, + XML_T("out of memory"), + XML_T("syntax error"), + XML_T("no element found"), + XML_T("not well-formed (invalid token)"), + XML_T("unclosed token"), + XML_T("unclosed token"), + XML_T("mismatched tag"), + XML_T("duplicate attribute"), + XML_T("junk after document element"), + XML_T("illegal parameter entity reference"), + XML_T("undefined entity"), + XML_T("recursive entity reference"), + XML_T("asynchronous entity"), + XML_T("reference to invalid character number"), + XML_T("reference to binary entity"), + XML_T("reference to external entity in attribute"), + XML_T("xml processing instruction not at start of external entity"), + XML_T("unknown encoding"), + XML_T("encoding specified in XML declaration is incorrect"), + XML_T("unclosed CDATA section"), + XML_T("error in processing external entity reference"), + XML_T("document is not standalone"), + XML_T("unexpected parser state - please send a bug report") + }; + if (code > 0 && code < (int)(sizeof(message)/sizeof(message[0]))) + return message[code]; + return 0; +} + +const XML_LChar * +XML_ExpatVersion(void) { + return VERSION; +} + +XML_Expat_Version +XML_ExpatVersionInfo(void) { + XML_Expat_Version version; + + version.major = XML_MAJOR_VERSION; + version.minor = XML_MINOR_VERSION; + version.micro = XML_MICRO_VERSION; + + return version; +} + +static +enum XML_Error contentProcessor(XML_Parser parser, + const char *start, + const char *end, + const char **endPtr) +{ + return doContent(parser, 0, encoding, start, end, endPtr); +} + +static +enum XML_Error externalEntityInitProcessor(XML_Parser parser, + const char *start, + const char *end, + const char **endPtr) +{ + enum XML_Error result = initializeEncoding(parser); + if (result != XML_ERROR_NONE) + return result; + processor = externalEntityInitProcessor2; + return externalEntityInitProcessor2(parser, start, end, endPtr); +} + +static +enum XML_Error externalEntityInitProcessor2(XML_Parser parser, + const char *start, + const char *end, + const char **endPtr) +{ + const char *next; + int tok = XmlContentTok(encoding, start, end, &next); + switch (tok) { + case XML_TOK_BOM: + start = next; + break; + case XML_TOK_PARTIAL: + if (endPtr) { + *endPtr = start; + return XML_ERROR_NONE; + } + eventPtr = start; + return XML_ERROR_UNCLOSED_TOKEN; + case XML_TOK_PARTIAL_CHAR: + if (endPtr) { + *endPtr = start; + return XML_ERROR_NONE; + } + eventPtr = start; + return XML_ERROR_PARTIAL_CHAR; + } + processor = externalEntityInitProcessor3; + return externalEntityInitProcessor3(parser, start, end, endPtr); +} + +static +enum XML_Error externalEntityInitProcessor3(XML_Parser parser, + const char *start, + const char *end, + const char **endPtr) +{ + const char *next; + int tok = XmlContentTok(encoding, start, end, &next); + switch (tok) { + case XML_TOK_XML_DECL: + { + enum XML_Error result = processXmlDecl(parser, 1, start, next); + if (result != XML_ERROR_NONE) + return result; + start = next; + } + break; + case XML_TOK_PARTIAL: + if (endPtr) { + *endPtr = start; + return XML_ERROR_NONE; + } + eventPtr = start; + return XML_ERROR_UNCLOSED_TOKEN; + case XML_TOK_PARTIAL_CHAR: + if (endPtr) { + *endPtr = start; + return XML_ERROR_NONE; + } + eventPtr = start; + return XML_ERROR_PARTIAL_CHAR; + } + processor = externalEntityContentProcessor; + tagLevel = 1; + return doContent(parser, 1, encoding, start, end, endPtr); +} + +static +enum XML_Error externalEntityContentProcessor(XML_Parser parser, + const char *start, + const char *end, + const char **endPtr) +{ + return doContent(parser, 1, encoding, start, end, endPtr); +} + +static enum XML_Error +doContent(XML_Parser parser, + int startTagLevel, + const ENCODING *enc, + const char *s, + const char *end, + const char **nextPtr) +{ + const char **eventPP; + const char **eventEndPP; + if (enc == encoding) { + eventPP = &eventPtr; + eventEndPP = &eventEndPtr; + } + else { + eventPP = &(openInternalEntities->internalEventPtr); + eventEndPP = &(openInternalEntities->internalEventEndPtr); + } + *eventPP = s; + for (;;) { + const char *next = s; /* XmlContentTok doesn't always set the last arg */ + int tok = XmlContentTok(enc, s, end, &next); + *eventEndPP = next; + switch (tok) { + case XML_TOK_TRAILING_CR: + if (nextPtr) { + *nextPtr = s; + return XML_ERROR_NONE; + } + *eventEndPP = end; + if (characterDataHandler) { + XML_Char c = 0xA; + characterDataHandler(handlerArg, &c, 1); + } + else if (defaultHandler) + reportDefault(parser, enc, s, end); + if (startTagLevel == 0) + return XML_ERROR_NO_ELEMENTS; + if (tagLevel != startTagLevel) + return XML_ERROR_ASYNC_ENTITY; + return XML_ERROR_NONE; + case XML_TOK_NONE: + if (nextPtr) { + *nextPtr = s; + return XML_ERROR_NONE; + } + if (startTagLevel > 0) { + if (tagLevel != startTagLevel) + return XML_ERROR_ASYNC_ENTITY; + return XML_ERROR_NONE; + } + return XML_ERROR_NO_ELEMENTS; + case XML_TOK_INVALID: + *eventPP = next; + return XML_ERROR_INVALID_TOKEN; + case XML_TOK_PARTIAL: + if (nextPtr) { + *nextPtr = s; + return XML_ERROR_NONE; + } + return XML_ERROR_UNCLOSED_TOKEN; + case XML_TOK_PARTIAL_CHAR: + if (nextPtr) { + *nextPtr = s; + return XML_ERROR_NONE; + } + return XML_ERROR_PARTIAL_CHAR; + case XML_TOK_ENTITY_REF: + { + const XML_Char *name; + ENTITY *entity; + XML_Char ch = XmlPredefinedEntityName(enc, + s + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (ch) { + if (characterDataHandler) + characterDataHandler(handlerArg, &ch, 1); + else if (defaultHandler) + reportDefault(parser, enc, s, next); + break; + } + name = poolStoreString(&dtd.pool, enc, + s + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (!name) + return XML_ERROR_NO_MEMORY; + entity = (ENTITY *)lookup(&dtd.generalEntities, name, 0); + poolDiscard(&dtd.pool); + if (!entity) { + if (dtd.complete || dtd.standalone) + return XML_ERROR_UNDEFINED_ENTITY; + if (defaultHandler) + reportDefault(parser, enc, s, next); + break; + } + if (entity->open) + return XML_ERROR_RECURSIVE_ENTITY_REF; + if (entity->notation) + return XML_ERROR_BINARY_ENTITY_REF; + if (entity) { + if (entity->textPtr) { + enum XML_Error result; + OPEN_INTERNAL_ENTITY openEntity; + if (defaultHandler && !defaultExpandInternalEntities) { + reportDefault(parser, enc, s, next); + break; + } + entity->open = 1; + openEntity.next = openInternalEntities; + openInternalEntities = &openEntity; + openEntity.entity = entity; + openEntity.internalEventPtr = 0; + openEntity.internalEventEndPtr = 0; + result = doContent(parser, + tagLevel, + internalEncoding, + (char *)entity->textPtr, + (char *)(entity->textPtr + entity->textLen), + 0); + entity->open = 0; + openInternalEntities = openEntity.next; + if (result) + return result; + } + else if (externalEntityRefHandler) { + const XML_Char *context; + entity->open = 1; + context = getContext(parser); + entity->open = 0; + if (!context) + return XML_ERROR_NO_MEMORY; + if (!externalEntityRefHandler(externalEntityRefHandlerArg, + context, + entity->base, + entity->systemId, + entity->publicId)) + return XML_ERROR_EXTERNAL_ENTITY_HANDLING; + poolDiscard(&tempPool); + } + else if (defaultHandler) + reportDefault(parser, enc, s, next); + } + break; + } + case XML_TOK_START_TAG_WITH_ATTS: + if (!startElementHandler) { + enum XML_Error result = storeAtts(parser, enc, s, 0, 0); + if (result) + return result; + } + /* fall through */ + case XML_TOK_START_TAG_NO_ATTS: + { + TAG *tag; + if (freeTagList) { + tag = freeTagList; + freeTagList = freeTagList->parent; + } + else { + tag = MALLOC(sizeof(TAG)); + if (!tag) + return XML_ERROR_NO_MEMORY; + tag->buf = MALLOC(INIT_TAG_BUF_SIZE); + if (!tag->buf) + return XML_ERROR_NO_MEMORY; + tag->bufEnd = tag->buf + INIT_TAG_BUF_SIZE; + } + tag->bindings = 0; + tag->parent = tagStack; + tagStack = tag; + tag->name.localPart = 0; + tag->rawName = s + enc->minBytesPerChar; + tag->rawNameLength = XmlNameLength(enc, tag->rawName); + if (nextPtr) { + /* Need to guarantee that: + tag->buf + ROUND_UP(tag->rawNameLength, sizeof(XML_Char)) <= tag->bufEnd - sizeof(XML_Char) */ + if (tag->rawNameLength + (int)(sizeof(XML_Char) - 1) + (int)sizeof(XML_Char) > tag->bufEnd - tag->buf) { + int bufSize = tag->rawNameLength * 4; + bufSize = ROUND_UP(bufSize, sizeof(XML_Char)); + tag->buf = REALLOC(tag->buf, bufSize); + if (!tag->buf) + return XML_ERROR_NO_MEMORY; + tag->bufEnd = tag->buf + bufSize; + } + memcpy(tag->buf, tag->rawName, tag->rawNameLength); + tag->rawName = tag->buf; + } + ++tagLevel; + if (startElementHandler) { + enum XML_Error result; + XML_Char *toPtr; + for (;;) { + const char *rawNameEnd = tag->rawName + tag->rawNameLength; + const char *fromPtr = tag->rawName; + int bufSize; + if (nextPtr) + toPtr = (XML_Char *)(tag->buf + ROUND_UP(tag->rawNameLength, sizeof(XML_Char))); + else + toPtr = (XML_Char *)tag->buf; + tag->name.str = toPtr; + XmlConvert(enc, + &fromPtr, rawNameEnd, + (ICHAR **)&toPtr, (ICHAR *)tag->bufEnd - 1); + if (fromPtr == rawNameEnd) + break; + bufSize = (tag->bufEnd - tag->buf) << 1; + tag->buf = REALLOC(tag->buf, bufSize); + if (!tag->buf) + return XML_ERROR_NO_MEMORY; + tag->bufEnd = tag->buf + bufSize; + if (nextPtr) + tag->rawName = tag->buf; + } + *toPtr = XML_T('\0'); + result = storeAtts(parser, enc, s, &(tag->name), &(tag->bindings)); + if (result) + return result; + startElementHandler(handlerArg, tag->name.str, (const XML_Char **)atts); + poolClear(&tempPool); + } + else { + tag->name.str = 0; + if (defaultHandler) + reportDefault(parser, enc, s, next); + } + break; + } + case XML_TOK_EMPTY_ELEMENT_WITH_ATTS: + if (!startElementHandler) { + enum XML_Error result = storeAtts(parser, enc, s, 0, 0); + if (result) + return result; + } + /* fall through */ + case XML_TOK_EMPTY_ELEMENT_NO_ATTS: + if (startElementHandler || endElementHandler) { + const char *rawName = s + enc->minBytesPerChar; + enum XML_Error result; + BINDING *bindings = 0; + TAG_NAME name; + name.str = poolStoreString(&tempPool, enc, rawName, + rawName + XmlNameLength(enc, rawName)); + if (!name.str) + return XML_ERROR_NO_MEMORY; + poolFinish(&tempPool); + result = storeAtts(parser, enc, s, &name, &bindings); + if (result) + return result; + poolFinish(&tempPool); + if (startElementHandler) + startElementHandler(handlerArg, name.str, (const XML_Char **)atts); + if (endElementHandler) { + if (startElementHandler) + *eventPP = *eventEndPP; + endElementHandler(handlerArg, name.str); + } + poolClear(&tempPool); + while (bindings) { + BINDING *b = bindings; + if (endNamespaceDeclHandler) + endNamespaceDeclHandler(handlerArg, b->prefix->name); + bindings = bindings->nextTagBinding; + b->nextTagBinding = freeBindingList; + freeBindingList = b; + b->prefix->binding = b->prevPrefixBinding; + } + } + else if (defaultHandler) + reportDefault(parser, enc, s, next); + if (tagLevel == 0) + return epilogProcessor(parser, next, end, nextPtr); + break; + case XML_TOK_END_TAG: + if (tagLevel == startTagLevel) + return XML_ERROR_ASYNC_ENTITY; + else { + int len; + const char *rawName; + TAG *tag = tagStack; + tagStack = tag->parent; + tag->parent = freeTagList; + freeTagList = tag; + rawName = s + enc->minBytesPerChar*2; + len = XmlNameLength(enc, rawName); + if (len != tag->rawNameLength + || memcmp(tag->rawName, rawName, len) != 0) { + *eventPP = rawName; + return XML_ERROR_TAG_MISMATCH; + } + --tagLevel; + if (endElementHandler && tag->name.str) { + if (tag->name.localPart) { + XML_Char *to = (XML_Char *)tag->name.str + tag->name.uriLen; + const XML_Char *from = tag->name.localPart; + while ((*to++ = *from++) != 0) + ; + } + endElementHandler(handlerArg, tag->name.str); + } + else if (defaultHandler) + reportDefault(parser, enc, s, next); + while (tag->bindings) { + BINDING *b = tag->bindings; + if (endNamespaceDeclHandler) + endNamespaceDeclHandler(handlerArg, b->prefix->name); + tag->bindings = tag->bindings->nextTagBinding; + b->nextTagBinding = freeBindingList; + freeBindingList = b; + b->prefix->binding = b->prevPrefixBinding; + } + if (tagLevel == 0) + return epilogProcessor(parser, next, end, nextPtr); + } + break; + case XML_TOK_CHAR_REF: + { + int n = XmlCharRefNumber(enc, s); + if (n < 0) + return XML_ERROR_BAD_CHAR_REF; + if (characterDataHandler) { + XML_Char buf[XML_ENCODE_MAX]; + characterDataHandler(handlerArg, buf, XmlEncode(n, (ICHAR *)buf)); + } + else if (defaultHandler) + reportDefault(parser, enc, s, next); + } + break; + case XML_TOK_XML_DECL: + return XML_ERROR_MISPLACED_XML_PI; + case XML_TOK_DATA_NEWLINE: + if (characterDataHandler) { + XML_Char c = 0xA; + characterDataHandler(handlerArg, &c, 1); + } + else if (defaultHandler) + reportDefault(parser, enc, s, next); + break; + case XML_TOK_CDATA_SECT_OPEN: + { + enum XML_Error result; + if (startCdataSectionHandler) + startCdataSectionHandler(handlerArg); +#if 0 + /* Suppose you doing a transformation on a document that involves + changing only the character data. You set up a defaultHandler + and a characterDataHandler. The defaultHandler simply copies + characters through. The characterDataHandler does the transformation + and writes the characters out escaping them as necessary. This case + will fail to work if we leave out the following two lines (because & + and < inside CDATA sections will be incorrectly escaped). + + However, now we have a start/endCdataSectionHandler, so it seems + easier to let the user deal with this. */ + + else if (characterDataHandler) + characterDataHandler(handlerArg, dataBuf, 0); +#endif + else if (defaultHandler) + reportDefault(parser, enc, s, next); + result = doCdataSection(parser, enc, &next, end, nextPtr); + if (!next) { + processor = cdataSectionProcessor; + return result; + } + } + break; + case XML_TOK_TRAILING_RSQB: + if (nextPtr) { + *nextPtr = s; + return XML_ERROR_NONE; + } + if (characterDataHandler) { + if (MUST_CONVERT(enc, s)) { + ICHAR *dataPtr = (ICHAR *)dataBuf; + XmlConvert(enc, &s, end, &dataPtr, (ICHAR *)dataBufEnd); + characterDataHandler(handlerArg, dataBuf, dataPtr - (ICHAR *)dataBuf); + } + else + characterDataHandler(handlerArg, + (XML_Char *)s, + (XML_Char *)end - (XML_Char *)s); + } + else if (defaultHandler) + reportDefault(parser, enc, s, end); + if (startTagLevel == 0) { + *eventPP = end; + return XML_ERROR_NO_ELEMENTS; + } + if (tagLevel != startTagLevel) { + *eventPP = end; + return XML_ERROR_ASYNC_ENTITY; + } + return XML_ERROR_NONE; + case XML_TOK_DATA_CHARS: + if (characterDataHandler) { + if (MUST_CONVERT(enc, s)) { + for (;;) { + ICHAR *dataPtr = (ICHAR *)dataBuf; + XmlConvert(enc, &s, next, &dataPtr, (ICHAR *)dataBufEnd); + *eventEndPP = s; + characterDataHandler(handlerArg, dataBuf, dataPtr - (ICHAR *)dataBuf); + if (s == next) + break; + *eventPP = s; + } + } + else + characterDataHandler(handlerArg, + (XML_Char *)s, + (XML_Char *)next - (XML_Char *)s); + } + else if (defaultHandler) + reportDefault(parser, enc, s, next); + break; + case XML_TOK_PI: + if (!reportProcessingInstruction(parser, enc, s, next)) + return XML_ERROR_NO_MEMORY; + break; + case XML_TOK_COMMENT: + if (!reportComment(parser, enc, s, next)) + return XML_ERROR_NO_MEMORY; + break; + default: + if (defaultHandler) + reportDefault(parser, enc, s, next); + break; + } + *eventPP = s = next; + } + /* not reached */ +} + +/* If tagNamePtr is non-null, build a real list of attributes, +otherwise just check the attributes for well-formedness. */ + +static enum XML_Error storeAtts(XML_Parser parser, const ENCODING *enc, + const char *attStr, TAG_NAME *tagNamePtr, + BINDING **bindingsPtr) +{ + ELEMENT_TYPE *elementType = 0; + int nDefaultAtts = 0; + const XML_Char **appAtts; /* the attribute list to pass to the application */ + int attIndex = 0; + int i; + int n; + int nPrefixes = 0; + BINDING *binding; + const XML_Char *localPart; + + /* lookup the element type name */ + if (tagNamePtr) { + elementType = (ELEMENT_TYPE *)lookup(&dtd.elementTypes, tagNamePtr->str,0); + if (!elementType) { + tagNamePtr->str = poolCopyString(&dtd.pool, tagNamePtr->str); + if (!tagNamePtr->str) + return XML_ERROR_NO_MEMORY; + elementType = (ELEMENT_TYPE *)lookup(&dtd.elementTypes, tagNamePtr->str, sizeof(ELEMENT_TYPE)); + if (!elementType) + return XML_ERROR_NO_MEMORY; + if (ns && !setElementTypePrefix(parser, elementType)) + return XML_ERROR_NO_MEMORY; + } + nDefaultAtts = elementType->nDefaultAtts; + } + /* get the attributes from the tokenizer */ + n = XmlGetAttributes(enc, attStr, attsSize, atts); + if (n + nDefaultAtts > attsSize) { + int oldAttsSize = attsSize; + attsSize = n + nDefaultAtts + INIT_ATTS_SIZE; + atts = REALLOC((void *)atts, attsSize * sizeof(ATTRIBUTE)); + if (!atts) + return XML_ERROR_NO_MEMORY; + if (n > oldAttsSize) + XmlGetAttributes(enc, attStr, n, atts); + } + appAtts = (const XML_Char **)atts; + for (i = 0; i < n; i++) { + /* add the name and value to the attribute list */ + ATTRIBUTE_ID *attId = getAttributeId(parser, enc, atts[i].name, + atts[i].name + + XmlNameLength(enc, atts[i].name)); + if (!attId) + return XML_ERROR_NO_MEMORY; + /* detect duplicate attributes */ + if ((attId->name)[-1]) { + if (enc == encoding) + eventPtr = atts[i].name; + return XML_ERROR_DUPLICATE_ATTRIBUTE; + } + (attId->name)[-1] = 1; + appAtts[attIndex++] = attId->name; + if (!atts[i].normalized) { + enum XML_Error result; + int isCdata = 1; + + /* figure out whether declared as other than CDATA */ + if (attId->maybeTokenized) { + int j; + for (j = 0; j < nDefaultAtts; j++) { + if (attId == elementType->defaultAtts[j].id) { + isCdata = elementType->defaultAtts[j].isCdata; + break; + } + } + } + + /* normalize the attribute value */ + result = storeAttributeValue(parser, enc, isCdata, + atts[i].valuePtr, atts[i].valueEnd, + &tempPool); + if (result) + return result; + if (tagNamePtr) { + appAtts[attIndex] = poolStart(&tempPool); + poolFinish(&tempPool); + } + else + poolDiscard(&tempPool); + } + else if (tagNamePtr) { + /* the value did not need normalizing */ + appAtts[attIndex] = poolStoreString(&tempPool, enc, atts[i].valuePtr, atts[i].valueEnd); + if (appAtts[attIndex] == 0) + return XML_ERROR_NO_MEMORY; + poolFinish(&tempPool); + } + /* handle prefixed attribute names */ + if (attId->prefix && tagNamePtr) { + if (attId->xmlns) { + /* deal with namespace declarations here */ + if (!addBinding(parser, attId->prefix, attId, appAtts[attIndex], bindingsPtr)) + return XML_ERROR_NO_MEMORY; + --attIndex; + } + else { + /* deal with other prefixed names later */ + attIndex++; + nPrefixes++; + (attId->name)[-1] = 2; + } + } + else + attIndex++; + } + if (tagNamePtr) { + int j; + nSpecifiedAtts = attIndex; + if (elementType->idAtt && (elementType->idAtt->name)[-1]) { + for (i = 0; i < attIndex; i += 2) + if (appAtts[i] == elementType->idAtt->name) { + idAttIndex = i; + break; + } + } + else + idAttIndex = -1; + /* do attribute defaulting */ + for (j = 0; j < nDefaultAtts; j++) { + const DEFAULT_ATTRIBUTE *da = elementType->defaultAtts + j; + if (!(da->id->name)[-1] && da->value) { + if (da->id->prefix) { + if (da->id->xmlns) { + if (!addBinding(parser, da->id->prefix, da->id, da->value, bindingsPtr)) + return XML_ERROR_NO_MEMORY; + } + else { + (da->id->name)[-1] = 2; + nPrefixes++; + appAtts[attIndex++] = da->id->name; + appAtts[attIndex++] = da->value; + } + } + else { + (da->id->name)[-1] = 1; + appAtts[attIndex++] = da->id->name; + appAtts[attIndex++] = da->value; + } + } + } + appAtts[attIndex] = 0; + } + i = 0; + if (nPrefixes) { + /* expand prefixed attribute names */ + for (; i < attIndex; i += 2) { + if (appAtts[i][-1] == 2) { + ATTRIBUTE_ID *id; + ((XML_Char *)(appAtts[i]))[-1] = 0; + id = (ATTRIBUTE_ID *)lookup(&dtd.attributeIds, appAtts[i], 0); + if (id->prefix->binding) { + int j; + const BINDING *b = id->prefix->binding; + const XML_Char *s = appAtts[i]; + for (j = 0; j < b->uriLen; j++) { + if (!poolAppendChar(&tempPool, b->uri[j])) + return XML_ERROR_NO_MEMORY; + } + while (*s++ != ':') + ; + do { + if (!poolAppendChar(&tempPool, *s)) + return XML_ERROR_NO_MEMORY; + } while (*s++); + if (ns_triplets) { + tempPool.ptr[-1] = namespaceSeparator; + s = b->prefix->name; + do { + if (!poolAppendChar(&tempPool, *s)) + return XML_ERROR_NO_MEMORY; + } while (*s++); + } + + appAtts[i] = poolStart(&tempPool); + poolFinish(&tempPool); + } + if (!--nPrefixes) + break; + } + else + ((XML_Char *)(appAtts[i]))[-1] = 0; + } + } + /* clear the flags that say whether attributes were specified */ + for (; i < attIndex; i += 2) + ((XML_Char *)(appAtts[i]))[-1] = 0; + if (!tagNamePtr) + return XML_ERROR_NONE; + for (binding = *bindingsPtr; binding; binding = binding->nextTagBinding) + binding->attId->name[-1] = 0; + /* expand the element type name */ + if (elementType->prefix) { + binding = elementType->prefix->binding; + if (!binding) + return XML_ERROR_NONE; + localPart = tagNamePtr->str; + while (*localPart++ != XML_T(':')) + ; + } + else if (dtd.defaultPrefix.binding) { + binding = dtd.defaultPrefix.binding; + localPart = tagNamePtr->str; + } + else + return XML_ERROR_NONE; + tagNamePtr->localPart = localPart; + tagNamePtr->uriLen = binding->uriLen; + for (i = 0; localPart[i++];) + ; + n = i + binding->uriLen; + if (n > binding->uriAlloc) { + TAG *p; + XML_Char *uri = MALLOC((n + EXPAND_SPARE) * sizeof(XML_Char)); + if (!uri) + return XML_ERROR_NO_MEMORY; + binding->uriAlloc = n + EXPAND_SPARE; + memcpy(uri, binding->uri, binding->uriLen * sizeof(XML_Char)); + for (p = tagStack; p; p = p->parent) + if (p->name.str == binding->uri) + p->name.str = uri; + FREE(binding->uri); + binding->uri = uri; + } + memcpy(binding->uri + binding->uriLen, localPart, i * sizeof(XML_Char)); + tagNamePtr->str = binding->uri; + return XML_ERROR_NONE; +} + +static +int addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId, const XML_Char *uri, BINDING **bindingsPtr) +{ + BINDING *b; + int len; + for (len = 0; uri[len]; len++) + ; + if (namespaceSeparator) + len++; + if (freeBindingList) { + b = freeBindingList; + if (len > b->uriAlloc) { + b->uri = REALLOC(b->uri, sizeof(XML_Char) * (len + EXPAND_SPARE)); + if (!b->uri) + return 0; + b->uriAlloc = len + EXPAND_SPARE; + } + freeBindingList = b->nextTagBinding; + } + else { + b = MALLOC(sizeof(BINDING)); + if (!b) + return 0; + b->uri = MALLOC(sizeof(XML_Char) * (len + EXPAND_SPARE)); + if (!b->uri) { + FREE(b); + return 0; + } + b->uriAlloc = len + EXPAND_SPARE; + } + b->uriLen = len; + memcpy(b->uri, uri, len * sizeof(XML_Char)); + if (namespaceSeparator) + b->uri[len - 1] = namespaceSeparator; + b->prefix = prefix; + b->attId = attId; + b->prevPrefixBinding = prefix->binding; + if (*uri == XML_T('\0') && prefix == &dtd.defaultPrefix) + prefix->binding = 0; + else + prefix->binding = b; + b->nextTagBinding = *bindingsPtr; + *bindingsPtr = b; + if (startNamespaceDeclHandler) + startNamespaceDeclHandler(handlerArg, prefix->name, + prefix->binding ? uri : 0); + return 1; +} + +/* The idea here is to avoid using stack for each CDATA section when +the whole file is parsed with one call. */ + +static +enum XML_Error cdataSectionProcessor(XML_Parser parser, + const char *start, + const char *end, + const char **endPtr) +{ + enum XML_Error result = doCdataSection(parser, encoding, &start, end, endPtr); + if (start) { + processor = contentProcessor; + return contentProcessor(parser, start, end, endPtr); + } + return result; +} + +/* startPtr gets set to non-null is the section is closed, and to null if +the section is not yet closed. */ + +static +enum XML_Error doCdataSection(XML_Parser parser, + const ENCODING *enc, + const char **startPtr, + const char *end, + const char **nextPtr) +{ + const char *s = *startPtr; + const char **eventPP; + const char **eventEndPP; + if (enc == encoding) { + eventPP = &eventPtr; + *eventPP = s; + eventEndPP = &eventEndPtr; + } + else { + eventPP = &(openInternalEntities->internalEventPtr); + eventEndPP = &(openInternalEntities->internalEventEndPtr); + } + *eventPP = s; + *startPtr = 0; + for (;;) { + const char *next; + int tok = XmlCdataSectionTok(enc, s, end, &next); + *eventEndPP = next; + switch (tok) { + case XML_TOK_CDATA_SECT_CLOSE: + if (endCdataSectionHandler) + endCdataSectionHandler(handlerArg); +#if 0 + /* see comment under XML_TOK_CDATA_SECT_OPEN */ + else if (characterDataHandler) + characterDataHandler(handlerArg, dataBuf, 0); +#endif + else if (defaultHandler) + reportDefault(parser, enc, s, next); + *startPtr = next; + return XML_ERROR_NONE; + case XML_TOK_DATA_NEWLINE: + if (characterDataHandler) { + XML_Char c = 0xA; + characterDataHandler(handlerArg, &c, 1); + } + else if (defaultHandler) + reportDefault(parser, enc, s, next); + break; + case XML_TOK_DATA_CHARS: + if (characterDataHandler) { + if (MUST_CONVERT(enc, s)) { + for (;;) { + ICHAR *dataPtr = (ICHAR *)dataBuf; + XmlConvert(enc, &s, next, &dataPtr, (ICHAR *)dataBufEnd); + *eventEndPP = next; + characterDataHandler(handlerArg, dataBuf, dataPtr - (ICHAR *)dataBuf); + if (s == next) + break; + *eventPP = s; + } + } + else + characterDataHandler(handlerArg, + (XML_Char *)s, + (XML_Char *)next - (XML_Char *)s); + } + else if (defaultHandler) + reportDefault(parser, enc, s, next); + break; + case XML_TOK_INVALID: + *eventPP = next; + return XML_ERROR_INVALID_TOKEN; + case XML_TOK_PARTIAL_CHAR: + if (nextPtr) { + *nextPtr = s; + return XML_ERROR_NONE; + } + return XML_ERROR_PARTIAL_CHAR; + case XML_TOK_PARTIAL: + case XML_TOK_NONE: + if (nextPtr) { + *nextPtr = s; + return XML_ERROR_NONE; + } + return XML_ERROR_UNCLOSED_CDATA_SECTION; + default: + *eventPP = next; + return XML_ERROR_UNEXPECTED_STATE; + } + *eventPP = s = next; + } + /* not reached */ +} + +#ifdef XML_DTD + +/* The idea here is to avoid using stack for each IGNORE section when +the whole file is parsed with one call. */ + +static +enum XML_Error ignoreSectionProcessor(XML_Parser parser, + const char *start, + const char *end, + const char **endPtr) +{ + enum XML_Error result = doIgnoreSection(parser, encoding, &start, end, endPtr); + if (start) { + processor = prologProcessor; + return prologProcessor(parser, start, end, endPtr); + } + return result; +} + +/* startPtr gets set to non-null is the section is closed, and to null if +the section is not yet closed. */ + +static +enum XML_Error doIgnoreSection(XML_Parser parser, + const ENCODING *enc, + const char **startPtr, + const char *end, + const char **nextPtr) +{ + const char *next; + int tok; + const char *s = *startPtr; + const char **eventPP; + const char **eventEndPP; + if (enc == encoding) { + eventPP = &eventPtr; + *eventPP = s; + eventEndPP = &eventEndPtr; + } + else { + eventPP = &(openInternalEntities->internalEventPtr); + eventEndPP = &(openInternalEntities->internalEventEndPtr); + } + *eventPP = s; + *startPtr = 0; + tok = XmlIgnoreSectionTok(enc, s, end, &next); + *eventEndPP = next; + switch (tok) { + case XML_TOK_IGNORE_SECT: + if (defaultHandler) + reportDefault(parser, enc, s, next); + *startPtr = next; + return XML_ERROR_NONE; + case XML_TOK_INVALID: + *eventPP = next; + return XML_ERROR_INVALID_TOKEN; + case XML_TOK_PARTIAL_CHAR: + if (nextPtr) { + *nextPtr = s; + return XML_ERROR_NONE; + } + return XML_ERROR_PARTIAL_CHAR; + case XML_TOK_PARTIAL: + case XML_TOK_NONE: + if (nextPtr) { + *nextPtr = s; + return XML_ERROR_NONE; + } + return XML_ERROR_SYNTAX; /* XML_ERROR_UNCLOSED_IGNORE_SECTION */ + default: + *eventPP = next; + return XML_ERROR_UNEXPECTED_STATE; + } + /* not reached */ +} + +#endif /* XML_DTD */ + +static enum XML_Error +initializeEncoding(XML_Parser parser) +{ + const char *s; +#ifdef XML_UNICODE + char encodingBuf[128]; + if (!protocolEncodingName) + s = 0; + else { + int i; + for (i = 0; protocolEncodingName[i]; i++) { + if (i == sizeof(encodingBuf) - 1 + || (protocolEncodingName[i] & ~0x7f) != 0) { + encodingBuf[0] = '\0'; + break; + } + encodingBuf[i] = (char)protocolEncodingName[i]; + } + encodingBuf[i] = '\0'; + s = encodingBuf; + } +#else + s = protocolEncodingName; +#endif + if ((ns ? XmlInitEncodingNS : XmlInitEncoding)(&initEncoding, &encoding, s)) + return XML_ERROR_NONE; + return handleUnknownEncoding(parser, protocolEncodingName); +} + +static enum XML_Error +processXmlDecl(XML_Parser parser, int isGeneralTextEntity, + const char *s, const char *next) +{ + const char *encodingName = 0; + const char *storedEncName = 0; + const ENCODING *newEncoding = 0; + const char *version = 0; + const char *versionend; + const char *storedversion = 0; + int standalone = -1; + if (!(ns + ? XmlParseXmlDeclNS + : XmlParseXmlDecl)(isGeneralTextEntity, + encoding, + s, + next, + &eventPtr, + &version, + &versionend, + &encodingName, + &newEncoding, + &standalone)) + return XML_ERROR_SYNTAX; + if (!isGeneralTextEntity && standalone == 1) { + dtd.standalone = 1; +#ifdef XML_DTD + if (paramEntityParsing == XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE) + paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER; +#endif /* XML_DTD */ + } + if (xmlDeclHandler) { + if (encodingName) { + storedEncName = poolStoreString(&temp2Pool, + encoding, + encodingName, + encodingName + + XmlNameLength(encoding, encodingName)); + if (! storedEncName) + return XML_ERROR_NO_MEMORY; + poolFinish(&temp2Pool); + } + if (version) { + storedversion = poolStoreString(&temp2Pool, + encoding, + version, + versionend - encoding->minBytesPerChar); + if (! storedversion) + return XML_ERROR_NO_MEMORY; + } + xmlDeclHandler(handlerArg, storedversion, storedEncName, standalone); + } + else if (defaultHandler) + reportDefault(parser, encoding, s, next); + if (!protocolEncodingName) { + if (newEncoding) { + if (newEncoding->minBytesPerChar != encoding->minBytesPerChar) { + eventPtr = encodingName; + return XML_ERROR_INCORRECT_ENCODING; + } + encoding = newEncoding; + } + else if (encodingName) { + enum XML_Error result; + if (! storedEncName) { + storedEncName = poolStoreString(&temp2Pool, + encoding, + encodingName, + encodingName + + XmlNameLength(encoding, encodingName)); + if (! storedEncName) + return XML_ERROR_NO_MEMORY; + } + result = handleUnknownEncoding(parser, storedEncName); + poolClear(&tempPool); + if (result == XML_ERROR_UNKNOWN_ENCODING) + eventPtr = encodingName; + return result; + } + } + + if (storedEncName || storedversion) + poolClear(&temp2Pool); + + return XML_ERROR_NONE; +} + +static enum XML_Error +handleUnknownEncoding(XML_Parser parser, const XML_Char *encodingName) +{ + if (unknownEncodingHandler) { + XML_Encoding info; + int i; + for (i = 0; i < 256; i++) + info.map[i] = -1; + info.convert = 0; + info.data = 0; + info.release = 0; + if (unknownEncodingHandler(unknownEncodingHandlerData, encodingName, &info)) { + ENCODING *enc; + unknownEncodingMem = MALLOC(XmlSizeOfUnknownEncoding()); + if (!unknownEncodingMem) { + if (info.release) + info.release(info.data); + return XML_ERROR_NO_MEMORY; + } + enc = (ns + ? XmlInitUnknownEncodingNS + : XmlInitUnknownEncoding)(unknownEncodingMem, + info.map, + info.convert, + info.data); + if (enc) { + unknownEncodingData = info.data; + unknownEncodingRelease = info.release; + encoding = enc; + return XML_ERROR_NONE; + } + } + if (info.release) + info.release(info.data); + } + return XML_ERROR_UNKNOWN_ENCODING; +} + +static enum XML_Error +prologInitProcessor(XML_Parser parser, + const char *s, + const char *end, + const char **nextPtr) +{ + enum XML_Error result = initializeEncoding(parser); + if (result != XML_ERROR_NONE) + return result; + processor = prologProcessor; + return prologProcessor(parser, s, end, nextPtr); +} + +static enum XML_Error +prologProcessor(XML_Parser parser, + const char *s, + const char *end, + const char **nextPtr) +{ + const char *next; + int tok = XmlPrologTok(encoding, s, end, &next); + return doProlog(parser, encoding, s, end, tok, next, nextPtr); +} + +static enum XML_Error +doProlog(XML_Parser parser, + const ENCODING *enc, + const char *s, + const char *end, + int tok, + const char *next, + const char **nextPtr) +{ +#ifdef XML_DTD + static const XML_Char externalSubsetName[] = { '#' , '\0' }; +#endif /* XML_DTD */ + + const char **eventPP; + const char **eventEndPP; + enum XML_Content_Quant quant; + + if (enc == encoding) { + eventPP = &eventPtr; + eventEndPP = &eventEndPtr; + } + else { + eventPP = &(openInternalEntities->internalEventPtr); + eventEndPP = &(openInternalEntities->internalEventEndPtr); + } + for (;;) { + int role; + *eventPP = s; + *eventEndPP = next; + if (tok <= 0) { + if (nextPtr != 0 && tok != XML_TOK_INVALID) { + *nextPtr = s; + return XML_ERROR_NONE; + } + switch (tok) { + case XML_TOK_INVALID: + *eventPP = next; + return XML_ERROR_INVALID_TOKEN; + case XML_TOK_PARTIAL: + return XML_ERROR_UNCLOSED_TOKEN; + case XML_TOK_PARTIAL_CHAR: + return XML_ERROR_PARTIAL_CHAR; + case XML_TOK_NONE: +#ifdef XML_DTD + if (enc != encoding) + return XML_ERROR_NONE; + if (parentParser) { + if (XmlTokenRole(&prologState, XML_TOK_NONE, end, end, enc) + == XML_ROLE_ERROR) + return XML_ERROR_SYNTAX; + hadExternalDoctype = 0; + return XML_ERROR_NONE; + } +#endif /* XML_DTD */ + return XML_ERROR_NO_ELEMENTS; + default: + tok = -tok; + next = end; + break; + } + } + role = XmlTokenRole(&prologState, tok, s, next, enc); + switch (role) { + case XML_ROLE_XML_DECL: + { + enum XML_Error result = processXmlDecl(parser, 0, s, next); + if (result != XML_ERROR_NONE) + return result; + enc = encoding; + } + break; + case XML_ROLE_DOCTYPE_NAME: + if (startDoctypeDeclHandler) { + doctypeName = poolStoreString(&tempPool, enc, s, next); + if (! doctypeName) + return XML_ERROR_NO_MEMORY; + poolFinish(&tempPool); + doctypeSysid = 0; + doctypePubid = 0; + } + break; + case XML_ROLE_DOCTYPE_INTERNAL_SUBSET: + if (startDoctypeDeclHandler) { + startDoctypeDeclHandler(handlerArg, doctypeName, doctypeSysid, + doctypePubid, 1); + doctypeName = 0; + poolClear(&tempPool); + } + break; +#ifdef XML_DTD + case XML_ROLE_TEXT_DECL: + { + enum XML_Error result = processXmlDecl(parser, 1, s, next); + if (result != XML_ERROR_NONE) + return result; + enc = encoding; + } + break; +#endif /* XML_DTD */ + case XML_ROLE_DOCTYPE_PUBLIC_ID: + if (startDoctypeDeclHandler) { + doctypePubid = poolStoreString(&tempPool, enc, s + 1, next - 1); + if (! doctypePubid) + return XML_ERROR_NO_MEMORY; + poolFinish(&tempPool); + } +#ifdef XML_DTD + declEntity = (ENTITY *)lookup(&dtd.paramEntities, + externalSubsetName, + sizeof(ENTITY)); + if (!declEntity) + return XML_ERROR_NO_MEMORY; +#endif /* XML_DTD */ + /* fall through */ + case XML_ROLE_ENTITY_PUBLIC_ID: + if (!XmlIsPublicId(enc, s, next, eventPP)) + return XML_ERROR_SYNTAX; + if (declEntity) { + XML_Char *tem = poolStoreString(&dtd.pool, + enc, + s + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (!tem) + return XML_ERROR_NO_MEMORY; + normalizePublicId(tem); + declEntity->publicId = tem; + poolFinish(&dtd.pool); + } + break; + case XML_ROLE_DOCTYPE_CLOSE: + if (doctypeName) { + startDoctypeDeclHandler(handlerArg, doctypeName, + doctypeSysid, doctypePubid, 0); + poolClear(&tempPool); + } + if (dtd.complete && hadExternalDoctype) { + dtd.complete = 0; +#ifdef XML_DTD + if (paramEntityParsing && externalEntityRefHandler) { + ENTITY *entity = (ENTITY *)lookup(&dtd.paramEntities, + externalSubsetName, + 0); + if (!externalEntityRefHandler(externalEntityRefHandlerArg, + 0, + entity->base, + entity->systemId, + entity->publicId)) + return XML_ERROR_EXTERNAL_ENTITY_HANDLING; + } +#endif /* XML_DTD */ + if (!dtd.complete + && !dtd.standalone + && notStandaloneHandler + && !notStandaloneHandler(handlerArg)) + return XML_ERROR_NOT_STANDALONE; + } + if (endDoctypeDeclHandler) + endDoctypeDeclHandler(handlerArg); + break; + case XML_ROLE_INSTANCE_START: + processor = contentProcessor; + return contentProcessor(parser, s, end, nextPtr); + case XML_ROLE_ATTLIST_ELEMENT_NAME: + declElementType = getElementType(parser, enc, s, next); + if (!declElementType) + return XML_ERROR_NO_MEMORY; + break; + case XML_ROLE_ATTRIBUTE_NAME: + declAttributeId = getAttributeId(parser, enc, s, next); + if (!declAttributeId) + return XML_ERROR_NO_MEMORY; + declAttributeIsCdata = 0; + declAttributeType = 0; + declAttributeIsId = 0; + break; + case XML_ROLE_ATTRIBUTE_TYPE_CDATA: + declAttributeIsCdata = 1; + declAttributeType = "CDATA"; + break; + case XML_ROLE_ATTRIBUTE_TYPE_ID: + declAttributeIsId = 1; + declAttributeType = "ID"; + break; + case XML_ROLE_ATTRIBUTE_TYPE_IDREF: + declAttributeType = "IDREF"; + break; + case XML_ROLE_ATTRIBUTE_TYPE_IDREFS: + declAttributeType = "IDREFS"; + break; + case XML_ROLE_ATTRIBUTE_TYPE_ENTITY: + declAttributeType = "ENTITY"; + break; + case XML_ROLE_ATTRIBUTE_TYPE_ENTITIES: + declAttributeType = "ENTITIES"; + break; + case XML_ROLE_ATTRIBUTE_TYPE_NMTOKEN: + declAttributeType = "NMTOKEN"; + break; + case XML_ROLE_ATTRIBUTE_TYPE_NMTOKENS: + declAttributeType = "NMTOKENS"; + break; + + case XML_ROLE_ATTRIBUTE_ENUM_VALUE: + case XML_ROLE_ATTRIBUTE_NOTATION_VALUE: + if (attlistDeclHandler) + { + char *prefix; + if (declAttributeType) { + prefix = "|"; + } + else { + prefix = (role == XML_ROLE_ATTRIBUTE_NOTATION_VALUE + ? "NOTATION(" + : "("); + } + if (! poolAppendString(&tempPool, prefix)) + return XML_ERROR_NO_MEMORY; + if (! poolAppend(&tempPool, enc, s, next)) + return XML_ERROR_NO_MEMORY; + declAttributeType = tempPool.start; + } + break; + case XML_ROLE_IMPLIED_ATTRIBUTE_VALUE: + case XML_ROLE_REQUIRED_ATTRIBUTE_VALUE: + if (dtd.complete + && !defineAttribute(declElementType, declAttributeId, + declAttributeIsCdata, declAttributeIsId, 0, + parser)) + return XML_ERROR_NO_MEMORY; + if (attlistDeclHandler && declAttributeType) { + if (*declAttributeType == '(' + || (*declAttributeType == 'N' && declAttributeType[1] == 'O')) { + /* Enumerated or Notation type */ + if (! poolAppendChar(&tempPool, ')') + || ! poolAppendChar(&tempPool, '\0')) + return XML_ERROR_NO_MEMORY; + declAttributeType = tempPool.start; + poolFinish(&tempPool); + } + *eventEndPP = s; + attlistDeclHandler(handlerArg, declElementType->name, + declAttributeId->name, declAttributeType, + 0, role == XML_ROLE_REQUIRED_ATTRIBUTE_VALUE); + poolClear(&tempPool); + } + break; + case XML_ROLE_DEFAULT_ATTRIBUTE_VALUE: + case XML_ROLE_FIXED_ATTRIBUTE_VALUE: + { + const XML_Char *attVal; + enum XML_Error result + = storeAttributeValue(parser, enc, declAttributeIsCdata, + s + enc->minBytesPerChar, + next - enc->minBytesPerChar, + &dtd.pool); + if (result) + return result; + attVal = poolStart(&dtd.pool); + poolFinish(&dtd.pool); + if (dtd.complete + /* ID attributes aren't allowed to have a default */ + && !defineAttribute(declElementType, declAttributeId, declAttributeIsCdata, 0, attVal, parser)) + return XML_ERROR_NO_MEMORY; + if (attlistDeclHandler && declAttributeType) { + if (*declAttributeType == '(' + || (*declAttributeType == 'N' && declAttributeType[1] == 'O')) { + /* Enumerated or Notation type */ + if (! poolAppendChar(&tempPool, ')') + || ! poolAppendChar(&tempPool, '\0')) + return XML_ERROR_NO_MEMORY; + declAttributeType = tempPool.start; + poolFinish(&tempPool); + } + *eventEndPP = s; + attlistDeclHandler(handlerArg, declElementType->name, + declAttributeId->name, declAttributeType, + attVal, + role == XML_ROLE_FIXED_ATTRIBUTE_VALUE); + poolClear(&tempPool); + } + break; + } + case XML_ROLE_ENTITY_VALUE: + { + enum XML_Error result = storeEntityValue(parser, enc, + s + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (declEntity) { + declEntity->textPtr = poolStart(&dtd.pool); + declEntity->textLen = poolLength(&dtd.pool); + poolFinish(&dtd.pool); + if (entityDeclHandler) { + *eventEndPP = s; + entityDeclHandler(handlerArg, + declEntity->name, + declEntity->is_param, + declEntity->textPtr, + declEntity->textLen, + curBase, 0, 0, 0); + } + } + else + poolDiscard(&dtd.pool); + if (result != XML_ERROR_NONE) + return result; + } + break; + case XML_ROLE_DOCTYPE_SYSTEM_ID: + if (startDoctypeDeclHandler) { + doctypeSysid = poolStoreString(&tempPool, enc, s + 1, next - 1); + if (! doctypeSysid) + return XML_ERROR_NO_MEMORY; + poolFinish(&tempPool); + } + if (!dtd.standalone +#ifdef XML_DTD + && !paramEntityParsing +#endif /* XML_DTD */ + && notStandaloneHandler + && !notStandaloneHandler(handlerArg)) + return XML_ERROR_NOT_STANDALONE; + hadExternalDoctype = 1; +#ifndef XML_DTD + break; +#else /* XML_DTD */ + if (!declEntity) { + declEntity = (ENTITY *)lookup(&dtd.paramEntities, + externalSubsetName, + sizeof(ENTITY)); + declEntity->publicId = 0; + if (!declEntity) + return XML_ERROR_NO_MEMORY; + } + /* fall through */ +#endif /* XML_DTD */ + case XML_ROLE_ENTITY_SYSTEM_ID: + if (declEntity) { + declEntity->systemId = poolStoreString(&dtd.pool, enc, + s + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (!declEntity->systemId) + return XML_ERROR_NO_MEMORY; + declEntity->base = curBase; + poolFinish(&dtd.pool); + } + break; + case XML_ROLE_ENTITY_COMPLETE: + if (declEntity && entityDeclHandler) { + *eventEndPP = s; + entityDeclHandler(handlerArg, + declEntity->name, + 0,0,0, + declEntity->base, + declEntity->systemId, + declEntity->publicId, + 0); + } + break; + case XML_ROLE_ENTITY_NOTATION_NAME: + if (declEntity) { + declEntity->notation = poolStoreString(&dtd.pool, enc, s, next); + if (!declEntity->notation) + return XML_ERROR_NO_MEMORY; + poolFinish(&dtd.pool); + if (unparsedEntityDeclHandler) { + *eventEndPP = s; + unparsedEntityDeclHandler(handlerArg, + declEntity->name, + declEntity->base, + declEntity->systemId, + declEntity->publicId, + declEntity->notation); + } + else if (entityDeclHandler) { + *eventEndPP = s; + entityDeclHandler(handlerArg, + declEntity->name, + 0,0,0, + declEntity->base, + declEntity->systemId, + declEntity->publicId, + declEntity->notation); + } + } + break; + case XML_ROLE_GENERAL_ENTITY_NAME: + { + const XML_Char *name; + if (XmlPredefinedEntityName(enc, s, next)) { + declEntity = 0; + break; + } + name = poolStoreString(&dtd.pool, enc, s, next); + if (!name) + return XML_ERROR_NO_MEMORY; + if (dtd.complete) { + declEntity = (ENTITY *)lookup(&dtd.generalEntities, name, sizeof(ENTITY)); + if (!declEntity) + return XML_ERROR_NO_MEMORY; + if (declEntity->name != name) { + poolDiscard(&dtd.pool); + declEntity = 0; + } + else { + poolFinish(&dtd.pool); + declEntity->publicId = 0; + declEntity->is_param = 0; + } + } + else { + poolDiscard(&dtd.pool); + declEntity = 0; + } + } + break; + case XML_ROLE_PARAM_ENTITY_NAME: +#ifdef XML_DTD + if (dtd.complete) { + const XML_Char *name = poolStoreString(&dtd.pool, enc, s, next); + if (!name) + return XML_ERROR_NO_MEMORY; + declEntity = (ENTITY *)lookup(&dtd.paramEntities, + name, sizeof(ENTITY)); + if (!declEntity) + return XML_ERROR_NO_MEMORY; + if (declEntity->name != name) { + poolDiscard(&dtd.pool); + declEntity = 0; + } + else { + poolFinish(&dtd.pool); + declEntity->publicId = 0; + declEntity->is_param = 1; + } + } +#else /* not XML_DTD */ + declEntity = 0; +#endif /* not XML_DTD */ + break; + case XML_ROLE_NOTATION_NAME: + declNotationPublicId = 0; + declNotationName = 0; + if (notationDeclHandler) { + declNotationName = poolStoreString(&tempPool, enc, s, next); + if (!declNotationName) + return XML_ERROR_NO_MEMORY; + poolFinish(&tempPool); + } + break; + case XML_ROLE_NOTATION_PUBLIC_ID: + if (!XmlIsPublicId(enc, s, next, eventPP)) + return XML_ERROR_SYNTAX; + if (declNotationName) { + XML_Char *tem = poolStoreString(&tempPool, + enc, + s + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (!tem) + return XML_ERROR_NO_MEMORY; + normalizePublicId(tem); + declNotationPublicId = tem; + poolFinish(&tempPool); + } + break; + case XML_ROLE_NOTATION_SYSTEM_ID: + if (declNotationName && notationDeclHandler) { + const XML_Char *systemId + = poolStoreString(&tempPool, enc, + s + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (!systemId) + return XML_ERROR_NO_MEMORY; + *eventEndPP = s; + notationDeclHandler(handlerArg, + declNotationName, + curBase, + systemId, + declNotationPublicId); + } + poolClear(&tempPool); + break; + case XML_ROLE_NOTATION_NO_SYSTEM_ID: + if (declNotationPublicId && notationDeclHandler) { + *eventEndPP = s; + notationDeclHandler(handlerArg, + declNotationName, + curBase, + 0, + declNotationPublicId); + } + poolClear(&tempPool); + break; + case XML_ROLE_ERROR: + switch (tok) { + case XML_TOK_PARAM_ENTITY_REF: + return XML_ERROR_PARAM_ENTITY_REF; + case XML_TOK_XML_DECL: + return XML_ERROR_MISPLACED_XML_PI; + default: + return XML_ERROR_SYNTAX; + } +#ifdef XML_DTD + case XML_ROLE_IGNORE_SECT: + { + enum XML_Error result; + if (defaultHandler) + reportDefault(parser, enc, s, next); + result = doIgnoreSection(parser, enc, &next, end, nextPtr); + if (!next) { + processor = ignoreSectionProcessor; + return result; + } + } + break; +#endif /* XML_DTD */ + case XML_ROLE_GROUP_OPEN: + if (prologState.level >= groupSize) { + if (groupSize) { + groupConnector = REALLOC(groupConnector, groupSize *= 2); + if (dtd.scaffIndex) + dtd.scaffIndex = REALLOC(dtd.scaffIndex, groupSize * sizeof(int)); + } + else + groupConnector = MALLOC(groupSize = 32); + if (!groupConnector) + return XML_ERROR_NO_MEMORY; + } + groupConnector[prologState.level] = 0; + if (dtd.in_eldecl) { + int myindex = nextScaffoldPart(parser); + if (myindex < 0) + return XML_ERROR_NO_MEMORY; + dtd.scaffIndex[dtd.scaffLevel] = myindex; + dtd.scaffLevel++; + dtd.scaffold[myindex].type = XML_CTYPE_SEQ; + } + break; + case XML_ROLE_GROUP_SEQUENCE: + if (groupConnector[prologState.level] == '|') + return XML_ERROR_SYNTAX; + groupConnector[prologState.level] = ','; + break; + case XML_ROLE_GROUP_CHOICE: + if (groupConnector[prologState.level] == ',') + return XML_ERROR_SYNTAX; + if (dtd.in_eldecl + && ! groupConnector[prologState.level] + && dtd.scaffold[dtd.scaffIndex[dtd.scaffLevel - 1]].type != XML_CTYPE_MIXED + ) { + dtd.scaffold[dtd.scaffIndex[dtd.scaffLevel - 1]].type = XML_CTYPE_CHOICE; + } + groupConnector[prologState.level] = '|'; + break; + case XML_ROLE_PARAM_ENTITY_REF: +#ifdef XML_DTD + case XML_ROLE_INNER_PARAM_ENTITY_REF: + if (paramEntityParsing + && (dtd.complete || role == XML_ROLE_INNER_PARAM_ENTITY_REF)) { + const XML_Char *name; + ENTITY *entity; + name = poolStoreString(&dtd.pool, enc, + s + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (!name) + return XML_ERROR_NO_MEMORY; + entity = (ENTITY *)lookup(&dtd.paramEntities, name, 0); + poolDiscard(&dtd.pool); + if (!entity) { + /* FIXME what to do if !dtd.complete? */ + return XML_ERROR_UNDEFINED_ENTITY; + } + if (entity->open) + return XML_ERROR_RECURSIVE_ENTITY_REF; + if (entity->textPtr) { + enum XML_Error result; + result = processInternalParamEntity(parser, entity); + if (result != XML_ERROR_NONE) + return result; + break; + } + if (role == XML_ROLE_INNER_PARAM_ENTITY_REF) + return XML_ERROR_PARAM_ENTITY_REF; + if (externalEntityRefHandler) { + dtd.complete = 0; + entity->open = 1; + if (!externalEntityRefHandler(externalEntityRefHandlerArg, + 0, + entity->base, + entity->systemId, + entity->publicId)) { + entity->open = 0; + return XML_ERROR_EXTERNAL_ENTITY_HANDLING; + } + entity->open = 0; + if (dtd.complete) + break; + } + } +#endif /* XML_DTD */ + if (!dtd.standalone + && notStandaloneHandler + && !notStandaloneHandler(handlerArg)) + return XML_ERROR_NOT_STANDALONE; + dtd.complete = 0; + if (defaultHandler) + reportDefault(parser, enc, s, next); + break; + + /* Element declaration stuff */ + + case XML_ROLE_ELEMENT_NAME: + if (elementDeclHandler) { + declElementType = getElementType(parser, enc, s, next); + if (! declElementType) + return XML_ERROR_NO_MEMORY; + dtd.scaffLevel = 0; + dtd.scaffCount = 0; + dtd.in_eldecl = 1; + } + break; + + case XML_ROLE_CONTENT_ANY: + case XML_ROLE_CONTENT_EMPTY: + if (dtd.in_eldecl) { + if (elementDeclHandler) { + XML_Content * content = (XML_Content *) MALLOC(sizeof(XML_Content)); + if (! content) + return XML_ERROR_NO_MEMORY; + content->quant = XML_CQUANT_NONE; + content->name = 0; + content->numchildren = 0; + content->children = 0; + content->type = ((role == XML_ROLE_CONTENT_ANY) ? + XML_CTYPE_ANY : + XML_CTYPE_EMPTY); + *eventEndPP = s; + elementDeclHandler(handlerArg, declElementType->name, content); + } + dtd.in_eldecl = 0; + } + break; + + case XML_ROLE_CONTENT_PCDATA: + if (dtd.in_eldecl) { + dtd.scaffold[dtd.scaffIndex[dtd.scaffLevel - 1]].type = XML_CTYPE_MIXED; + } + break; + + case XML_ROLE_CONTENT_ELEMENT: + quant = XML_CQUANT_NONE; + goto elementContent; + case XML_ROLE_CONTENT_ELEMENT_OPT: + quant = XML_CQUANT_OPT; + goto elementContent; + case XML_ROLE_CONTENT_ELEMENT_REP: + quant = XML_CQUANT_REP; + goto elementContent; + case XML_ROLE_CONTENT_ELEMENT_PLUS: + quant = XML_CQUANT_PLUS; + elementContent: + if (dtd.in_eldecl) + { + ELEMENT_TYPE *el; + const char *nxt = quant == XML_CQUANT_NONE ? next : next - 1; + int myindex = nextScaffoldPart(parser); + if (myindex < 0) + return XML_ERROR_NO_MEMORY; + dtd.scaffold[myindex].type = XML_CTYPE_NAME; + dtd.scaffold[myindex].quant = quant; + el = getElementType(parser, enc, s, nxt); + if (! el) + return XML_ERROR_NO_MEMORY; + dtd.scaffold[myindex].name = el->name; + dtd.contentStringLen += nxt - s + 1; + } + break; + + case XML_ROLE_GROUP_CLOSE: + quant = XML_CQUANT_NONE; + goto closeGroup; + case XML_ROLE_GROUP_CLOSE_OPT: + quant = XML_CQUANT_OPT; + goto closeGroup; + case XML_ROLE_GROUP_CLOSE_REP: + quant = XML_CQUANT_REP; + goto closeGroup; + case XML_ROLE_GROUP_CLOSE_PLUS: + quant = XML_CQUANT_PLUS; + closeGroup: + if (dtd.in_eldecl) { + dtd.scaffLevel--; + dtd.scaffold[dtd.scaffIndex[dtd.scaffLevel]].quant = quant; + if (dtd.scaffLevel == 0) { + if (elementDeclHandler) { + XML_Content *model = build_model(parser); + if (! model) + return XML_ERROR_NO_MEMORY; + *eventEndPP = s; + elementDeclHandler(handlerArg, declElementType->name, model); + } + dtd.in_eldecl = 0; + dtd.contentStringLen = 0; + } + } + break; + /* End element declaration stuff */ + + case XML_ROLE_NONE: + switch (tok) { + case XML_TOK_PI: + if (!reportProcessingInstruction(parser, enc, s, next)) + return XML_ERROR_NO_MEMORY; + break; + case XML_TOK_COMMENT: + if (!reportComment(parser, enc, s, next)) + return XML_ERROR_NO_MEMORY; + break; + } + break; + } + if (defaultHandler) { + switch (tok) { + case XML_TOK_PI: + case XML_TOK_COMMENT: + case XML_TOK_BOM: + case XML_TOK_XML_DECL: +#ifdef XML_DTD + case XML_TOK_IGNORE_SECT: +#endif /* XML_DTD */ + case XML_TOK_PARAM_ENTITY_REF: + break; + default: +#ifdef XML_DTD + if (role != XML_ROLE_IGNORE_SECT) +#endif /* XML_DTD */ + reportDefault(parser, enc, s, next); + } + } + s = next; + tok = XmlPrologTok(enc, s, end, &next); + } + /* not reached */ +} + +static +enum XML_Error epilogProcessor(XML_Parser parser, + const char *s, + const char *end, + const char **nextPtr) +{ + processor = epilogProcessor; + eventPtr = s; + for (;;) { + const char *next; + int tok = XmlPrologTok(encoding, s, end, &next); + eventEndPtr = next; + switch (tok) { + case -XML_TOK_PROLOG_S: + if (defaultHandler) { + eventEndPtr = end; + reportDefault(parser, encoding, s, end); + } + /* fall through */ + case XML_TOK_NONE: + if (nextPtr) + *nextPtr = end; + return XML_ERROR_NONE; + case XML_TOK_PROLOG_S: + if (defaultHandler) + reportDefault(parser, encoding, s, next); + break; + case XML_TOK_PI: + if (!reportProcessingInstruction(parser, encoding, s, next)) + return XML_ERROR_NO_MEMORY; + break; + case XML_TOK_COMMENT: + if (!reportComment(parser, encoding, s, next)) + return XML_ERROR_NO_MEMORY; + break; + case XML_TOK_INVALID: + eventPtr = next; + return XML_ERROR_INVALID_TOKEN; + case XML_TOK_PARTIAL: + if (nextPtr) { + *nextPtr = s; + return XML_ERROR_NONE; + } + return XML_ERROR_UNCLOSED_TOKEN; + case XML_TOK_PARTIAL_CHAR: + if (nextPtr) { + *nextPtr = s; + return XML_ERROR_NONE; + } + return XML_ERROR_PARTIAL_CHAR; + default: + return XML_ERROR_JUNK_AFTER_DOC_ELEMENT; + } + eventPtr = s = next; + } +} + +#ifdef XML_DTD + +static enum XML_Error +processInternalParamEntity(XML_Parser parser, ENTITY *entity) +{ + const char *s, *end, *next; + int tok; + enum XML_Error result; + OPEN_INTERNAL_ENTITY openEntity; + entity->open = 1; + openEntity.next = openInternalEntities; + openInternalEntities = &openEntity; + openEntity.entity = entity; + openEntity.internalEventPtr = 0; + openEntity.internalEventEndPtr = 0; + s = (char *)entity->textPtr; + end = (char *)(entity->textPtr + entity->textLen); + tok = XmlPrologTok(internalEncoding, s, end, &next); + result = doProlog(parser, internalEncoding, s, end, tok, next, 0); + entity->open = 0; + openInternalEntities = openEntity.next; + return result; +} + +#endif /* XML_DTD */ + +static +enum XML_Error errorProcessor(XML_Parser parser, + const char *s, + const char *end, + const char **nextPtr) +{ + itkExpatUnused(s); + itkExpatUnused(end); + itkExpatUnused(nextPtr); + return errorCode; +} + +static enum XML_Error +storeAttributeValue(XML_Parser parser, const ENCODING *enc, int isCdata, + const char *ptr, const char *end, + STRING_POOL *pool) +{ + enum XML_Error result = appendAttributeValue(parser, enc, isCdata, ptr, end, pool); + if (result) + return result; + if (!isCdata && poolLength(pool) && poolLastChar(pool) == 0x20) + poolChop(pool); + if (!poolAppendChar(pool, XML_T('\0'))) + return XML_ERROR_NO_MEMORY; + return XML_ERROR_NONE; +} + +static enum XML_Error +appendAttributeValue(XML_Parser parser, const ENCODING *enc, int isCdata, + const char *ptr, const char *end, + STRING_POOL *pool) +{ + for (;;) { + const char *next; + int tok = XmlAttributeValueTok(enc, ptr, end, &next); + switch (tok) { + case XML_TOK_NONE: + return XML_ERROR_NONE; + case XML_TOK_INVALID: + if (enc == encoding) + eventPtr = next; + return XML_ERROR_INVALID_TOKEN; + case XML_TOK_PARTIAL: + if (enc == encoding) + eventPtr = ptr; + return XML_ERROR_INVALID_TOKEN; + case XML_TOK_CHAR_REF: + { + XML_Char buf[XML_ENCODE_MAX]; + int i; + int n = XmlCharRefNumber(enc, ptr); + if (n < 0) { + if (enc == encoding) + eventPtr = ptr; + return XML_ERROR_BAD_CHAR_REF; + } + if (!isCdata + && n == 0x20 /* space */ + && (poolLength(pool) == 0 || poolLastChar(pool) == 0x20)) + break; + n = XmlEncode(n, (ICHAR *)buf); + if (!n) { + if (enc == encoding) + eventPtr = ptr; + return XML_ERROR_BAD_CHAR_REF; + } + for (i = 0; i < n; i++) { + if (!poolAppendChar(pool, buf[i])) + return XML_ERROR_NO_MEMORY; + } + } + break; + case XML_TOK_DATA_CHARS: + if (!poolAppend(pool, enc, ptr, next)) + return XML_ERROR_NO_MEMORY; + break; + case XML_TOK_TRAILING_CR: + next = ptr + enc->minBytesPerChar; + /* fall through */ + case XML_TOK_ATTRIBUTE_VALUE_S: + case XML_TOK_DATA_NEWLINE: + if (!isCdata && (poolLength(pool) == 0 || poolLastChar(pool) == 0x20)) + break; + if (!poolAppendChar(pool, 0x20)) + return XML_ERROR_NO_MEMORY; + break; + case XML_TOK_ENTITY_REF: + { + const XML_Char *name; + ENTITY *entity; + XML_Char ch = XmlPredefinedEntityName(enc, + ptr + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (ch) { + if (!poolAppendChar(pool, ch)) + return XML_ERROR_NO_MEMORY; + break; + } + name = poolStoreString(&temp2Pool, enc, + ptr + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (!name) + return XML_ERROR_NO_MEMORY; + entity = (ENTITY *)lookup(&dtd.generalEntities, name, 0); + poolDiscard(&temp2Pool); + if (!entity) { + if (dtd.complete) { + if (enc == encoding) + eventPtr = ptr; + return XML_ERROR_UNDEFINED_ENTITY; + } + } + else if (entity->open) { + if (enc == encoding) + eventPtr = ptr; + return XML_ERROR_RECURSIVE_ENTITY_REF; + } + else if (entity->notation) { + if (enc == encoding) + eventPtr = ptr; + return XML_ERROR_BINARY_ENTITY_REF; + } + else if (!entity->textPtr) { + if (enc == encoding) + eventPtr = ptr; + return XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF; + } + else { + enum XML_Error result; + const XML_Char *textEnd = entity->textPtr + entity->textLen; + entity->open = 1; + result = appendAttributeValue(parser, internalEncoding, isCdata, (char *)entity->textPtr, (char *)textEnd, pool); + entity->open = 0; + if (result) + return result; + } + } + break; + default: + if (enc == encoding) + eventPtr = ptr; + return XML_ERROR_UNEXPECTED_STATE; + } + ptr = next; + } + /* not reached */ +} + +static +enum XML_Error storeEntityValue(XML_Parser parser, + const ENCODING *enc, + const char *entityTextPtr, + const char *entityTextEnd) +{ + STRING_POOL *pool = &(dtd.pool); + for (;;) { + const char *next; + int tok = XmlEntityValueTok(enc, entityTextPtr, entityTextEnd, &next); + switch (tok) { + case XML_TOK_PARAM_ENTITY_REF: +#ifdef XML_DTD + if (parentParser || enc != encoding) { + enum XML_Error result; + const XML_Char *name; + ENTITY *entity; + name = poolStoreString(&tempPool, enc, + entityTextPtr + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (!name) + return XML_ERROR_NO_MEMORY; + entity = (ENTITY *)lookup(&dtd.paramEntities, name, 0); + poolDiscard(&tempPool); + if (!entity) { + if (enc == encoding) + eventPtr = entityTextPtr; + return XML_ERROR_UNDEFINED_ENTITY; + } + if (entity->open) { + if (enc == encoding) + eventPtr = entityTextPtr; + return XML_ERROR_RECURSIVE_ENTITY_REF; + } + if (entity->systemId) { + if (enc == encoding) + eventPtr = entityTextPtr; + return XML_ERROR_PARAM_ENTITY_REF; + } + entity->open = 1; + result = storeEntityValue(parser, + internalEncoding, + (char *)entity->textPtr, + (char *)(entity->textPtr + entity->textLen)); + entity->open = 0; + if (result) + return result; + break; + } +#endif /* XML_DTD */ + eventPtr = entityTextPtr; + return XML_ERROR_SYNTAX; + case XML_TOK_NONE: + return XML_ERROR_NONE; + case XML_TOK_ENTITY_REF: + case XML_TOK_DATA_CHARS: + if (!poolAppend(pool, enc, entityTextPtr, next)) + return XML_ERROR_NO_MEMORY; + break; + case XML_TOK_TRAILING_CR: + next = entityTextPtr + enc->minBytesPerChar; + /* fall through */ + case XML_TOK_DATA_NEWLINE: + if (pool->end == pool->ptr && !poolGrow(pool)) + return XML_ERROR_NO_MEMORY; + *(pool->ptr)++ = 0xA; + break; + case XML_TOK_CHAR_REF: + { + XML_Char buf[XML_ENCODE_MAX]; + int i; + int n = XmlCharRefNumber(enc, entityTextPtr); + if (n < 0) { + if (enc == encoding) + eventPtr = entityTextPtr; + return XML_ERROR_BAD_CHAR_REF; + } + n = XmlEncode(n, (ICHAR *)buf); + if (!n) { + if (enc == encoding) + eventPtr = entityTextPtr; + return XML_ERROR_BAD_CHAR_REF; + } + for (i = 0; i < n; i++) { + if (pool->end == pool->ptr && !poolGrow(pool)) + return XML_ERROR_NO_MEMORY; + *(pool->ptr)++ = buf[i]; + } + } + break; + case XML_TOK_PARTIAL: + if (enc == encoding) + eventPtr = entityTextPtr; + return XML_ERROR_INVALID_TOKEN; + case XML_TOK_INVALID: + if (enc == encoding) + eventPtr = next; + return XML_ERROR_INVALID_TOKEN; + default: + if (enc == encoding) + eventPtr = entityTextPtr; + return XML_ERROR_UNEXPECTED_STATE; + } + entityTextPtr = next; + } + /* not reached */ +} + +static void +normalizeLines(XML_Char *s) +{ + XML_Char *p; + for (;; s++) { + if (*s == XML_T('\0')) + return; + if (*s == 0xD) + break; + } + p = s; + do { + if (*s == 0xD) { + *p++ = 0xA; + if (*++s == 0xA) + s++; + } + else + *p++ = *s++; + } while (*s); + *p = XML_T('\0'); +} + +static int +reportProcessingInstruction(XML_Parser parser, const ENCODING *enc, const char *start, const char *end) +{ + const XML_Char *target; + XML_Char *data; + const char *tem; + if (!processingInstructionHandler) { + if (defaultHandler) + reportDefault(parser, enc, start, end); + return 1; + } + start += enc->minBytesPerChar * 2; + tem = start + XmlNameLength(enc, start); + target = poolStoreString(&tempPool, enc, start, tem); + if (!target) + return 0; + poolFinish(&tempPool); + data = poolStoreString(&tempPool, enc, + XmlSkipS(enc, tem), + end - enc->minBytesPerChar*2); + if (!data) + return 0; + normalizeLines(data); + processingInstructionHandler(handlerArg, target, data); + poolClear(&tempPool); + return 1; +} + +static int +reportComment(XML_Parser parser, const ENCODING *enc, const char *start, const char *end) +{ + XML_Char *data; + if (!commentHandler) { + if (defaultHandler) + reportDefault(parser, enc, start, end); + return 1; + } + data = poolStoreString(&tempPool, + enc, + start + enc->minBytesPerChar * 4, + end - enc->minBytesPerChar * 3); + if (!data) + return 0; + normalizeLines(data); + commentHandler(handlerArg, data); + poolClear(&tempPool); + return 1; +} + +static void +reportDefault(XML_Parser parser, const ENCODING *enc, const char *s, const char *end) +{ + if (MUST_CONVERT(enc, s)) { + const char **eventPP; + const char **eventEndPP; + if (enc == encoding) { + eventPP = &eventPtr; + eventEndPP = &eventEndPtr; + } + else { + eventPP = &(openInternalEntities->internalEventPtr); + eventEndPP = &(openInternalEntities->internalEventEndPtr); + } + do { + ICHAR *dataPtr = (ICHAR *)dataBuf; + XmlConvert(enc, &s, end, &dataPtr, (ICHAR *)dataBufEnd); + *eventEndPP = s; + defaultHandler(handlerArg, dataBuf, dataPtr - (ICHAR *)dataBuf); + *eventPP = s; + } while (s != end); + } + else + defaultHandler(handlerArg, (XML_Char *)s, (XML_Char *)end - (XML_Char *)s); +} + + +static int +defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *attId, int isCdata, + int isId, const XML_Char *value, XML_Parser parser) +{ + DEFAULT_ATTRIBUTE *att; + if (value || isId) { + /* The handling of default attributes gets messed up if we have + a default which duplicates a non-default. */ + int i; + for (i = 0; i < type->nDefaultAtts; i++) + if (attId == type->defaultAtts[i].id) + return 1; + if (isId && !type->idAtt && !attId->xmlns) + type->idAtt = attId; + } + if (type->nDefaultAtts == type->allocDefaultAtts) { + if (type->allocDefaultAtts == 0) { + type->allocDefaultAtts = 8; + type->defaultAtts = MALLOC(type->allocDefaultAtts*sizeof(DEFAULT_ATTRIBUTE)); + } + else { + type->allocDefaultAtts *= 2; + type->defaultAtts = REALLOC(type->defaultAtts, + type->allocDefaultAtts*sizeof(DEFAULT_ATTRIBUTE)); + } + if (!type->defaultAtts) + return 0; + } + att = type->defaultAtts + type->nDefaultAtts; + att->id = attId; + att->value = value; + att->isCdata = isCdata; + if (!isCdata) + attId->maybeTokenized = 1; + type->nDefaultAtts += 1; + return 1; +} + +static int setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *elementType) +{ + const XML_Char *name; + for (name = elementType->name; *name; name++) { + if (*name == XML_T(':')) { + PREFIX *prefix; + const XML_Char *s; + for (s = elementType->name; s != name; s++) { + if (!poolAppendChar(&dtd.pool, *s)) + return 0; + } + if (!poolAppendChar(&dtd.pool, XML_T('\0'))) + return 0; + prefix = (PREFIX *)lookup(&dtd.prefixes, poolStart(&dtd.pool), sizeof(PREFIX)); + if (!prefix) + return 0; + if (prefix->name == poolStart(&dtd.pool)) + poolFinish(&dtd.pool); + else + poolDiscard(&dtd.pool); + elementType->prefix = prefix; + + } + } + return 1; +} + +static ATTRIBUTE_ID * +getAttributeId(XML_Parser parser, const ENCODING *enc, const char *start, const char *end) +{ + ATTRIBUTE_ID *id; + const XML_Char *name; + if (!poolAppendChar(&dtd.pool, XML_T('\0'))) + return 0; + name = poolStoreString(&dtd.pool, enc, start, end); + if (!name) + return 0; + ++name; + id = (ATTRIBUTE_ID *)lookup(&dtd.attributeIds, name, sizeof(ATTRIBUTE_ID)); + if (!id) + return 0; + if (id->name != name) + poolDiscard(&dtd.pool); + else { + poolFinish(&dtd.pool); + if (!ns) + ; + else if (name[0] == 'x' + && name[1] == 'm' + && name[2] == 'l' + && name[3] == 'n' + && name[4] == 's' + && (name[5] == XML_T('\0') || name[5] == XML_T(':'))) { + if (name[5] == '\0') + id->prefix = &dtd.defaultPrefix; + else + id->prefix = (PREFIX *)lookup(&dtd.prefixes, name + 6, sizeof(PREFIX)); + id->xmlns = 1; + } + else { + int i; + for (i = 0; name[i]; i++) { + if (name[i] == XML_T(':')) { + int j; + for (j = 0; j < i; j++) { + if (!poolAppendChar(&dtd.pool, name[j])) + return 0; + } + if (!poolAppendChar(&dtd.pool, XML_T('\0'))) + return 0; + id->prefix = (PREFIX *)lookup(&dtd.prefixes, poolStart(&dtd.pool), sizeof(PREFIX)); + if (id->prefix->name == poolStart(&dtd.pool)) + poolFinish(&dtd.pool); + else + poolDiscard(&dtd.pool); + break; + } + } + } + } + return id; +} + +#define CONTEXT_SEP XML_T('\f') + +static +const XML_Char *getContext(XML_Parser parser) +{ + HASH_TABLE_ITER iter; + int needSep = 0; + + if (dtd.defaultPrefix.binding) { + int i; + int len; + if (!poolAppendChar(&tempPool, XML_T('='))) + return 0; + len = dtd.defaultPrefix.binding->uriLen; + if (namespaceSeparator != XML_T('\0')) + len--; + for (i = 0; i < len; i++) + if (!poolAppendChar(&tempPool, dtd.defaultPrefix.binding->uri[i])) + return 0; + needSep = 1; + } + + hashTableIterInit(&iter, &(dtd.prefixes)); + for (;;) { + int i; + int len; + const XML_Char *s; + PREFIX *prefix = (PREFIX *)hashTableIterNext(&iter); + if (!prefix) + break; + if (!prefix->binding) + continue; + if (needSep && !poolAppendChar(&tempPool, CONTEXT_SEP)) + return 0; + for (s = prefix->name; *s; s++) + if (!poolAppendChar(&tempPool, *s)) + return 0; + if (!poolAppendChar(&tempPool, XML_T('='))) + return 0; + len = prefix->binding->uriLen; + if (namespaceSeparator != XML_T('\0')) + len--; + for (i = 0; i < len; i++) + if (!poolAppendChar(&tempPool, prefix->binding->uri[i])) + return 0; + needSep = 1; + } + + + hashTableIterInit(&iter, &(dtd.generalEntities)); + for (;;) { + const XML_Char *s; + ENTITY *e = (ENTITY *)hashTableIterNext(&iter); + if (!e) + break; + if (!e->open) + continue; + if (needSep && !poolAppendChar(&tempPool, CONTEXT_SEP)) + return 0; + for (s = e->name; *s; s++) + if (!poolAppendChar(&tempPool, *s)) + return 0; + needSep = 1; + } + + if (!poolAppendChar(&tempPool, XML_T('\0'))) + return 0; + return tempPool.start; +} + +static +int setContext(XML_Parser parser, const XML_Char *context) +{ + const XML_Char *s = context; + + while (*context != XML_T('\0')) { + if (*s == CONTEXT_SEP || *s == XML_T('\0')) { + ENTITY *e; + if (!poolAppendChar(&tempPool, XML_T('\0'))) + return 0; + e = (ENTITY *)lookup(&dtd.generalEntities, poolStart(&tempPool), 0); + if (e) + e->open = 1; + if (*s != XML_T('\0')) + s++; + context = s; + poolDiscard(&tempPool); + } + else if (*s == '=') { + PREFIX *prefix; + if (poolLength(&tempPool) == 0) + prefix = &dtd.defaultPrefix; + else { + if (!poolAppendChar(&tempPool, XML_T('\0'))) + return 0; + prefix = (PREFIX *)lookup(&dtd.prefixes, poolStart(&tempPool), sizeof(PREFIX)); + if (!prefix) + return 0; + if (prefix->name == poolStart(&tempPool)) { + prefix->name = poolCopyString(&dtd.pool, prefix->name); + if (!prefix->name) + return 0; + } + poolDiscard(&tempPool); + } + for (context = s + 1; *context != CONTEXT_SEP && *context != XML_T('\0'); context++) + if (!poolAppendChar(&tempPool, *context)) + return 0; + if (!poolAppendChar(&tempPool, XML_T('\0'))) + return 0; + if (!addBinding(parser, prefix, 0, poolStart(&tempPool), &inheritedBindings)) + return 0; + poolDiscard(&tempPool); + if (*context != XML_T('\0')) + ++context; + s = context; + } + else { + if (!poolAppendChar(&tempPool, *s)) + return 0; + s++; + } + } + return 1; +} + + +static +void normalizePublicId(XML_Char *publicId) +{ + XML_Char *p = publicId; + XML_Char *s; + for (s = publicId; *s; s++) { + switch (*s) { + case 0x20: + case 0xD: + case 0xA: + if (p != publicId && p[-1] != 0x20) + *p++ = 0x20; + break; + default: + *p++ = *s; + } + } + if (p != publicId && p[-1] == 0x20) + --p; + *p = XML_T('\0'); +} + +static int dtdInit(DTD *p, XML_Parser parser) +{ + XML_Memory_Handling_Suite *ms = &((Parser *) parser)->m_mem; + poolInit(&(p->pool), ms); + hashTableInit(&(p->generalEntities), ms); + hashTableInit(&(p->elementTypes), ms); + hashTableInit(&(p->attributeIds), ms); + hashTableInit(&(p->prefixes), ms); + p->complete = 1; + p->standalone = 0; +#ifdef XML_DTD + hashTableInit(&(p->paramEntities), ms); +#endif /* XML_DTD */ + p->defaultPrefix.name = 0; + p->defaultPrefix.binding = 0; + + p->in_eldecl = 0; + p->scaffIndex = 0; + p->scaffLevel = 0; + p->scaffold = 0; + p->contentStringLen = 0; + p->scaffSize = 0; + p->scaffCount = 0; + + return 1; +} + +#ifdef XML_DTD + +static void dtdSwap(DTD *p1, DTD *p2) +{ + DTD tem; + memcpy(&tem, p1, sizeof(DTD)); + memcpy(p1, p2, sizeof(DTD)); + memcpy(p2, &tem, sizeof(DTD)); +} + +#endif /* XML_DTD */ + +static void dtdDestroy(DTD *p, XML_Parser parser) +{ + HASH_TABLE_ITER iter; + hashTableIterInit(&iter, &(p->elementTypes)); + for (;;) { + ELEMENT_TYPE *e = (ELEMENT_TYPE *)hashTableIterNext(&iter); + if (!e) + break; + if (e->allocDefaultAtts != 0) + FREE(e->defaultAtts); + } + hashTableDestroy(&(p->generalEntities)); +#ifdef XML_DTD + hashTableDestroy(&(p->paramEntities)); +#endif /* XML_DTD */ + hashTableDestroy(&(p->elementTypes)); + hashTableDestroy(&(p->attributeIds)); + hashTableDestroy(&(p->prefixes)); + poolDestroy(&(p->pool)); + if (p->scaffIndex) + FREE(p->scaffIndex); + if (p->scaffold) + FREE(p->scaffold); +} + +/* Do a deep copy of the DTD. Return 0 for out of memory; non-zero otherwise. +The new DTD has already been initialized. */ + +static int dtdCopy(DTD *newDtd, const DTD *oldDtd, XML_Parser parser) +{ + HASH_TABLE_ITER iter; + + /* Copy the prefix table. */ + + hashTableIterInit(&iter, &(oldDtd->prefixes)); + for (;;) { + const XML_Char *name; + const PREFIX *oldP = (PREFIX *)hashTableIterNext(&iter); + if (!oldP) + break; + name = poolCopyString(&(newDtd->pool), oldP->name); + if (!name) + return 0; + if (!lookup(&(newDtd->prefixes), name, sizeof(PREFIX))) + return 0; + } + + hashTableIterInit(&iter, &(oldDtd->attributeIds)); + + /* Copy the attribute id table. */ + + for (;;) { + ATTRIBUTE_ID *newA; + const XML_Char *name; + const ATTRIBUTE_ID *oldA = (ATTRIBUTE_ID *)hashTableIterNext(&iter); + + if (!oldA) + break; + /* Remember to allocate the scratch byte before the name. */ + if (!poolAppendChar(&(newDtd->pool), XML_T('\0'))) + return 0; + name = poolCopyString(&(newDtd->pool), oldA->name); + if (!name) + return 0; + ++name; + newA = (ATTRIBUTE_ID *)lookup(&(newDtd->attributeIds), name, sizeof(ATTRIBUTE_ID)); + if (!newA) + return 0; + newA->maybeTokenized = oldA->maybeTokenized; + if (oldA->prefix) { + newA->xmlns = oldA->xmlns; + if (oldA->prefix == &oldDtd->defaultPrefix) + newA->prefix = &newDtd->defaultPrefix; + else + newA->prefix = (PREFIX *)lookup(&(newDtd->prefixes), oldA->prefix->name, 0); + } + } + + /* Copy the element type table. */ + + hashTableIterInit(&iter, &(oldDtd->elementTypes)); + + for (;;) { + int i; + ELEMENT_TYPE *newE; + const XML_Char *name; + const ELEMENT_TYPE *oldE = (ELEMENT_TYPE *)hashTableIterNext(&iter); + if (!oldE) + break; + name = poolCopyString(&(newDtd->pool), oldE->name); + if (!name) + return 0; + newE = (ELEMENT_TYPE *)lookup(&(newDtd->elementTypes), name, sizeof(ELEMENT_TYPE)); + if (!newE) + return 0; + if (oldE->nDefaultAtts) { + newE->defaultAtts = (DEFAULT_ATTRIBUTE *)MALLOC(oldE->nDefaultAtts * sizeof(DEFAULT_ATTRIBUTE)); + if (!newE->defaultAtts) + return 0; + } + if (oldE->idAtt) + newE->idAtt = (ATTRIBUTE_ID *)lookup(&(newDtd->attributeIds), oldE->idAtt->name, 0); + newE->allocDefaultAtts = newE->nDefaultAtts = oldE->nDefaultAtts; + if (oldE->prefix) + newE->prefix = (PREFIX *)lookup(&(newDtd->prefixes), oldE->prefix->name, 0); + for (i = 0; i < newE->nDefaultAtts; i++) { + newE->defaultAtts[i].id = (ATTRIBUTE_ID *)lookup(&(newDtd->attributeIds), oldE->defaultAtts[i].id->name, 0); + newE->defaultAtts[i].isCdata = oldE->defaultAtts[i].isCdata; + if (oldE->defaultAtts[i].value) { + newE->defaultAtts[i].value = poolCopyString(&(newDtd->pool), oldE->defaultAtts[i].value); + if (!newE->defaultAtts[i].value) + return 0; + } + else + newE->defaultAtts[i].value = 0; + } + } + + /* Copy the entity tables. */ + if (!copyEntityTable(&(newDtd->generalEntities), + &(newDtd->pool), + &(oldDtd->generalEntities), parser)) + return 0; + +#ifdef XML_DTD + if (!copyEntityTable(&(newDtd->paramEntities), + &(newDtd->pool), + &(oldDtd->paramEntities), parser)) + return 0; +#endif /* XML_DTD */ + + newDtd->complete = oldDtd->complete; + newDtd->standalone = oldDtd->standalone; + + /* Don't want deep copying for scaffolding */ + newDtd->in_eldecl = oldDtd->in_eldecl; + newDtd->scaffold = oldDtd->scaffold; + newDtd->contentStringLen = oldDtd->contentStringLen; + newDtd->scaffSize = oldDtd->scaffSize; + newDtd->scaffLevel = oldDtd->scaffLevel; + newDtd->scaffIndex = oldDtd->scaffIndex; + + return 1; +} /* End dtdCopy */ + +static int copyEntityTable(HASH_TABLE *newTable, + STRING_POOL *newPool, + const HASH_TABLE *oldTable, + XML_Parser parser) +{ + HASH_TABLE_ITER iter; + const XML_Char *cachedOldBase = 0; + const XML_Char *cachedNewBase = 0; + itkExpatUnused(parser); + + hashTableIterInit(&iter, oldTable); + + for (;;) { + ENTITY *newE; + const XML_Char *name; + const ENTITY *oldE = (ENTITY *)hashTableIterNext(&iter); + if (!oldE) + break; + name = poolCopyString(newPool, oldE->name); + if (!name) + return 0; + newE = (ENTITY *)lookup(newTable, name, sizeof(ENTITY)); + if (!newE) + return 0; + if (oldE->systemId) { + const XML_Char *tem = poolCopyString(newPool, oldE->systemId); + if (!tem) + return 0; + newE->systemId = tem; + if (oldE->base) { + if (oldE->base == cachedOldBase) + newE->base = cachedNewBase; + else { + cachedOldBase = oldE->base; + tem = poolCopyString(newPool, cachedOldBase); + if (!tem) + return 0; + cachedNewBase = newE->base = tem; + } + } + } + else { + const XML_Char *tem = poolCopyStringN(newPool, oldE->textPtr, oldE->textLen); + if (!tem) + return 0; + newE->textPtr = tem; + newE->textLen = oldE->textLen; + } + if (oldE->notation) { + const XML_Char *tem = poolCopyString(newPool, oldE->notation); + if (!tem) + return 0; + newE->notation = tem; + } + } + return 1; +} + +#define INIT_SIZE 64 + +static +int keyeq(KEY s1, KEY s2) +{ + for (; *s1 == *s2; s1++, s2++) + if (*s1 == 0) + return 1; + return 0; +} + +static +unsigned long hash(KEY s) +{ + unsigned long h = 0; + while (*s) + h = (h << 5) + h + (unsigned char)*s++; + return h; +} + +static +NAMED *lookup(HASH_TABLE *table, KEY name, size_t createSize) +{ + size_t i; + if (table->size == 0) { + size_t tsize; + + if (!createSize) + return 0; + tsize = INIT_SIZE * sizeof(NAMED *); + table->v = table->mem->malloc_fcn(tsize); + if (!table->v) + return 0; + memset(table->v, 0, tsize); + table->size = INIT_SIZE; + table->usedLim = INIT_SIZE / 2; + i = hash(name) & (table->size - 1); + } + else { + unsigned long h = hash(name); + for (i = h & (table->size - 1); + table->v[i]; + i == 0 ? i = table->size - 1 : --i) { + if (keyeq(name, table->v[i]->name)) + return table->v[i]; + } + if (!createSize) + return 0; + if (table->used == table->usedLim) { + /* check for overflow */ + size_t newSize = table->size * 2; + size_t tsize = newSize * sizeof(NAMED *); + NAMED **newV = table->mem->malloc_fcn(tsize); + if (!newV) + return 0; + memset(newV, 0, tsize); + for (i = 0; i < table->size; i++) + if (table->v[i]) { + size_t j; + for (j = hash(table->v[i]->name) & (newSize - 1); + newV[j]; + j == 0 ? j = newSize - 1 : --j) + ; + newV[j] = table->v[i]; + } + table->mem->free_fcn(table->v); + table->v = newV; + table->size = newSize; + table->usedLim = newSize/2; + for (i = h & (table->size - 1); + table->v[i]; + i == 0 ? i = table->size - 1 : --i) + ; + } + } + table->v[i] = table->mem->malloc_fcn(createSize); + if (!table->v[i]) + return 0; + memset(table->v[i], 0, createSize); + table->v[i]->name = name; + (table->used)++; + return table->v[i]; +} + +static +void hashTableDestroy(HASH_TABLE *table) +{ + size_t i; + for (i = 0; i < table->size; i++) { + NAMED *p = table->v[i]; + if (p) + table->mem->free_fcn(p); + } + if (table->v) + table->mem->free_fcn(table->v); +} + +static +void hashTableInit(HASH_TABLE *p, XML_Memory_Handling_Suite *ms) +{ + p->size = 0; + p->usedLim = 0; + p->used = 0; + p->v = 0; + p->mem = ms; +} + +static +void hashTableIterInit(HASH_TABLE_ITER *iter, const HASH_TABLE *table) +{ + iter->p = table->v; + iter->end = iter->p + table->size; +} + +static +NAMED *hashTableIterNext(HASH_TABLE_ITER *iter) +{ + while (iter->p != iter->end) { + NAMED *tem = *(iter->p)++; + if (tem) + return tem; + } + return 0; +} + + +static +void poolInit(STRING_POOL *pool, XML_Memory_Handling_Suite *ms) +{ + pool->blocks = 0; + pool->freeBlocks = 0; + pool->start = 0; + pool->ptr = 0; + pool->end = 0; + pool->mem = ms; +} + +static +void poolClear(STRING_POOL *pool) +{ + if (!pool->freeBlocks) + pool->freeBlocks = pool->blocks; + else { + BLOCK *p = pool->blocks; + while (p) { + BLOCK *tem = p->next; + p->next = pool->freeBlocks; + pool->freeBlocks = p; + p = tem; + } + } + pool->blocks = 0; + pool->start = 0; + pool->ptr = 0; + pool->end = 0; +} + +static +void poolDestroy(STRING_POOL *pool) +{ + BLOCK *p = pool->blocks; + while (p) { + BLOCK *tem = p->next; + pool->mem->free_fcn(p); + p = tem; + } + pool->blocks = 0; + p = pool->freeBlocks; + while (p) { + BLOCK *tem = p->next; + pool->mem->free_fcn(p); + p = tem; + } + pool->freeBlocks = 0; + pool->ptr = 0; + pool->start = 0; + pool->end = 0; +} + +static +XML_Char *poolAppend(STRING_POOL *pool, const ENCODING *enc, + const char *ptr, const char *end) +{ + if (!pool->ptr && !poolGrow(pool)) + return 0; + for (;;) { + XmlConvert(enc, &ptr, end, (ICHAR **)&(pool->ptr), (ICHAR *)pool->end); + if (ptr == end) + break; + if (!poolGrow(pool)) + return 0; + } + return pool->start; +} + +static const XML_Char *poolCopyString(STRING_POOL *pool, const XML_Char *s) +{ + do { + if (!poolAppendChar(pool, *s)) + return 0; + } while (*s++); + s = pool->start; + poolFinish(pool); + return s; +} + +static const XML_Char *poolCopyStringN(STRING_POOL *pool, const XML_Char *s, int n) +{ + if (!pool->ptr && !poolGrow(pool)) + return 0; + for (; n > 0; --n, s++) { + if (!poolAppendChar(pool, *s)) + return 0; + + } + s = pool->start; + poolFinish(pool); + return s; +} + +static +const XML_Char *poolAppendString(STRING_POOL *pool, const XML_Char *s) +{ + while (*s) { + if (!poolAppendChar(pool, *s)) + return 0; + s++; + } + return pool->start; +} /* End poolAppendString */ + +static +XML_Char *poolStoreString(STRING_POOL *pool, const ENCODING *enc, + const char *ptr, const char *end) +{ + if (!poolAppend(pool, enc, ptr, end)) + return 0; + if (pool->ptr == pool->end && !poolGrow(pool)) + return 0; + *(pool->ptr)++ = 0; + return pool->start; +} + +static +int poolGrow(STRING_POOL *pool) +{ + if (pool->freeBlocks) { + if (pool->start == 0) { + pool->blocks = pool->freeBlocks; + pool->freeBlocks = pool->freeBlocks->next; + pool->blocks->next = 0; + pool->start = pool->blocks->s; + pool->end = pool->start + pool->blocks->size; + pool->ptr = pool->start; + return 1; + } + if (pool->end - pool->start < pool->freeBlocks->size) { + BLOCK *tem = pool->freeBlocks->next; + pool->freeBlocks->next = pool->blocks; + pool->blocks = pool->freeBlocks; + pool->freeBlocks = tem; + memcpy(pool->blocks->s, pool->start, (pool->end - pool->start) * sizeof(XML_Char)); + pool->ptr = pool->blocks->s + (pool->ptr - pool->start); + pool->start = pool->blocks->s; + pool->end = pool->start + pool->blocks->size; + return 1; + } + } + if (pool->blocks && pool->start == pool->blocks->s) { + int blockSize = (pool->end - pool->start)*2; + pool->blocks = pool->mem->realloc_fcn(pool->blocks, offsetof(BLOCK, s) + blockSize * sizeof(XML_Char)); + if (!pool->blocks) + return 0; + pool->blocks->size = blockSize; + pool->ptr = pool->blocks->s + (pool->ptr - pool->start); + pool->start = pool->blocks->s; + pool->end = pool->start + blockSize; + } + else { + BLOCK *tem; + int blockSize = pool->end - pool->start; + if (blockSize < INIT_BLOCK_SIZE) + blockSize = INIT_BLOCK_SIZE; + else + blockSize *= 2; + tem = pool->mem->malloc_fcn(offsetof(BLOCK, s) + blockSize * sizeof(XML_Char)); + if (!tem) + return 0; + tem->size = blockSize; + tem->next = pool->blocks; + pool->blocks = tem; + if (pool->ptr != pool->start) + memcpy(tem->s, pool->start, (pool->ptr - pool->start) * sizeof(XML_Char)); + pool->ptr = tem->s + (pool->ptr - pool->start); + pool->start = tem->s; + pool->end = tem->s + blockSize; + } + return 1; +} + +static int +nextScaffoldPart(XML_Parser parser) +{ + CONTENT_SCAFFOLD * me; + int next; + + if (! dtd.scaffIndex) { + dtd.scaffIndex = MALLOC(groupSize * sizeof(int)); + if (! dtd.scaffIndex) + return -1; + dtd.scaffIndex[0] = 0; + } + + if (dtd.scaffCount >= dtd.scaffSize) { + if (dtd.scaffold) { + dtd.scaffSize *= 2; + dtd.scaffold = (CONTENT_SCAFFOLD *) REALLOC(dtd.scaffold, + dtd.scaffSize * sizeof(CONTENT_SCAFFOLD)); + } + else { + dtd.scaffSize = 32; + dtd.scaffold = (CONTENT_SCAFFOLD *) MALLOC(dtd.scaffSize * sizeof(CONTENT_SCAFFOLD)); + } + if (! dtd.scaffold) + return -1; + } + next = dtd.scaffCount++; + me = &dtd.scaffold[next]; + if (dtd.scaffLevel) { + CONTENT_SCAFFOLD *parent = &dtd.scaffold[dtd.scaffIndex[dtd.scaffLevel - 1]]; + if (parent->lastchild) { + dtd.scaffold[parent->lastchild].nextsib = next; + } + if (! parent->childcnt) + parent->firstchild = next; + parent->lastchild = next; + parent->childcnt++; + } + me->firstchild = me->lastchild = me->childcnt = me->nextsib = 0; + return next; +} /* End nextScaffoldPart */ + +static void +build_node (XML_Parser parser, + int src_node, + XML_Content *dest, + XML_Content **contpos, + char **strpos) +{ + dest->type = dtd.scaffold[src_node].type; + dest->quant = dtd.scaffold[src_node].quant; + if (dest->type == XML_CTYPE_NAME) { + const char *src; + dest->name = *strpos; + src = dtd.scaffold[src_node].name; + for (;;) { + *(*strpos)++ = *src; + if (! *src) + break; + src++; + } + dest->numchildren = 0; + dest->children = 0; + } + else { + unsigned int i; + int cn; + dest->numchildren = dtd.scaffold[src_node].childcnt; + dest->children = *contpos; + *contpos += dest->numchildren; + for (i = 0, cn = dtd.scaffold[src_node].firstchild; + i < dest->numchildren; + i++, cn = dtd.scaffold[cn].nextsib) { + build_node(parser, cn, &(dest->children[i]), contpos, strpos); + } + dest->name = 0; + } +} /* End build_node */ + +static XML_Content * +build_model (XML_Parser parser) +{ + XML_Content *ret; + XML_Content *cpos; + char * str; + int allocsize = dtd.scaffCount * sizeof(XML_Content) + dtd.contentStringLen; + + ret = MALLOC(allocsize); + if (! ret) + return 0; + + str = (char *) (&ret[dtd.scaffCount]); + cpos = &ret[1]; + + build_node(parser, 0, ret, &cpos, &str); + return ret; +} /* End build_model */ + +static ELEMENT_TYPE * +getElementType(XML_Parser parser, + const ENCODING *enc, + const char *ptr, + const char *end) +{ + const XML_Char *name = poolStoreString(&dtd.pool, enc, ptr, end); + ELEMENT_TYPE *ret; + + if (! name) + return 0; + ret = (ELEMENT_TYPE *) lookup(&dtd.elementTypes, name, sizeof(ELEMENT_TYPE)); + if (! ret) + return 0; + if (ret->name != name) + poolDiscard(&dtd.pool); + else { + poolFinish(&dtd.pool); + if (!setElementTypePrefix(parser, ret)) + return 0; + } + return ret; +} /* End getElementType */ diff --git a/Utilities/ITK/Utilities/expat/xmlrole.c b/Utilities/ITK/Utilities/expat/xmlrole.c new file mode 100644 index 0000000000000000000000000000000000000000..c4da174353fe5b05ddfdee4d5d0a47a718de44d1 --- /dev/null +++ b/Utilities/ITK/Utilities/expat/xmlrole.c @@ -0,0 +1,1400 @@ +/* +Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd +See the file COPYING for copying permission. +*/ + +static char RCSId[] + = "$Header: /cvsroot/Insight/Insight/Utilities/expat/xmlrole.c,v 1.3 2006/02/02 23:05:33 malaterre Exp $"; +const char* GetVTKEXpatXMLRole_RCSId(void) +{ + return RCSId; +} + +#include "expatConfig.h" + +#include "xmlrole.h" +#include "ascii.h" + +/* Doesn't check: + + that ,| are not mixed in a model group + content of literals + +*/ + +static const char KW_ANY[] = { ASCII_A, ASCII_N, ASCII_Y, '\0' }; +static const char KW_ATTLIST[] = { ASCII_A, ASCII_T, ASCII_T, ASCII_L, ASCII_I, ASCII_S, ASCII_T, '\0' }; +static const char KW_CDATA[] = { ASCII_C, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0' }; +static const char KW_DOCTYPE[] = { ASCII_D, ASCII_O, ASCII_C, ASCII_T, ASCII_Y, ASCII_P, ASCII_E, '\0' }; +static const char KW_ELEMENT[] = { ASCII_E, ASCII_L, ASCII_E, ASCII_M, ASCII_E, ASCII_N, ASCII_T, '\0' }; +static const char KW_EMPTY[] = { ASCII_E, ASCII_M, ASCII_P, ASCII_T, ASCII_Y, '\0' }; +static const char KW_ENTITIES[] = { ASCII_E, ASCII_N, ASCII_T, ASCII_I, ASCII_T, ASCII_I, ASCII_E, ASCII_S, '\0' }; +static const char KW_ENTITY[] = { ASCII_E, ASCII_N, ASCII_T, ASCII_I, ASCII_T, ASCII_Y, '\0' }; +static const char KW_FIXED[] = { ASCII_F, ASCII_I, ASCII_X, ASCII_E, ASCII_D, '\0' }; +static const char KW_ID[] = { ASCII_I, ASCII_D, '\0' }; +static const char KW_IDREF[] = { ASCII_I, ASCII_D, ASCII_R, ASCII_E, ASCII_F, '\0' }; +static const char KW_IDREFS[] = { ASCII_I, ASCII_D, ASCII_R, ASCII_E, ASCII_F, ASCII_S, '\0' }; +static const char KW_IGNORE[] = { ASCII_I, ASCII_G, ASCII_N, ASCII_O, ASCII_R, ASCII_E, '\0' }; +static const char KW_IMPLIED[] = { ASCII_I, ASCII_M, ASCII_P, ASCII_L, ASCII_I, ASCII_E, ASCII_D, '\0' }; +static const char KW_INCLUDE[] = { ASCII_I, ASCII_N, ASCII_C, ASCII_L, ASCII_U, ASCII_D, ASCII_E, '\0' }; +static const char KW_NDATA[] = { ASCII_N, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0' }; +static const char KW_NMTOKEN[] = { ASCII_N, ASCII_M, ASCII_T, ASCII_O, ASCII_K, ASCII_E, ASCII_N, '\0' }; +static const char KW_NMTOKENS[] = { ASCII_N, ASCII_M, ASCII_T, ASCII_O, ASCII_K, ASCII_E, ASCII_N, ASCII_S, '\0' }; +static const char KW_NOTATION[] = { ASCII_N, ASCII_O, ASCII_T, ASCII_A, ASCII_T, ASCII_I, ASCII_O, ASCII_N, '\0' }; +static const char KW_PCDATA[] = { ASCII_P, ASCII_C, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0' }; +static const char KW_PUBLIC[] = { ASCII_P, ASCII_U, ASCII_B, ASCII_L, ASCII_I, ASCII_C, '\0' }; +static const char KW_REQUIRED[] = { ASCII_R, ASCII_E, ASCII_Q, ASCII_U, ASCII_I, ASCII_R, ASCII_E, ASCII_D, '\0' }; +static const char KW_SYSTEM[] = { ASCII_S, ASCII_Y, ASCII_S, ASCII_T, ASCII_E, ASCII_M, '\0' }; + +#ifndef MIN_BYTES_PER_CHAR +#define MIN_BYTES_PER_CHAR(enc) ((enc)->minBytesPerChar) +#endif + +#ifdef XML_DTD +#define setTopLevel(state) \ + ((state)->handler = ((state)->documentEntity \ + ? internalSubset \ + : externalSubset1)) +#else /* not XML_DTD */ +#define setTopLevel(state) ((state)->handler = internalSubset) +#endif /* not XML_DTD */ + +typedef int PROLOG_HANDLER(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc); + +static PROLOG_HANDLER + prolog0, prolog1, prolog2, + doctype0, doctype1, doctype2, doctype3, doctype4, doctype5, + internalSubset, + entity0, entity1, entity2, entity3, entity4, entity5, entity6, + entity7, entity8, entity9, + notation0, notation1, notation2, notation3, notation4, + attlist0, attlist1, attlist2, attlist3, attlist4, attlist5, attlist6, + attlist7, attlist8, attlist9, + element0, element1, element2, element3, element4, element5, element6, + element7, +#ifdef XML_DTD + externalSubset0, externalSubset1, + condSect0, condSect1, condSect2, +#endif /* XML_DTD */ + declClose, + error; + +static +int common(PROLOG_STATE *state, int tok); + +static +int prolog0(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + state->handler = prolog1; + return XML_ROLE_NONE; + case XML_TOK_XML_DECL: + state->handler = prolog1; + return XML_ROLE_XML_DECL; + case XML_TOK_PI: + state->handler = prolog1; + return XML_ROLE_NONE; + case XML_TOK_COMMENT: + state->handler = prolog1; + case XML_TOK_BOM: + return XML_ROLE_NONE; + case XML_TOK_DECL_OPEN: + if (!XmlNameMatchesAscii(enc, + ptr + 2 * MIN_BYTES_PER_CHAR(enc), + end, + KW_DOCTYPE)) + break; + state->handler = doctype0; + return XML_ROLE_NONE; + case XML_TOK_INSTANCE_START: + state->handler = error; + return XML_ROLE_INSTANCE_START; + } + return common(state, tok); +} + +static +int prolog1(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_PI: + case XML_TOK_COMMENT: + case XML_TOK_BOM: + return XML_ROLE_NONE; + case XML_TOK_DECL_OPEN: + if (!XmlNameMatchesAscii(enc, + ptr + 2 * MIN_BYTES_PER_CHAR(enc), + end, + KW_DOCTYPE)) + break; + state->handler = doctype0; + return XML_ROLE_NONE; + case XML_TOK_INSTANCE_START: + state->handler = error; + return XML_ROLE_INSTANCE_START; + } + return common(state, tok); +} + +static +int prolog2(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + itkExpatUnused(ptr); + itkExpatUnused(end); + itkExpatUnused(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_PI: + case XML_TOK_COMMENT: + return XML_ROLE_NONE; + case XML_TOK_INSTANCE_START: + state->handler = error; + return XML_ROLE_INSTANCE_START; + } + return common(state, tok); +} + +static +int doctype0(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + itkExpatUnused(ptr); + itkExpatUnused(end); + itkExpatUnused(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_NAME: + case XML_TOK_PREFIXED_NAME: + state->handler = doctype1; + return XML_ROLE_DOCTYPE_NAME; + } + return common(state, tok); +} + +static +int doctype1(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_OPEN_BRACKET: + state->handler = internalSubset; + return XML_ROLE_DOCTYPE_INTERNAL_SUBSET; + case XML_TOK_DECL_CLOSE: + state->handler = prolog2; + return XML_ROLE_DOCTYPE_CLOSE; + case XML_TOK_NAME: + if (XmlNameMatchesAscii(enc, ptr, end, KW_SYSTEM)) { + state->handler = doctype3; + return XML_ROLE_NONE; + } + if (XmlNameMatchesAscii(enc, ptr, end, KW_PUBLIC)) { + state->handler = doctype2; + return XML_ROLE_NONE; + } + break; + } + return common(state, tok); +} + +static +int doctype2(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + itkExpatUnused(ptr); + itkExpatUnused(end); + itkExpatUnused(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_LITERAL: + state->handler = doctype3; + return XML_ROLE_DOCTYPE_PUBLIC_ID; + } + return common(state, tok); +} + +static +int doctype3(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + itkExpatUnused(ptr); + itkExpatUnused(end); + itkExpatUnused(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_LITERAL: + state->handler = doctype4; + return XML_ROLE_DOCTYPE_SYSTEM_ID; + } + return common(state, tok); +} + +static +int doctype4(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + itkExpatUnused(ptr); + itkExpatUnused(end); + itkExpatUnused(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_OPEN_BRACKET: + state->handler = internalSubset; + return XML_ROLE_DOCTYPE_INTERNAL_SUBSET; + case XML_TOK_DECL_CLOSE: + state->handler = prolog2; + return XML_ROLE_DOCTYPE_CLOSE; + } + return common(state, tok); +} + +static +int doctype5(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + itkExpatUnused(ptr); + itkExpatUnused(end); + itkExpatUnused(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_DECL_CLOSE: + state->handler = prolog2; + return XML_ROLE_DOCTYPE_CLOSE; + } + return common(state, tok); +} + +static +int internalSubset(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_DECL_OPEN: + if (XmlNameMatchesAscii(enc, + ptr + 2 * MIN_BYTES_PER_CHAR(enc), + end, + KW_ENTITY)) { + state->handler = entity0; + return XML_ROLE_NONE; + } + if (XmlNameMatchesAscii(enc, + ptr + 2 * MIN_BYTES_PER_CHAR(enc), + end, + KW_ATTLIST)) { + state->handler = attlist0; + return XML_ROLE_NONE; + } + if (XmlNameMatchesAscii(enc, + ptr + 2 * MIN_BYTES_PER_CHAR(enc), + end, + KW_ELEMENT)) { + state->handler = element0; + return XML_ROLE_NONE; + } + if (XmlNameMatchesAscii(enc, + ptr + 2 * MIN_BYTES_PER_CHAR(enc), + end, + KW_NOTATION)) { + state->handler = notation0; + return XML_ROLE_NONE; + } + break; + case XML_TOK_PI: + case XML_TOK_COMMENT: + return XML_ROLE_NONE; + case XML_TOK_PARAM_ENTITY_REF: + return XML_ROLE_PARAM_ENTITY_REF; + case XML_TOK_CLOSE_BRACKET: + state->handler = doctype5; + return XML_ROLE_NONE; + } + return common(state, tok); +} + +#ifdef XML_DTD + +static +int externalSubset0(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + state->handler = externalSubset1; + if (tok == XML_TOK_XML_DECL) + return XML_ROLE_TEXT_DECL; + return externalSubset1(state, tok, ptr, end, enc); +} + +static +int externalSubset1(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_COND_SECT_OPEN: + state->handler = condSect0; + return XML_ROLE_NONE; + case XML_TOK_COND_SECT_CLOSE: + if (state->includeLevel == 0) + break; + state->includeLevel -= 1; + return XML_ROLE_NONE; + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_CLOSE_BRACKET: + break; + case XML_TOK_NONE: + if (state->includeLevel) + break; + return XML_ROLE_NONE; + default: + return internalSubset(state, tok, ptr, end, enc); + } + return common(state, tok); +} + +#endif /* XML_DTD */ + +static +int entity0(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + itkExpatUnused(ptr); + itkExpatUnused(end); + itkExpatUnused(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_PERCENT: + state->handler = entity1; + return XML_ROLE_NONE; + case XML_TOK_NAME: + state->handler = entity2; + return XML_ROLE_GENERAL_ENTITY_NAME; + } + return common(state, tok); +} + +static +int entity1(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + itkExpatUnused(ptr); + itkExpatUnused(end); + itkExpatUnused(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_NAME: + state->handler = entity7; + return XML_ROLE_PARAM_ENTITY_NAME; + } + return common(state, tok); +} + +static +int entity2(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_NAME: + if (XmlNameMatchesAscii(enc, ptr, end, KW_SYSTEM)) { + state->handler = entity4; + return XML_ROLE_NONE; + } + if (XmlNameMatchesAscii(enc, ptr, end, KW_PUBLIC)) { + state->handler = entity3; + return XML_ROLE_NONE; + } + break; + case XML_TOK_LITERAL: + state->handler = declClose; + return XML_ROLE_ENTITY_VALUE; + } + return common(state, tok); +} + +static +int entity3(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + itkExpatUnused(ptr); + itkExpatUnused(end); + itkExpatUnused(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_LITERAL: + state->handler = entity4; + return XML_ROLE_ENTITY_PUBLIC_ID; + } + return common(state, tok); +} + + +static +int entity4(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + itkExpatUnused(ptr); + itkExpatUnused(end); + itkExpatUnused(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_LITERAL: + state->handler = entity5; + return XML_ROLE_ENTITY_SYSTEM_ID; + } + return common(state, tok); +} + +static +int entity5(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_DECL_CLOSE: + setTopLevel(state); + return XML_ROLE_ENTITY_COMPLETE; + case XML_TOK_NAME: + if (XmlNameMatchesAscii(enc, ptr, end, KW_NDATA)) { + state->handler = entity6; + return XML_ROLE_NONE; + } + break; + } + return common(state, tok); +} + +static +int entity6(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + itkExpatUnused(ptr); + itkExpatUnused(end); + itkExpatUnused(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_NAME: + state->handler = declClose; + return XML_ROLE_ENTITY_NOTATION_NAME; + } + return common(state, tok); +} + +static +int entity7(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_NAME: + if (XmlNameMatchesAscii(enc, ptr, end, KW_SYSTEM)) { + state->handler = entity9; + return XML_ROLE_NONE; + } + if (XmlNameMatchesAscii(enc, ptr, end, KW_PUBLIC)) { + state->handler = entity8; + return XML_ROLE_NONE; + } + break; + case XML_TOK_LITERAL: + state->handler = declClose; + return XML_ROLE_ENTITY_VALUE; + } + return common(state, tok); +} + +static +int entity8(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + itkExpatUnused(ptr); + itkExpatUnused(end); + itkExpatUnused(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_LITERAL: + state->handler = entity9; + return XML_ROLE_ENTITY_PUBLIC_ID; + } + return common(state, tok); +} + +static +int entity9(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + itkExpatUnused(ptr); + itkExpatUnused(end); + itkExpatUnused(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_LITERAL: + state->handler = declClose; + return XML_ROLE_ENTITY_SYSTEM_ID; + } + return common(state, tok); +} + +static +int notation0(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + itkExpatUnused(ptr); + itkExpatUnused(end); + itkExpatUnused(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_NAME: + state->handler = notation1; + return XML_ROLE_NOTATION_NAME; + } + return common(state, tok); +} + +static +int notation1(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_NAME: + if (XmlNameMatchesAscii(enc, ptr, end, KW_SYSTEM)) { + state->handler = notation3; + return XML_ROLE_NONE; + } + if (XmlNameMatchesAscii(enc, ptr, end, KW_PUBLIC)) { + state->handler = notation2; + return XML_ROLE_NONE; + } + break; + } + return common(state, tok); +} + +static +int notation2(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + itkExpatUnused(ptr); + itkExpatUnused(end); + itkExpatUnused(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_LITERAL: + state->handler = notation4; + return XML_ROLE_NOTATION_PUBLIC_ID; + } + return common(state, tok); +} + +static +int notation3(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + itkExpatUnused(ptr); + itkExpatUnused(end); + itkExpatUnused(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_LITERAL: + state->handler = declClose; + return XML_ROLE_NOTATION_SYSTEM_ID; + } + return common(state, tok); +} + +static +int notation4(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + itkExpatUnused(ptr); + itkExpatUnused(end); + itkExpatUnused(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_LITERAL: + state->handler = declClose; + return XML_ROLE_NOTATION_SYSTEM_ID; + case XML_TOK_DECL_CLOSE: + setTopLevel(state); + return XML_ROLE_NOTATION_NO_SYSTEM_ID; + } + return common(state, tok); +} + +static +int attlist0(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + itkExpatUnused(ptr); + itkExpatUnused(end); + itkExpatUnused(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_NAME: + case XML_TOK_PREFIXED_NAME: + state->handler = attlist1; + return XML_ROLE_ATTLIST_ELEMENT_NAME; + } + return common(state, tok); +} + +static +int attlist1(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + itkExpatUnused(ptr); + itkExpatUnused(end); + itkExpatUnused(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_DECL_CLOSE: + setTopLevel(state); + return XML_ROLE_NONE; + case XML_TOK_NAME: + case XML_TOK_PREFIXED_NAME: + state->handler = attlist2; + return XML_ROLE_ATTRIBUTE_NAME; + } + return common(state, tok); +} + +static +int attlist2(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + itkExpatUnused(ptr); + itkExpatUnused(end); + itkExpatUnused(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_NAME: + { + static const char *types[] = { + KW_CDATA, + KW_ID, + KW_IDREF, + KW_IDREFS, + KW_ENTITY, + KW_ENTITIES, + KW_NMTOKEN, + KW_NMTOKENS, + }; + int i; + for (i = 0; i < (int)(sizeof(types)/sizeof(types[0])); i++) + if (XmlNameMatchesAscii(enc, ptr, end, types[i])) { + state->handler = attlist8; + return XML_ROLE_ATTRIBUTE_TYPE_CDATA + i; + } + } + if (XmlNameMatchesAscii(enc, ptr, end, KW_NOTATION)) { + state->handler = attlist5; + return XML_ROLE_NONE; + } + break; + case XML_TOK_OPEN_PAREN: + state->handler = attlist3; + return XML_ROLE_NONE; + } + return common(state, tok); +} + +static +int attlist3(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + itkExpatUnused(ptr); + itkExpatUnused(end); + itkExpatUnused(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_NMTOKEN: + case XML_TOK_NAME: + case XML_TOK_PREFIXED_NAME: + state->handler = attlist4; + return XML_ROLE_ATTRIBUTE_ENUM_VALUE; + } + return common(state, tok); +} + +static +int attlist4(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + itkExpatUnused(ptr); + itkExpatUnused(end); + itkExpatUnused(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_CLOSE_PAREN: + state->handler = attlist8; + return XML_ROLE_NONE; + case XML_TOK_OR: + state->handler = attlist3; + return XML_ROLE_NONE; + } + return common(state, tok); +} + +static +int attlist5(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + itkExpatUnused(ptr); + itkExpatUnused(end); + itkExpatUnused(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_OPEN_PAREN: + state->handler = attlist6; + return XML_ROLE_NONE; + } + return common(state, tok); +} + + +static +int attlist6(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + itkExpatUnused(ptr); + itkExpatUnused(end); + itkExpatUnused(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_NAME: + state->handler = attlist7; + return XML_ROLE_ATTRIBUTE_NOTATION_VALUE; + } + return common(state, tok); +} + +static +int attlist7(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + itkExpatUnused(ptr); + itkExpatUnused(end); + itkExpatUnused(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_CLOSE_PAREN: + state->handler = attlist8; + return XML_ROLE_NONE; + case XML_TOK_OR: + state->handler = attlist6; + return XML_ROLE_NONE; + } + return common(state, tok); +} + +/* default value */ +static +int attlist8(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + itkExpatUnused(ptr); + itkExpatUnused(end); + itkExpatUnused(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_POUND_NAME: + if (XmlNameMatchesAscii(enc, + ptr + MIN_BYTES_PER_CHAR(enc), + end, + KW_IMPLIED)) { + state->handler = attlist1; + return XML_ROLE_IMPLIED_ATTRIBUTE_VALUE; + } + if (XmlNameMatchesAscii(enc, + ptr + MIN_BYTES_PER_CHAR(enc), + end, + KW_REQUIRED)) { + state->handler = attlist1; + return XML_ROLE_REQUIRED_ATTRIBUTE_VALUE; + } + if (XmlNameMatchesAscii(enc, + ptr + MIN_BYTES_PER_CHAR(enc), + end, + KW_FIXED)) { + state->handler = attlist9; + return XML_ROLE_NONE; + } + break; + case XML_TOK_LITERAL: + state->handler = attlist1; + return XML_ROLE_DEFAULT_ATTRIBUTE_VALUE; + } + return common(state, tok); +} + +static +int attlist9(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + itkExpatUnused(ptr); + itkExpatUnused(end); + itkExpatUnused(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_LITERAL: + state->handler = attlist1; + return XML_ROLE_FIXED_ATTRIBUTE_VALUE; + } + return common(state, tok); +} + +static +int element0(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + itkExpatUnused(ptr); + itkExpatUnused(end); + itkExpatUnused(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_NAME: + case XML_TOK_PREFIXED_NAME: + state->handler = element1; + return XML_ROLE_ELEMENT_NAME; + } + return common(state, tok); +} + +static +int element1(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + itkExpatUnused(ptr); + itkExpatUnused(end); + itkExpatUnused(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_NAME: + if (XmlNameMatchesAscii(enc, ptr, end, KW_EMPTY)) { + state->handler = declClose; + return XML_ROLE_CONTENT_EMPTY; + } + if (XmlNameMatchesAscii(enc, ptr, end, KW_ANY)) { + state->handler = declClose; + return XML_ROLE_CONTENT_ANY; + } + break; + case XML_TOK_OPEN_PAREN: + state->handler = element2; + state->level = 1; + return XML_ROLE_GROUP_OPEN; + } + return common(state, tok); +} + +static +int element2(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + itkExpatUnused(ptr); + itkExpatUnused(end); + itkExpatUnused(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_POUND_NAME: + if (XmlNameMatchesAscii(enc, + ptr + MIN_BYTES_PER_CHAR(enc), + end, + KW_PCDATA)) { + state->handler = element3; + return XML_ROLE_CONTENT_PCDATA; + } + break; + case XML_TOK_OPEN_PAREN: + state->level = 2; + state->handler = element6; + return XML_ROLE_GROUP_OPEN; + case XML_TOK_NAME: + case XML_TOK_PREFIXED_NAME: + state->handler = element7; + return XML_ROLE_CONTENT_ELEMENT; + case XML_TOK_NAME_QUESTION: + state->handler = element7; + return XML_ROLE_CONTENT_ELEMENT_OPT; + case XML_TOK_NAME_ASTERISK: + state->handler = element7; + return XML_ROLE_CONTENT_ELEMENT_REP; + case XML_TOK_NAME_PLUS: + state->handler = element7; + return XML_ROLE_CONTENT_ELEMENT_PLUS; + } + return common(state, tok); +} + +static +int element3(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + itkExpatUnused(ptr); + itkExpatUnused(end); + itkExpatUnused(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_CLOSE_PAREN: + state->handler = declClose; + return XML_ROLE_GROUP_CLOSE; + case XML_TOK_CLOSE_PAREN_ASTERISK: + state->handler = declClose; + return XML_ROLE_GROUP_CLOSE_REP; + case XML_TOK_OR: + state->handler = element4; + return XML_ROLE_NONE; + } + return common(state, tok); +} + +static +int element4(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + itkExpatUnused(ptr); + itkExpatUnused(end); + itkExpatUnused(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_NAME: + case XML_TOK_PREFIXED_NAME: + state->handler = element5; + return XML_ROLE_CONTENT_ELEMENT; + } + return common(state, tok); +} + +static +int element5(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + itkExpatUnused(ptr); + itkExpatUnused(end); + itkExpatUnused(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_CLOSE_PAREN_ASTERISK: + state->handler = declClose; + return XML_ROLE_GROUP_CLOSE_REP; + case XML_TOK_OR: + state->handler = element4; + return XML_ROLE_NONE; + } + return common(state, tok); +} + +static +int element6(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + itkExpatUnused(ptr); + itkExpatUnused(end); + itkExpatUnused(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_OPEN_PAREN: + state->level += 1; + return XML_ROLE_GROUP_OPEN; + case XML_TOK_NAME: + case XML_TOK_PREFIXED_NAME: + state->handler = element7; + return XML_ROLE_CONTENT_ELEMENT; + case XML_TOK_NAME_QUESTION: + state->handler = element7; + return XML_ROLE_CONTENT_ELEMENT_OPT; + case XML_TOK_NAME_ASTERISK: + state->handler = element7; + return XML_ROLE_CONTENT_ELEMENT_REP; + case XML_TOK_NAME_PLUS: + state->handler = element7; + return XML_ROLE_CONTENT_ELEMENT_PLUS; + } + return common(state, tok); +} + +static +int element7(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + itkExpatUnused(ptr); + itkExpatUnused(end); + itkExpatUnused(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_CLOSE_PAREN: + state->level -= 1; + if (state->level == 0) + state->handler = declClose; + return XML_ROLE_GROUP_CLOSE; + case XML_TOK_CLOSE_PAREN_ASTERISK: + state->level -= 1; + if (state->level == 0) + state->handler = declClose; + return XML_ROLE_GROUP_CLOSE_REP; + case XML_TOK_CLOSE_PAREN_QUESTION: + state->level -= 1; + if (state->level == 0) + state->handler = declClose; + return XML_ROLE_GROUP_CLOSE_OPT; + case XML_TOK_CLOSE_PAREN_PLUS: + state->level -= 1; + if (state->level == 0) + state->handler = declClose; + return XML_ROLE_GROUP_CLOSE_PLUS; + case XML_TOK_COMMA: + state->handler = element6; + return XML_ROLE_GROUP_SEQUENCE; + case XML_TOK_OR: + state->handler = element6; + return XML_ROLE_GROUP_CHOICE; + } + return common(state, tok); +} + +#ifdef XML_DTD + +static +int condSect0(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + itkExpatUnused(ptr); + itkExpatUnused(end); + itkExpatUnused(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_NAME: + if (XmlNameMatchesAscii(enc, ptr, end, KW_INCLUDE)) { + state->handler = condSect1; + return XML_ROLE_NONE; + } + if (XmlNameMatchesAscii(enc, ptr, end, KW_IGNORE)) { + state->handler = condSect2; + return XML_ROLE_NONE; + } + break; + } + return common(state, tok); +} + +static +int condSect1(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + itkExpatUnused(ptr); + itkExpatUnused(end); + itkExpatUnused(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_OPEN_BRACKET: + state->handler = externalSubset1; + state->includeLevel += 1; + return XML_ROLE_NONE; + } + return common(state, tok); +} + +static +int condSect2(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + itkExpatUnused(ptr); + itkExpatUnused(end); + itkExpatUnused(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_OPEN_BRACKET: + state->handler = externalSubset1; + return XML_ROLE_IGNORE_SECT; + } + return common(state, tok); +} + +#endif /* XML_DTD */ + +static +int declClose(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + itkExpatUnused(ptr); + itkExpatUnused(end); + itkExpatUnused(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_DECL_CLOSE: + setTopLevel(state); + return XML_ROLE_NONE; + } + return common(state, tok); +} + +#if 0 + +static +int ignore(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + itkExpatUnused(ptr); + itkExpatUnused(end); + itkExpatUnused(enc); + switch (tok) { + case XML_TOK_DECL_CLOSE: + state->handler = internalSubset; + return 0; + default: + return XML_ROLE_NONE; + } + return common(state, tok); +} +#endif + +static +int error(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + itkExpatUnused(state); + itkExpatUnused(tok); + itkExpatUnused(ptr); + itkExpatUnused(end); + itkExpatUnused(enc); + return XML_ROLE_NONE; +} + +static +int common(PROLOG_STATE *state, int tok) +{ +#ifdef XML_DTD + if (!state->documentEntity && tok == XML_TOK_PARAM_ENTITY_REF) + return XML_ROLE_INNER_PARAM_ENTITY_REF; +#endif + state->handler = error; + return XML_ROLE_ERROR; +} + +void XmlPrologStateInit(PROLOG_STATE *state) +{ + state->handler = prolog0; +#ifdef XML_DTD + state->documentEntity = 1; + state->includeLevel = 0; +#endif /* XML_DTD */ +} + +#ifdef XML_DTD + +void XmlPrologStateInitExternalEntity(PROLOG_STATE *state) +{ + state->handler = externalSubset0; + state->documentEntity = 0; + state->includeLevel = 0; +} + +#endif /* XML_DTD */ diff --git a/Utilities/ITK/Utilities/expat/xmlrole.h b/Utilities/ITK/Utilities/expat/xmlrole.h new file mode 100644 index 0000000000000000000000000000000000000000..6f257930666685466fa41dac6d8aa654079c46e4 --- /dev/null +++ b/Utilities/ITK/Utilities/expat/xmlrole.h @@ -0,0 +1,100 @@ +/* +Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd +See the file COPYING for copying permission. +*/ + +#ifndef XmlRole_INCLUDED +#define XmlRole_INCLUDED 1 + +#include "xmltok.h" + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + XML_ROLE_ERROR = -1, + XML_ROLE_NONE = 0, + XML_ROLE_XML_DECL, + XML_ROLE_INSTANCE_START, + XML_ROLE_DOCTYPE_NAME, + XML_ROLE_DOCTYPE_SYSTEM_ID, + XML_ROLE_DOCTYPE_PUBLIC_ID, + XML_ROLE_DOCTYPE_INTERNAL_SUBSET, + XML_ROLE_DOCTYPE_CLOSE, + XML_ROLE_GENERAL_ENTITY_NAME, + XML_ROLE_PARAM_ENTITY_NAME, + XML_ROLE_ENTITY_VALUE, + XML_ROLE_ENTITY_SYSTEM_ID, + XML_ROLE_ENTITY_PUBLIC_ID, + XML_ROLE_ENTITY_COMPLETE, + XML_ROLE_ENTITY_NOTATION_NAME, + XML_ROLE_NOTATION_NAME, + XML_ROLE_NOTATION_SYSTEM_ID, + XML_ROLE_NOTATION_NO_SYSTEM_ID, + XML_ROLE_NOTATION_PUBLIC_ID, + XML_ROLE_ATTRIBUTE_NAME, + XML_ROLE_ATTRIBUTE_TYPE_CDATA, + XML_ROLE_ATTRIBUTE_TYPE_ID, + XML_ROLE_ATTRIBUTE_TYPE_IDREF, + XML_ROLE_ATTRIBUTE_TYPE_IDREFS, + XML_ROLE_ATTRIBUTE_TYPE_ENTITY, + XML_ROLE_ATTRIBUTE_TYPE_ENTITIES, + XML_ROLE_ATTRIBUTE_TYPE_NMTOKEN, + XML_ROLE_ATTRIBUTE_TYPE_NMTOKENS, + XML_ROLE_ATTRIBUTE_ENUM_VALUE, + XML_ROLE_ATTRIBUTE_NOTATION_VALUE, + XML_ROLE_ATTLIST_ELEMENT_NAME, + XML_ROLE_IMPLIED_ATTRIBUTE_VALUE, + XML_ROLE_REQUIRED_ATTRIBUTE_VALUE, + XML_ROLE_DEFAULT_ATTRIBUTE_VALUE, + XML_ROLE_FIXED_ATTRIBUTE_VALUE, + XML_ROLE_ELEMENT_NAME, + XML_ROLE_CONTENT_ANY, + XML_ROLE_CONTENT_EMPTY, + XML_ROLE_CONTENT_PCDATA, + XML_ROLE_GROUP_OPEN, + XML_ROLE_GROUP_CLOSE, + XML_ROLE_GROUP_CLOSE_REP, + XML_ROLE_GROUP_CLOSE_OPT, + XML_ROLE_GROUP_CLOSE_PLUS, + XML_ROLE_GROUP_CHOICE, + XML_ROLE_GROUP_SEQUENCE, + XML_ROLE_CONTENT_ELEMENT, + XML_ROLE_CONTENT_ELEMENT_REP, + XML_ROLE_CONTENT_ELEMENT_OPT, + XML_ROLE_CONTENT_ELEMENT_PLUS, +#ifdef XML_DTD + XML_ROLE_TEXT_DECL, + XML_ROLE_IGNORE_SECT, + XML_ROLE_INNER_PARAM_ENTITY_REF, +#endif /* XML_DTD */ + XML_ROLE_PARAM_ENTITY_REF +}; + +typedef struct prolog_state { + int (*handler)(struct prolog_state *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc); + unsigned level; +#ifdef XML_DTD + unsigned includeLevel; + int documentEntity; +#endif /* XML_DTD */ +} PROLOG_STATE; + +void XmlPrologStateInit(PROLOG_STATE *); +#ifdef XML_DTD +void XmlPrologStateInitExternalEntity(PROLOG_STATE *); +#endif /* XML_DTD */ + +#define XmlTokenRole(state, tok, ptr, end, enc) \ + (((state)->handler)(state, tok, ptr, end, enc)) + +#ifdef __cplusplus +} +#endif + +#endif /* not XmlRole_INCLUDED */ diff --git a/Utilities/ITK/Utilities/expat/xmltok.c b/Utilities/ITK/Utilities/expat/xmltok.c new file mode 100644 index 0000000000000000000000000000000000000000..1a6c6538d19f436b7b36e7b17d45bc246973df5a --- /dev/null +++ b/Utilities/ITK/Utilities/expat/xmltok.c @@ -0,0 +1,1584 @@ +/* +Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd +See the file COPYING for copying permission. +*/ + +#include "expatConfig.h" + +#include "xmltok.h" +#include "nametab.h" + +#if defined(__BORLANDC__) +#pragma warn -8008 // Disable "condition is always true" warning. +#pragma warn -8066 // Disable "unreachable code" warning. +#endif + +#ifdef XML_DTD +#define IGNORE_SECTION_TOK_VTABLE , PREFIX(ignoreSectionTok) +#else +#define IGNORE_SECTION_TOK_VTABLE /* as nothing */ +#endif + +#define VTABLE1 \ + { PREFIX(prologTok), PREFIX(contentTok), \ + PREFIX(cdataSectionTok) IGNORE_SECTION_TOK_VTABLE }, \ + { PREFIX(attributeValueTok), PREFIX(entityValueTok) }, \ + PREFIX(sameName), \ + PREFIX(nameMatchesAscii), \ + PREFIX(nameLength), \ + PREFIX(skipS), \ + PREFIX(getAtts), \ + PREFIX(charRefNumber), \ + PREFIX(predefinedEntityName), \ + PREFIX(updatePosition), \ + PREFIX(isPublicId) + +#define VTABLE VTABLE1, PREFIX(toUtf8), PREFIX(toUtf16) + +#define UCS2_GET_NAMING(pages, hi, lo) \ + (namingBitmap[(pages[hi] << 3) + ((lo) >> 5)] & (1 << ((lo) & 0x1F))) + +/* A 2 byte UTF-8 representation splits the characters 11 bits +between the bottom 5 and 6 bits of the bytes. +We need 8 bits to index into pages, 3 bits to add to that index and +5 bits to generate the mask. */ +#define UTF8_GET_NAMING2(pages, byte) \ + (namingBitmap[((pages)[(((byte)[0]) >> 2) & 7] << 3) \ + + ((((byte)[0]) & 3) << 1) \ + + ((((byte)[1]) >> 5) & 1)] \ + & (1 << (((byte)[1]) & 0x1F))) + +/* A 3 byte UTF-8 representation splits the characters 16 bits +between the bottom 4, 6 and 6 bits of the bytes. +We need 8 bits to index into pages, 3 bits to add to that index and +5 bits to generate the mask. */ +#define UTF8_GET_NAMING3(pages, byte) \ + (namingBitmap[((pages)[((((byte)[0]) & 0xF) << 4) \ + + ((((byte)[1]) >> 2) & 0xF)] \ + << 3) \ + + ((((byte)[1]) & 3) << 1) \ + + ((((byte)[2]) >> 5) & 1)] \ + & (1 << (((byte)[2]) & 0x1F))) + +#define UTF8_GET_NAMING(pages, p, n) \ + ((n) == 2 \ + ? UTF8_GET_NAMING2(pages, (const unsigned char *)(p)) \ + : ((n) == 3 \ + ? UTF8_GET_NAMING3(pages, (const unsigned char *)(p)) \ + : 0)) + +#define UTF8_INVALID3(p) \ + ((*p) == 0xED \ + ? (((p)[1] & 0x20) != 0) \ + : ((*p) == 0xEF \ + ? ((p)[1] == 0xBF && ((p)[2] == 0xBF || (p)[2] == 0xBE)) \ + : 0)) + +#define UTF8_INVALID4(p) ((*p) == 0xF4 && ((p)[1] & 0x30) != 0) + +static +int isNever(const ENCODING *enc, const char *p) +{ + itkExpatUnused(enc); + itkExpatUnused(p); + return 0; +} + +static +int utf8_isName2(const ENCODING *enc, const char *p) +{ + itkExpatUnused(enc); + return UTF8_GET_NAMING2(namePages, (const unsigned char *)p); +} + +static +int utf8_isName3(const ENCODING *enc, const char *p) +{ + itkExpatUnused(enc); + return UTF8_GET_NAMING3(namePages, (const unsigned char *)p); +} + +#define utf8_isName4 isNever + +static +int utf8_isNmstrt2(const ENCODING *enc, const char *p) +{ + itkExpatUnused(enc); + return UTF8_GET_NAMING2(nmstrtPages, (const unsigned char *)p); +} + +static +int utf8_isNmstrt3(const ENCODING *enc, const char *p) +{ + itkExpatUnused(enc); + return UTF8_GET_NAMING3(nmstrtPages, (const unsigned char *)p); +} + +#define utf8_isNmstrt4 isNever + +#define utf8_isInvalid2 isNever + +static +int utf8_isInvalid3(const ENCODING *enc, const char *p) +{ + itkExpatUnused(enc); + return UTF8_INVALID3((const unsigned char *)p); +} + +static +int utf8_isInvalid4(const ENCODING *enc, const char *p) +{ + itkExpatUnused(enc); + return UTF8_INVALID4((const unsigned char *)p); +} + +struct normal_encoding { + ENCODING enc; + unsigned char type[256]; +#ifdef XML_MIN_SIZE + int (*byteType)(const ENCODING *, const char *); + int (*isNameMin)(const ENCODING *, const char *); + int (*isNmstrtMin)(const ENCODING *, const char *); + int (*byteToAscii)(const ENCODING *, const char *); + int (*charMatches)(const ENCODING *, const char *, int); +#endif /* XML_MIN_SIZE */ + int (*isName2)(const ENCODING *, const char *); + int (*isName3)(const ENCODING *, const char *); + int (*isName4)(const ENCODING *, const char *); + int (*isNmstrt2)(const ENCODING *, const char *); + int (*isNmstrt3)(const ENCODING *, const char *); + int (*isNmstrt4)(const ENCODING *, const char *); + int (*isInvalid2)(const ENCODING *, const char *); + int (*isInvalid3)(const ENCODING *, const char *); + int (*isInvalid4)(const ENCODING *, const char *); +}; + +#ifdef XML_MIN_SIZE + +#define STANDARD_VTABLE(E) \ + E ## byteType, \ + E ## isNameMin, \ + E ## isNmstrtMin, \ + E ## byteToAscii, \ + E ## charMatches, + +#else + +#define STANDARD_VTABLE(E) /* as nothing */ + +#endif + +#define NORMAL_VTABLE(E) \ + E ## isName2, \ + E ## isName3, \ + E ## isName4, \ + E ## isNmstrt2, \ + E ## isNmstrt3, \ + E ## isNmstrt4, \ + E ## isInvalid2, \ + E ## isInvalid3, \ + E ## isInvalid4 + +#define EMPTY_VTABLE(E) 0, 0, 0, 0, 0, 0, 0, 0, 0 + +static int checkCharRefNumber(int); + +#include "xmltok_impl.h" +#include "ascii.h" + +#ifdef XML_MIN_SIZE +#define sb_isNameMin isNever +#define sb_isNmstrtMin isNever +#endif + +#ifdef XML_MIN_SIZE +#define MINBPC(enc) ((enc)->minBytesPerChar) +#else +/* minimum bytes per character */ +#define MINBPC(enc) 1 +#endif + +#define SB_BYTE_TYPE(enc, p) \ + (((struct normal_encoding *)(enc))->type[(unsigned char)*(p)]) + +#ifdef XML_MIN_SIZE +static +int sb_byteType(const ENCODING *enc, const char *p) +{ + return SB_BYTE_TYPE(enc, p); +} +#define BYTE_TYPE(enc, p) \ + (((const struct normal_encoding *)(enc))->byteType(enc, p)) +#else +#define BYTE_TYPE(enc, p) SB_BYTE_TYPE(enc, p) +#endif + +#ifdef XML_MIN_SIZE +#define BYTE_TO_ASCII(enc, p) \ + (((const struct normal_encoding *)(enc))->byteToAscii(enc, p)) +static +int sb_byteToAscii(const ENCODING *enc, const char *p) +{ + return *p; +} +#else +#define BYTE_TO_ASCII(enc, p) (*(p)) +#endif + +#define IS_NAME_CHAR(enc, p, n) \ + (((const struct normal_encoding *)(enc))->isName ## n(enc, p)) +#define IS_NMSTRT_CHAR(enc, p, n) \ + (((const struct normal_encoding *)(enc))->isNmstrt ## n(enc, p)) +#define IS_INVALID_CHAR(enc, p, n) \ + (((const struct normal_encoding *)(enc))->isInvalid ## n(enc, p)) + +#ifdef XML_MIN_SIZE +#define IS_NAME_CHAR_MINBPC(enc, p) \ + (((const struct normal_encoding *)(enc))->isNameMin(enc, p)) +#define IS_NMSTRT_CHAR_MINBPC(enc, p) \ + (((const struct normal_encoding *)(enc))->isNmstrtMin(enc, p)) +#else +#define IS_NAME_CHAR_MINBPC(enc, p) (0) +#define IS_NMSTRT_CHAR_MINBPC(enc, p) (0) +#endif + +#ifdef XML_MIN_SIZE +#define CHAR_MATCHES(enc, p, c) \ + (((const struct normal_encoding *)(enc))->charMatches(enc, p, c)) +static +int sb_charMatches(const ENCODING *enc, const char *p, int c) +{ + return *p == c; +} +#else +/* c is an ASCII character */ +#define CHAR_MATCHES(enc, p, c) (*(p) == c) +#endif + +#define PREFIX(ident) normal_ ## ident +#include "xmltok_impl.c" + +#undef MINBPC +#undef BYTE_TYPE +#undef BYTE_TO_ASCII +#undef CHAR_MATCHES +#undef IS_NAME_CHAR +#undef IS_NAME_CHAR_MINBPC +#undef IS_NMSTRT_CHAR +#undef IS_NMSTRT_CHAR_MINBPC +#undef IS_INVALID_CHAR + +enum { /* UTF8_cvalN is value of masked first byte of N byte sequence */ + UTF8_cval1 = 0x00, + UTF8_cval2 = 0xc0, + UTF8_cval3 = 0xe0, + UTF8_cval4 = 0xf0 +}; + +static +void utf8_toUtf8(const ENCODING *enc, + const char **fromP, const char *fromLim, + char **toP, const char *toLim) +{ + char *to; + const char *from; + itkExpatUnused(enc); + if (fromLim - *fromP > toLim - *toP) { + /* Avoid copying partial characters. */ + for (fromLim = *fromP + (toLim - *toP); fromLim > *fromP; fromLim--) + if (((unsigned char)fromLim[-1] & 0xc0) != 0x80) + break; + } + for (to = *toP, from = *fromP; from != fromLim; from++, to++) + *to = *from; + *fromP = from; + *toP = to; +} + +static +void utf8_toUtf16(const ENCODING *enc, + const char **fromP, const char *fromLim, + unsigned short **toP, const unsigned short *toLim) +{ + unsigned short *to = *toP; + const char *from = *fromP; + while (from != fromLim && to != toLim) { + switch (((struct normal_encoding *)enc)->type[(unsigned char)*from]) { + case BT_LEAD2: + *to++ = ((from[0] & 0x1f) << 6) | (from[1] & 0x3f); + from += 2; + break; + case BT_LEAD3: + *to++ = ((from[0] & 0xf) << 12) | ((from[1] & 0x3f) << 6) | (from[2] & 0x3f); + from += 3; + break; + case BT_LEAD4: + { + unsigned long n; + if (to + 1 == toLim) + break; + n = ((from[0] & 0x7) << 18) | ((from[1] & 0x3f) << 12) | ((from[2] & 0x3f) << 6) | (from[3] & 0x3f); + n -= 0x10000; + to[0] = (unsigned short)((n >> 10) | 0xD800); + to[1] = (unsigned short)((n & 0x3FF) | 0xDC00); + to += 2; + from += 4; + } + break; + default: + *to++ = *from++; + break; + } + } + *fromP = from; + *toP = to; +} + +#ifdef XML_NS +static const struct normal_encoding utf8_encoding_ns = { + { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 }, + { +#include "asciitab.h" +#include "utf8tab.h" + }, + STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_) +}; +#endif + +static const struct normal_encoding utf8_encoding = { + { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 }, + { +#define BT_COLON BT_NMSTRT +#include "asciitab.h" +#undef BT_COLON +#include "utf8tab.h" + }, + STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_) +}; + +#ifdef XML_NS + +static const struct normal_encoding internal_utf8_encoding_ns = { + { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 }, + { +#include "iasciitab.h" +#include "utf8tab.h" + }, + STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_) +}; + +#endif + +static const struct normal_encoding internal_utf8_encoding = { + { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 }, + { +#define BT_COLON BT_NMSTRT +#include "iasciitab.h" +#undef BT_COLON +#include "utf8tab.h" + }, + STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_) +}; + +static +void latin1_toUtf8(const ENCODING *enc, + const char **fromP, const char *fromLim, + char **toP, const char *toLim) +{ + itkExpatUnused(enc); + for (;;) { + unsigned char c; + if (*fromP == fromLim) + break; + c = (unsigned char)**fromP; + if (c & 0x80) { + if (toLim - *toP < 2) + break; + *(*toP)++ = ((c >> 6) | UTF8_cval2); + *(*toP)++ = ((c & 0x3f) | 0x80); + (*fromP)++; + } + else { + if (*toP == toLim) + break; + *(*toP)++ = *(*fromP)++; + } + } +} + +static +void latin1_toUtf16(const ENCODING *enc, + const char **fromP, const char *fromLim, + unsigned short **toP, const unsigned short *toLim) +{ + itkExpatUnused(enc); + while (*fromP != fromLim && *toP != toLim) + *(*toP)++ = (unsigned char)*(*fromP)++; +} + +#ifdef XML_NS + +static const struct normal_encoding latin1_encoding_ns = { + { VTABLE1, latin1_toUtf8, latin1_toUtf16, 1, 0, 0 }, + { +#include "asciitab.h" +#include "latin1tab.h" + }, + STANDARD_VTABLE(sb_) EMPTY_VTABLE(sb_) +}; + +#endif + +static const struct normal_encoding latin1_encoding = { + { VTABLE1, latin1_toUtf8, latin1_toUtf16, 1, 0, 0 }, + { +#define BT_COLON BT_NMSTRT +#include "asciitab.h" +#undef BT_COLON +#include "latin1tab.h" + }, + STANDARD_VTABLE(sb_) EMPTY_VTABLE(sb_) +}; + +static +void ascii_toUtf8(const ENCODING *enc, + const char **fromP, const char *fromLim, + char **toP, const char *toLim) +{ + itkExpatUnused(enc); + while (*fromP != fromLim && *toP != toLim) + *(*toP)++ = *(*fromP)++; +} + +#ifdef XML_NS + +static const struct normal_encoding ascii_encoding_ns = { + { VTABLE1, ascii_toUtf8, latin1_toUtf16, 1, 1, 0 }, + { +#include "asciitab.h" +/* BT_NONXML == 0 */ + }, + STANDARD_VTABLE(sb_) EMPTY_VTABLE(sb_) +}; + +#endif + +static const struct normal_encoding ascii_encoding = { + { VTABLE1, ascii_toUtf8, latin1_toUtf16, 1, 1, 0 }, + { +#define BT_COLON BT_NMSTRT +#include "asciitab.h" +#undef BT_COLON +/* BT_NONXML == 0 */ + }, + STANDARD_VTABLE(sb_) EMPTY_VTABLE(sb_) +}; + +static int unicode_byte_type(char hi, char lo) +{ + switch ((unsigned char)hi) { + case 0xD8: case 0xD9: case 0xDA: case 0xDB: + return BT_LEAD4; + case 0xDC: case 0xDD: case 0xDE: case 0xDF: + return BT_TRAIL; + case 0xFF: + switch ((unsigned char)lo) { + case 0xFF: + case 0xFE: + return BT_NONXML; + } + break; + } + return BT_NONASCII; +} + +#define DEFINE_UTF16_TO_UTF8(E) \ +static \ +void E ## toUtf8(const ENCODING *enc, \ + const char **fromP, const char *fromLim, \ + char **toP, const char *toLim) \ +{ \ + const char *from; \ + itkExpatUnused(enc);\ + for (from = *fromP; from != fromLim; from += 2) { \ + int plane; \ + unsigned char lo2; \ + unsigned char lo = GET_LO(from); \ + unsigned char hi = GET_HI(from); \ + switch (hi) { \ + case 0: \ + if (lo < 0x80) { \ + if (*toP == toLim) { \ + *fromP = from; \ + return; \ + } \ + *(*toP)++ = lo; \ + break; \ + } \ + /* fall through */ \ + case 0x1: case 0x2: case 0x3: \ + case 0x4: case 0x5: case 0x6: case 0x7: \ + if (toLim - *toP < 2) { \ + *fromP = from; \ + return; \ + } \ + *(*toP)++ = ((lo >> 6) | (hi << 2) | UTF8_cval2); \ + *(*toP)++ = ((lo & 0x3f) | 0x80); \ + break; \ + default: \ + if (toLim - *toP < 3) { \ + *fromP = from; \ + return; \ + } \ + /* 16 bits divided 4, 6, 6 amongst 3 bytes */ \ + *(*toP)++ = ((hi >> 4) | UTF8_cval3); \ + *(*toP)++ = (((hi & 0xf) << 2) | (lo >> 6) | 0x80); \ + *(*toP)++ = ((lo & 0x3f) | 0x80); \ + break; \ + case 0xD8: case 0xD9: case 0xDA: case 0xDB: \ + if (toLim - *toP < 4) { \ + *fromP = from; \ + return; \ + } \ + plane = (((hi & 0x3) << 2) | ((lo >> 6) & 0x3)) + 1; \ + *(*toP)++ = ((plane >> 2) | UTF8_cval4); \ + *(*toP)++ = (((lo >> 2) & 0xF) | ((plane & 0x3) << 4) | 0x80); \ + from += 2; \ + lo2 = GET_LO(from); \ + *(*toP)++ = (((lo & 0x3) << 4) \ + | ((GET_HI(from) & 0x3) << 2) \ + | (lo2 >> 6) \ + | 0x80); \ + *(*toP)++ = ((lo2 & 0x3f) | 0x80); \ + break; \ + } \ + } \ + *fromP = from; \ +} + +#define DEFINE_UTF16_TO_UTF16(E) \ +static \ +void E ## toUtf16(const ENCODING *enc, \ + const char **fromP, const char *fromLim, \ + unsigned short **toP, const unsigned short *toLim) \ +{ \ + itkExpatUnused(enc);\ + /* Avoid copying first half only of surrogate */ \ + if (fromLim - *fromP > ((toLim - *toP) << 1) \ + && (GET_HI(fromLim - 2) & 0xF8) == 0xD8) \ + fromLim -= 2; \ + for (; *fromP != fromLim && *toP != toLim; *fromP += 2) \ + *(*toP)++ = (GET_HI(*fromP) << 8) | GET_LO(*fromP); \ +} + +#define SET2(ptr, ch) \ + (((ptr)[0] = ((ch) & 0xff)), ((ptr)[1] = ((ch) >> 8))) +#define GET_LO(ptr) ((unsigned char)(ptr)[0]) +#define GET_HI(ptr) ((unsigned char)(ptr)[1]) + +DEFINE_UTF16_TO_UTF8(little2_) +DEFINE_UTF16_TO_UTF16(little2_) + +#undef SET2 +#undef GET_LO +#undef GET_HI + +#define SET2(ptr, ch) \ + (((ptr)[0] = ((ch) >> 8)), ((ptr)[1] = ((ch) & 0xFF))) +#define GET_LO(ptr) ((unsigned char)(ptr)[1]) +#define GET_HI(ptr) ((unsigned char)(ptr)[0]) + +DEFINE_UTF16_TO_UTF8(big2_) +DEFINE_UTF16_TO_UTF16(big2_) + +#undef SET2 +#undef GET_LO +#undef GET_HI + +#define LITTLE2_BYTE_TYPE(enc, p) \ + ((p)[1] == 0 \ + ? ((struct normal_encoding *)(enc))->type[(unsigned char)*(p)] \ + : unicode_byte_type((p)[1], (p)[0])) +#define LITTLE2_BYTE_TO_ASCII(enc, p) ((p)[1] == 0 ? (p)[0] : -1) +#define LITTLE2_CHAR_MATCHES(enc, p, c) ((p)[1] == 0 && (p)[0] == c) +#define LITTLE2_IS_NAME_CHAR_MINBPC(enc, p) \ + UCS2_GET_NAMING(namePages, (unsigned char)p[1], (unsigned char)p[0]) +#define LITTLE2_IS_NMSTRT_CHAR_MINBPC(enc, p) \ + UCS2_GET_NAMING(nmstrtPages, (unsigned char)p[1], (unsigned char)p[0]) + +#ifdef XML_MIN_SIZE + +static +int little2_byteType(const ENCODING *enc, const char *p) +{ + return LITTLE2_BYTE_TYPE(enc, p); +} + +static +int little2_byteToAscii(const ENCODING *enc, const char *p) +{ + return LITTLE2_BYTE_TO_ASCII(enc, p); +} + +static +int little2_charMatches(const ENCODING *enc, const char *p, int c) +{ + return LITTLE2_CHAR_MATCHES(enc, p, c); +} + +static +int little2_isNameMin(const ENCODING *enc, const char *p) +{ + return LITTLE2_IS_NAME_CHAR_MINBPC(enc, p); +} + +static +int little2_isNmstrtMin(const ENCODING *enc, const char *p) +{ + return LITTLE2_IS_NMSTRT_CHAR_MINBPC(enc, p); +} + +#undef VTABLE +#define VTABLE VTABLE1, little2_toUtf8, little2_toUtf16 + +#else /* not XML_MIN_SIZE */ + +#undef PREFIX +#define PREFIX(ident) little2_ ## ident +#define MINBPC(enc) 2 +/* CHAR_MATCHES is guaranteed to have MINBPC bytes available. */ +#define BYTE_TYPE(enc, p) LITTLE2_BYTE_TYPE(enc, p) +#define BYTE_TO_ASCII(enc, p) LITTLE2_BYTE_TO_ASCII(enc, p) +#define CHAR_MATCHES(enc, p, c) LITTLE2_CHAR_MATCHES(enc, p, c) +#define IS_NAME_CHAR(enc, p, n) 0 +#define IS_NAME_CHAR_MINBPC(enc, p) LITTLE2_IS_NAME_CHAR_MINBPC(enc, p) +#define IS_NMSTRT_CHAR(enc, p, n) (0) +#define IS_NMSTRT_CHAR_MINBPC(enc, p) LITTLE2_IS_NMSTRT_CHAR_MINBPC(enc, p) + +#include "xmltok_impl.c" + +#undef MINBPC +#undef BYTE_TYPE +#undef BYTE_TO_ASCII +#undef CHAR_MATCHES +#undef IS_NAME_CHAR +#undef IS_NAME_CHAR_MINBPC +#undef IS_NMSTRT_CHAR +#undef IS_NMSTRT_CHAR_MINBPC +#undef IS_INVALID_CHAR + +#endif /* not XML_MIN_SIZE */ + +#ifdef XML_NS + +static const struct normal_encoding little2_encoding_ns = { + { VTABLE, 2, 0, +#if XML_BYTE_ORDER == 12 + 1 +#else + 0 +#endif + }, + { +#include "asciitab.h" +#include "latin1tab.h" + }, + STANDARD_VTABLE(little2_) EMPTY_VTABLE(little2_) +}; + +#endif + +static const struct normal_encoding little2_encoding = { + { VTABLE, 2, 0, +#if XML_BYTE_ORDER == 12 + 1 +#else + 0 +#endif + }, + { +#define BT_COLON BT_NMSTRT +#include "asciitab.h" +#undef BT_COLON +#include "latin1tab.h" + }, + STANDARD_VTABLE(little2_) EMPTY_VTABLE(little2_) +}; + +#if XML_BYTE_ORDER != 21 + +#ifdef XML_NS + +static const struct normal_encoding internal_little2_encoding_ns = { + { VTABLE, 2, 0, 1 }, + { +#include "iasciitab.h" +#include "latin1tab.h" + }, + STANDARD_VTABLE(little2_) EMPTY_VTABLE(little2_) +}; + +#endif + +static const struct normal_encoding internal_little2_encoding = { + { VTABLE, 2, 0, 1 }, + { +#define BT_COLON BT_NMSTRT +#include "iasciitab.h" +#undef BT_COLON +#include "latin1tab.h" + }, + STANDARD_VTABLE(little2_) EMPTY_VTABLE(little2_) +}; + +#endif + + +#define BIG2_BYTE_TYPE(enc, p) \ + ((p)[0] == 0 \ + ? ((struct normal_encoding *)(enc))->type[(unsigned char)(p)[1]] \ + : unicode_byte_type((p)[0], (p)[1])) +#define BIG2_BYTE_TO_ASCII(enc, p) ((p)[0] == 0 ? (p)[1] : -1) +#define BIG2_CHAR_MATCHES(enc, p, c) ((p)[0] == 0 && (p)[1] == c) +#define BIG2_IS_NAME_CHAR_MINBPC(enc, p) \ + UCS2_GET_NAMING(namePages, (unsigned char)p[0], (unsigned char)p[1]) +#define BIG2_IS_NMSTRT_CHAR_MINBPC(enc, p) \ + UCS2_GET_NAMING(nmstrtPages, (unsigned char)p[0], (unsigned char)p[1]) + +#ifdef XML_MIN_SIZE + +static +int big2_byteType(const ENCODING *enc, const char *p) +{ + return BIG2_BYTE_TYPE(enc, p); +} + +static +int big2_byteToAscii(const ENCODING *enc, const char *p) +{ + return BIG2_BYTE_TO_ASCII(enc, p); +} + +static +int big2_charMatches(const ENCODING *enc, const char *p, int c) +{ + return BIG2_CHAR_MATCHES(enc, p, c); +} + +static +int big2_isNameMin(const ENCODING *enc, const char *p) +{ + return BIG2_IS_NAME_CHAR_MINBPC(enc, p); +} + +static +int big2_isNmstrtMin(const ENCODING *enc, const char *p) +{ + return BIG2_IS_NMSTRT_CHAR_MINBPC(enc, p); +} + +#undef VTABLE +#define VTABLE VTABLE1, big2_toUtf8, big2_toUtf16 + +#else /* not XML_MIN_SIZE */ + +#undef PREFIX +#define PREFIX(ident) big2_ ## ident +#define MINBPC(enc) 2 +/* CHAR_MATCHES is guaranteed to have MINBPC bytes available. */ +#define BYTE_TYPE(enc, p) BIG2_BYTE_TYPE(enc, p) +#define BYTE_TO_ASCII(enc, p) BIG2_BYTE_TO_ASCII(enc, p) +#define CHAR_MATCHES(enc, p, c) BIG2_CHAR_MATCHES(enc, p, c) +#define IS_NAME_CHAR(enc, p, n) 0 +#define IS_NAME_CHAR_MINBPC(enc, p) BIG2_IS_NAME_CHAR_MINBPC(enc, p) +#define IS_NMSTRT_CHAR(enc, p, n) (0) +#define IS_NMSTRT_CHAR_MINBPC(enc, p) BIG2_IS_NMSTRT_CHAR_MINBPC(enc, p) + +#include "xmltok_impl.c" + +#undef MINBPC +#undef BYTE_TYPE +#undef BYTE_TO_ASCII +#undef CHAR_MATCHES +#undef IS_NAME_CHAR +#undef IS_NAME_CHAR_MINBPC +#undef IS_NMSTRT_CHAR +#undef IS_NMSTRT_CHAR_MINBPC +#undef IS_INVALID_CHAR + +#endif /* not XML_MIN_SIZE */ + +#ifdef XML_NS + +static const struct normal_encoding big2_encoding_ns = { + { VTABLE, 2, 0, +#if XML_BYTE_ORDER == 21 + 1 +#else + 0 +#endif + }, + { +#include "asciitab.h" +#include "latin1tab.h" + }, + STANDARD_VTABLE(big2_) EMPTY_VTABLE(big2_) +}; + +#endif + +static const struct normal_encoding big2_encoding = { + { VTABLE, 2, 0, +#if XML_BYTE_ORDER == 21 + 1 +#else + 0 +#endif + }, + { +#define BT_COLON BT_NMSTRT +#include "asciitab.h" +#undef BT_COLON +#include "latin1tab.h" + }, + STANDARD_VTABLE(big2_) EMPTY_VTABLE(big2_) +}; + +#if XML_BYTE_ORDER != 12 + +#ifdef XML_NS + +static const struct normal_encoding internal_big2_encoding_ns = { + { VTABLE, 2, 0, 1 }, + { +#include "iasciitab.h" +#include "latin1tab.h" + }, + STANDARD_VTABLE(big2_) EMPTY_VTABLE(big2_) +}; + +#endif + +static const struct normal_encoding internal_big2_encoding = { + { VTABLE, 2, 0, 1 }, + { +#define BT_COLON BT_NMSTRT +#include "iasciitab.h" +#undef BT_COLON +#include "latin1tab.h" + }, + STANDARD_VTABLE(big2_) EMPTY_VTABLE(big2_) +}; + +#endif + +#undef PREFIX + +static +int streqci(const char *s1, const char *s2) +{ + for (;;) { + char c1 = *s1++; + char c2 = *s2++; + if (ASCII_a <= c1 && c1 <= ASCII_z) + c1 += ASCII_A - ASCII_a; + if (ASCII_a <= c2 && c2 <= ASCII_z) + c2 += ASCII_A - ASCII_a; + if (c1 != c2) + return 0; + if (!c1) + break; + } + return 1; +} + +static +void initUpdatePosition(const ENCODING *enc, const char *ptr, + const char *end, POSITION *pos) +{ + itkExpatUnused(enc); + normal_updatePosition(&utf8_encoding.enc, ptr, end, pos); +} + +static +int toAscii(const ENCODING *enc, const char *ptr, const char *end) +{ + char buf[1]; + char *p = buf; + XmlUtf8Convert(enc, &ptr, end, &p, p + 1); + if (p == buf) + return -1; + else + return buf[0]; +} + +static +int isSpace(int c) +{ + switch (c) { + case 0x20: + case 0xD: + case 0xA: + case 0x9: + return 1; + } + return 0; +} + +/* Return 1 if there's just optional white space +or there's an S followed by name=val. */ +static +int parsePseudoAttribute(const ENCODING *enc, + const char *ptr, + const char *end, + const char **namePtr, + const char **nameEndPtr, + const char **valPtr, + const char **nextTokPtr) +{ + int c; + char open; + if (ptr == end) { + *namePtr = 0; + return 1; + } + if (!isSpace(toAscii(enc, ptr, end))) { + *nextTokPtr = ptr; + return 0; + } + do { + ptr += enc->minBytesPerChar; + } while (isSpace(toAscii(enc, ptr, end))); + if (ptr == end) { + *namePtr = 0; + return 1; + } + *namePtr = ptr; + for (;;) { + c = toAscii(enc, ptr, end); + if (c == -1) { + *nextTokPtr = ptr; + return 0; + } + if (c == ASCII_EQUALS) { + *nameEndPtr = ptr; + break; + } + if (isSpace(c)) { + *nameEndPtr = ptr; + do { + ptr += enc->minBytesPerChar; + } while (isSpace(c = toAscii(enc, ptr, end))); + if (c != ASCII_EQUALS) { + *nextTokPtr = ptr; + return 0; + } + break; + } + ptr += enc->minBytesPerChar; + } + if (ptr == *namePtr) { + *nextTokPtr = ptr; + return 0; + } + ptr += enc->minBytesPerChar; + c = toAscii(enc, ptr, end); + while (isSpace(c)) { + ptr += enc->minBytesPerChar; + c = toAscii(enc, ptr, end); + } + if (c != ASCII_QUOT && c != ASCII_APOS) { + *nextTokPtr = ptr; + return 0; + } + open = c; + ptr += enc->minBytesPerChar; + *valPtr = ptr; + for (;; ptr += enc->minBytesPerChar) { + c = toAscii(enc, ptr, end); + if (c == open) + break; + if (!(ASCII_a <= c && c <= ASCII_z) + && !(ASCII_A <= c && c <= ASCII_Z) + && !(ASCII_0 <= c && c <= ASCII_9) + && c != ASCII_PERIOD + && c != ASCII_MINUS + && c != ASCII_UNDERSCORE) { + *nextTokPtr = ptr; + return 0; + } + } + *nextTokPtr = ptr + enc->minBytesPerChar; + return 1; +} + +static const char KW_version[] = { + ASCII_v, ASCII_e, ASCII_r, ASCII_s, ASCII_i, ASCII_o, ASCII_n, '\0' +}; + +static const char KW_encoding[] = { + ASCII_e, ASCII_n, ASCII_c, ASCII_o, ASCII_d, ASCII_i, ASCII_n, ASCII_g, '\0' +}; + +static const char KW_standalone[] = { + ASCII_s, ASCII_t, ASCII_a, ASCII_n, ASCII_d, ASCII_a, ASCII_l, ASCII_o, ASCII_n, ASCII_e, '\0' +}; + +static const char KW_yes[] = { + ASCII_y, ASCII_e, ASCII_s, '\0' +}; + +static const char KW_no[] = { + ASCII_n, ASCII_o, '\0' +}; + +static +int doParseXmlDecl(const ENCODING *(*encodingFinder)(const ENCODING *, + const char *, + const char *), + int isGeneralTextEntity, + const ENCODING *enc, + const char *ptr, + const char *end, + const char **badPtr, + const char **versionPtr, + const char **versionEndPtr, + const char **encodingName, + const ENCODING **encoding, + int *standalone) +{ + const char *val = 0; + const char *name = 0; + const char *nameEnd = 0; + ptr += 5 * enc->minBytesPerChar; + end -= 2 * enc->minBytesPerChar; + if (!parsePseudoAttribute(enc, ptr, end, &name, &nameEnd, &val, &ptr) || !name) { + *badPtr = ptr; + return 0; + } + if (!XmlNameMatchesAscii(enc, name, nameEnd, KW_version)) { + if (!isGeneralTextEntity) { + *badPtr = name; + return 0; + } + } + else { + if (versionPtr) + *versionPtr = val; + if (versionEndPtr) + *versionEndPtr = ptr; + if (!parsePseudoAttribute(enc, ptr, end, &name, &nameEnd, &val, &ptr)) { + *badPtr = ptr; + return 0; + } + if (!name) { + if (isGeneralTextEntity) { + /* a TextDecl must have an EncodingDecl */ + *badPtr = ptr; + return 0; + } + return 1; + } + } + if (XmlNameMatchesAscii(enc, name, nameEnd, KW_encoding)) { + int c = toAscii(enc, val, end); + if (!(ASCII_a <= c && c <= ASCII_z) && !(ASCII_A <= c && c <= ASCII_Z)) { + *badPtr = val; + return 0; + } + if (encodingName) + *encodingName = val; + if (encoding) + *encoding = encodingFinder(enc, val, ptr - enc->minBytesPerChar); + if (!parsePseudoAttribute(enc, ptr, end, &name, &nameEnd, &val, &ptr)) { + *badPtr = ptr; + return 0; + } + if (!name) + return 1; + } + if (!XmlNameMatchesAscii(enc, name, nameEnd, KW_standalone) || isGeneralTextEntity) { + *badPtr = name; + return 0; + } + if (XmlNameMatchesAscii(enc, val, ptr - enc->minBytesPerChar, KW_yes)) { + if (standalone) + *standalone = 1; + } + else if (XmlNameMatchesAscii(enc, val, ptr - enc->minBytesPerChar, KW_no)) { + if (standalone) + *standalone = 0; + } + else { + *badPtr = val; + return 0; + } + while (isSpace(toAscii(enc, ptr, end))) + ptr += enc->minBytesPerChar; + if (ptr != end) { + *badPtr = ptr; + return 0; + } + return 1; +} + +static +int checkCharRefNumber(int result) +{ + switch (result >> 8) { + case 0xD8: case 0xD9: case 0xDA: case 0xDB: + case 0xDC: case 0xDD: case 0xDE: case 0xDF: + return -1; + case 0: + if (latin1_encoding.type[result] == BT_NONXML) + return -1; + break; + case 0xFF: + if (result == 0xFFFE || result == 0xFFFF) + return -1; + break; + } + return result; +} + +int XmlUtf8Encode(int c, char *buf) +{ + enum { + /* minN is minimum legal resulting value for N byte sequence */ + min2 = 0x80, + min3 = 0x800, + min4 = 0x10000 + }; + + if (c < 0) + return 0; + if (c < min2) { + buf[0] = (c | UTF8_cval1); + return 1; + } + if (c < min3) { + buf[0] = ((c >> 6) | UTF8_cval2); + buf[1] = ((c & 0x3f) | 0x80); + return 2; + } + if (c < min4) { + buf[0] = ((c >> 12) | UTF8_cval3); + buf[1] = (((c >> 6) & 0x3f) | 0x80); + buf[2] = ((c & 0x3f) | 0x80); + return 3; + } + if (c < 0x110000) { + buf[0] = ((c >> 18) | UTF8_cval4); + buf[1] = (((c >> 12) & 0x3f) | 0x80); + buf[2] = (((c >> 6) & 0x3f) | 0x80); + buf[3] = ((c & 0x3f) | 0x80); + return 4; + } + return 0; +} + +int XmlUtf16Encode(int charNum, unsigned short *buf) +{ + if (charNum < 0) + return 0; + if (charNum < 0x10000) { + buf[0] = charNum; + return 1; + } + if (charNum < 0x110000) { + charNum -= 0x10000; + buf[0] = (charNum >> 10) + 0xD800; + buf[1] = (charNum & 0x3FF) + 0xDC00; + return 2; + } + return 0; +} + +struct unknown_encoding { + struct normal_encoding normal; + int (*convert)(void *userData, const char *p); + void *userData; + unsigned short utf16[256]; + char utf8[256][4]; +}; + +int XmlSizeOfUnknownEncoding(void) +{ + return sizeof(struct unknown_encoding); +} + +static +int unknown_isName(const ENCODING *enc, const char *p) +{ + int c = ((const struct unknown_encoding *)enc) + ->convert(((const struct unknown_encoding *)enc)->userData, p); + if (c & ~0xFFFF) + return 0; + return UCS2_GET_NAMING(namePages, c >> 8, c & 0xFF); +} + +static +int unknown_isNmstrt(const ENCODING *enc, const char *p) +{ + int c = ((const struct unknown_encoding *)enc) + ->convert(((const struct unknown_encoding *)enc)->userData, p); + if (c & ~0xFFFF) + return 0; + return UCS2_GET_NAMING(nmstrtPages, c >> 8, c & 0xFF); +} + +static +int unknown_isInvalid(const ENCODING *enc, const char *p) +{ + int c = ((const struct unknown_encoding *)enc) + ->convert(((const struct unknown_encoding *)enc)->userData, p); + return (c & ~0xFFFF) || checkCharRefNumber(c) < 0; +} + +static +void unknown_toUtf8(const ENCODING *enc, + const char **fromP, const char *fromLim, + char **toP, const char *toLim) +{ + char buf[XML_UTF8_ENCODE_MAX]; + for (;;) { + const char *utf8; + int n; + if (*fromP == fromLim) + break; + utf8 = ((const struct unknown_encoding *)enc)->utf8[(unsigned char)**fromP]; + n = *utf8++; + if (n == 0) { + int c = ((const struct unknown_encoding *)enc) + ->convert(((const struct unknown_encoding *)enc)->userData, *fromP); + n = XmlUtf8Encode(c, buf); + if (n > toLim - *toP) + break; + utf8 = buf; + *fromP += ((const struct normal_encoding *)enc)->type[(unsigned char)**fromP] + - (BT_LEAD2 - 2); + } + else { + if (n > toLim - *toP) + break; + (*fromP)++; + } + do { + *(*toP)++ = *utf8++; + } while (--n != 0); + } +} + +static +void unknown_toUtf16(const ENCODING *enc, + const char **fromP, const char *fromLim, + unsigned short **toP, const unsigned short *toLim) +{ + while (*fromP != fromLim && *toP != toLim) { + unsigned short c + = ((const struct unknown_encoding *)enc)->utf16[(unsigned char)**fromP]; + if (c == 0) { + c = (unsigned short)((const struct unknown_encoding *)enc) + ->convert(((const struct unknown_encoding *)enc)->userData, *fromP); + *fromP += ((const struct normal_encoding *)enc)->type[(unsigned char)**fromP] + - (BT_LEAD2 - 2); + } + else + (*fromP)++; + *(*toP)++ = c; + } +} + +ENCODING * +XmlInitUnknownEncoding(void *mem, + int *table, + int (*convert)(void *userData, const char *p), + void *userData) +{ + int i; + struct unknown_encoding *e = mem; + for (i = 0; i < (int)sizeof(struct normal_encoding); i++) + ((char *)mem)[i] = ((char *)&latin1_encoding)[i]; + for (i = 0; i < 128; i++) + if (latin1_encoding.type[i] != BT_OTHER + && latin1_encoding.type[i] != BT_NONXML + && table[i] != i) + return 0; + for (i = 0; i < 256; i++) { + int c = table[i]; + if (c == -1) { + e->normal.type[i] = BT_MALFORM; + /* This shouldn't really get used. */ + e->utf16[i] = 0xFFFF; + e->utf8[i][0] = 1; + e->utf8[i][1] = 0; + } + else if (c < 0) { + if (c < -4) + return 0; + e->normal.type[i] = BT_LEAD2 - (c + 2); + e->utf8[i][0] = 0; + e->utf16[i] = 0; + } + else if (c < 0x80) { + if (latin1_encoding.type[c] != BT_OTHER + && latin1_encoding.type[c] != BT_NONXML + && c != i) + return 0; + e->normal.type[i] = latin1_encoding.type[c]; + e->utf8[i][0] = 1; + e->utf8[i][1] = (char)c; + e->utf16[i] = c == 0 ? 0xFFFF : c; + } + else if (checkCharRefNumber(c) < 0) { + e->normal.type[i] = BT_NONXML; + /* This shouldn't really get used. */ + e->utf16[i] = 0xFFFF; + e->utf8[i][0] = 1; + e->utf8[i][1] = 0; + } + else { + if (c > 0xFFFF) + return 0; + if (UCS2_GET_NAMING(nmstrtPages, c >> 8, c & 0xff)) + e->normal.type[i] = BT_NMSTRT; + else if (UCS2_GET_NAMING(namePages, c >> 8, c & 0xff)) + e->normal.type[i] = BT_NAME; + else + e->normal.type[i] = BT_OTHER; + e->utf8[i][0] = (char)XmlUtf8Encode(c, e->utf8[i] + 1); + e->utf16[i] = c; + } + } + e->userData = userData; + e->convert = convert; + if (convert) { + e->normal.isName2 = unknown_isName; + e->normal.isName3 = unknown_isName; + e->normal.isName4 = unknown_isName; + e->normal.isNmstrt2 = unknown_isNmstrt; + e->normal.isNmstrt3 = unknown_isNmstrt; + e->normal.isNmstrt4 = unknown_isNmstrt; + e->normal.isInvalid2 = unknown_isInvalid; + e->normal.isInvalid3 = unknown_isInvalid; + e->normal.isInvalid4 = unknown_isInvalid; + } + e->normal.enc.utf8Convert = unknown_toUtf8; + e->normal.enc.utf16Convert = unknown_toUtf16; + return &(e->normal.enc); +} + +/* If this enumeration is changed, getEncodingIndex and encodings +must also be changed. */ +enum { + UNKNOWN_ENC = -1, + ISO_8859_1_ENC = 0, + US_ASCII_ENC, + UTF_8_ENC, + UTF_16_ENC, + UTF_16BE_ENC, + UTF_16LE_ENC, + /* must match encodingNames up to here */ + NO_ENC +}; + +static const char KW_ISO_8859_1[] = { + ASCII_I, ASCII_S, ASCII_O, ASCII_MINUS, ASCII_8, ASCII_8, ASCII_5, ASCII_9, ASCII_MINUS, ASCII_1, '\0' +}; +static const char KW_US_ASCII[] = { + ASCII_U, ASCII_S, ASCII_MINUS, ASCII_A, ASCII_S, ASCII_C, ASCII_I, ASCII_I, '\0' +}; +static const char KW_UTF_8[] = { + ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_8, '\0' +}; +static const char KW_UTF_16[] = { + ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_1, ASCII_6, '\0' +}; +static const char KW_UTF_16BE[] = { + ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_1, ASCII_6, ASCII_B, ASCII_E, '\0' +}; +static const char KW_UTF_16LE[] = { + ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_1, ASCII_6, ASCII_L, ASCII_E, '\0' +}; + +static +int getEncodingIndex(const char *name) +{ + static const char *encodingNames[] = { + KW_ISO_8859_1, + KW_US_ASCII, + KW_UTF_8, + KW_UTF_16, + KW_UTF_16BE, + KW_UTF_16LE, + }; + int i; + if (name == 0) + return NO_ENC; + for (i = 0; i < (int)(sizeof(encodingNames)/sizeof(encodingNames[0])); i++) + if (streqci(name, encodingNames[i])) + return i; + return UNKNOWN_ENC; +} + +/* For binary compatibility, we store the index of the encoding specified +at initialization in the isUtf16 member. */ + +#define INIT_ENC_INDEX(enc) ((int)(enc)->initEnc.isUtf16) +#define SET_INIT_ENC_INDEX(enc, i) ((enc)->initEnc.isUtf16 = (char)i) + +/* This is what detects the encoding. +encodingTable maps from encoding indices to encodings; +INIT_ENC_INDEX(enc) is the index of the external (protocol) specified encoding; +state is XML_CONTENT_STATE if we're parsing an external text entity, +and XML_PROLOG_STATE otherwise. +*/ + + +static +int initScan(const ENCODING **encodingTable, + const INIT_ENCODING *enc, + int state, + const char *ptr, + const char *end, + const char **nextTokPtr) +{ + const ENCODING **encPtr; + + if (ptr == end) + return XML_TOK_NONE; + encPtr = enc->encPtr; + if (ptr + 1 == end) { + /* only a single byte available for auto-detection */ +#ifndef XML_DTD /* FIXME */ + /* a well-formed document entity must have more than one byte */ + if (state != XML_CONTENT_STATE) + return XML_TOK_PARTIAL; +#endif + /* so we're parsing an external text entity... */ + /* if UTF-16 was externally specified, then we need at least 2 bytes */ + switch (INIT_ENC_INDEX(enc)) { + case UTF_16_ENC: + case UTF_16LE_ENC: + case UTF_16BE_ENC: + return XML_TOK_PARTIAL; + } + switch ((unsigned char)*ptr) { + case 0xFE: + case 0xFF: + case 0xEF: /* possibly first byte of UTF-8 BOM */ + if (INIT_ENC_INDEX(enc) == ISO_8859_1_ENC + && state == XML_CONTENT_STATE) + break; + /* fall through */ + case 0x00: + case 0x3C: + return XML_TOK_PARTIAL; + } + } + else { + switch (((unsigned char)ptr[0] << 8) | (unsigned char)ptr[1]) { + case 0xFEFF: + if (INIT_ENC_INDEX(enc) == ISO_8859_1_ENC + && state == XML_CONTENT_STATE) + break; + *nextTokPtr = ptr + 2; + *encPtr = encodingTable[UTF_16BE_ENC]; + return XML_TOK_BOM; + /* 00 3C is handled in the default case */ + case 0x3C00: + if ((INIT_ENC_INDEX(enc) == UTF_16BE_ENC + || INIT_ENC_INDEX(enc) == UTF_16_ENC) + && state == XML_CONTENT_STATE) + break; + *encPtr = encodingTable[UTF_16LE_ENC]; + return XmlTok(*encPtr, state, ptr, end, nextTokPtr); + case 0xFFFE: + if (INIT_ENC_INDEX(enc) == ISO_8859_1_ENC + && state == XML_CONTENT_STATE) + break; + *nextTokPtr = ptr + 2; + *encPtr = encodingTable[UTF_16LE_ENC]; + return XML_TOK_BOM; + case 0xEFBB: + /* Maybe a UTF-8 BOM (EF BB BF) */ + /* If there's an explicitly specified (external) encoding + of ISO-8859-1 or some flavour of UTF-16 + and this is an external text entity, + don't look for the BOM, + because it might be a legal data. */ + if (state == XML_CONTENT_STATE) { + int e = INIT_ENC_INDEX(enc); + if (e == ISO_8859_1_ENC || e == UTF_16BE_ENC || e == UTF_16LE_ENC || e == UTF_16_ENC) + break; + } + if (ptr + 2 == end) + return XML_TOK_PARTIAL; + if ((unsigned char)ptr[2] == 0xBF) { + *nextTokPtr = ptr + 3; + *encPtr = encodingTable[UTF_8_ENC]; + return XML_TOK_BOM; + } + break; + default: + if (ptr[0] == '\0') { + /* 0 isn't a legal data character. Furthermore a document entity can only + start with ASCII characters. So the only way this can fail to be big-endian + UTF-16 if it it's an external parsed general entity that's labelled as + UTF-16LE. */ + if (state == XML_CONTENT_STATE && INIT_ENC_INDEX(enc) == UTF_16LE_ENC) + break; + *encPtr = encodingTable[UTF_16BE_ENC]; + return XmlTok(*encPtr, state, ptr, end, nextTokPtr); + } + else if (ptr[1] == '\0') { + /* We could recover here in the case: + - parsing an external entity + - second byte is 0 + - no externally specified encoding + - no encoding declaration + by assuming UTF-16LE. But we don't, because this would mean when + presented just with a single byte, we couldn't reliably determine + whether we needed further bytes. */ + if (state == XML_CONTENT_STATE) + break; + *encPtr = encodingTable[UTF_16LE_ENC]; + return XmlTok(*encPtr, state, ptr, end, nextTokPtr); + } + break; + } + } + *encPtr = encodingTable[INIT_ENC_INDEX(enc)]; + return XmlTok(*encPtr, state, ptr, end, nextTokPtr); +} + + +#define NS(x) x +#define ns(x) x +#include "xmltok_ns.c" +#undef NS +#undef ns + +#ifdef XML_NS + +#define NS(x) x ## NS +#define ns(x) x ## _ns + +#include "xmltok_ns.c" + +#undef NS +#undef ns + +ENCODING * +XmlInitUnknownEncodingNS(void *mem, + int *table, + int (*convert)(void *userData, const char *p), + void *userData) +{ + ENCODING *enc = XmlInitUnknownEncoding(mem, table, convert, userData); + if (enc) + ((struct normal_encoding *)enc)->type[ASCII_COLON] = BT_COLON; + return enc; +} + +#endif /* XML_NS */ diff --git a/Utilities/ITK/Utilities/expat/xmltok.h b/Utilities/ITK/Utilities/expat/xmltok.h new file mode 100644 index 0000000000000000000000000000000000000000..cdf49b2cba6ff80488d00e045d7925f4698a2f6c --- /dev/null +++ b/Utilities/ITK/Utilities/expat/xmltok.h @@ -0,0 +1,299 @@ +/* +Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd +See the file COPYING for copying permission. +*/ + +#ifndef XmlTok_INCLUDED +#define XmlTok_INCLUDED 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* The following token may be returned by XmlContentTok */ +#define XML_TOK_TRAILING_RSQB -5 /* ] or ]] at the end of the scan; might be start of + illegal ]]> sequence */ +/* The following tokens may be returned by both XmlPrologTok and XmlContentTok */ +#define XML_TOK_NONE -4 /* The string to be scanned is empty */ +#define XML_TOK_TRAILING_CR -3 /* A CR at the end of the scan; + might be part of CRLF sequence */ +#define XML_TOK_PARTIAL_CHAR -2 /* only part of a multibyte sequence */ +#define XML_TOK_PARTIAL -1 /* only part of a token */ +#define XML_TOK_INVALID 0 + +/* The following tokens are returned by XmlContentTok; some are also + returned by XmlAttributeValueTok, XmlEntityTok, XmlCdataSectionTok */ + +#define XML_TOK_START_TAG_WITH_ATTS 1 +#define XML_TOK_START_TAG_NO_ATTS 2 +#define XML_TOK_EMPTY_ELEMENT_WITH_ATTS 3 /* empty element tag <e/> */ +#define XML_TOK_EMPTY_ELEMENT_NO_ATTS 4 +#define XML_TOK_END_TAG 5 +#define XML_TOK_DATA_CHARS 6 +#define XML_TOK_DATA_NEWLINE 7 +#define XML_TOK_CDATA_SECT_OPEN 8 +#define XML_TOK_ENTITY_REF 9 +#define XML_TOK_CHAR_REF 10 /* numeric character reference */ + +/* The following tokens may be returned by both XmlPrologTok and XmlContentTok */ +#define XML_TOK_PI 11 /* processing instruction */ +#define XML_TOK_XML_DECL 12 /* XML decl or text decl */ +#define XML_TOK_COMMENT 13 +#define XML_TOK_BOM 14 /* Byte order mark */ + +/* The following tokens are returned only by XmlPrologTok */ +#define XML_TOK_PROLOG_S 15 +#define XML_TOK_DECL_OPEN 16 /* <!foo */ +#define XML_TOK_DECL_CLOSE 17 /* > */ +#define XML_TOK_NAME 18 +#define XML_TOK_NMTOKEN 19 +#define XML_TOK_POUND_NAME 20 /* #name */ +#define XML_TOK_OR 21 /* | */ +#define XML_TOK_PERCENT 22 +#define XML_TOK_OPEN_PAREN 23 +#define XML_TOK_CLOSE_PAREN 24 +#define XML_TOK_OPEN_BRACKET 25 +#define XML_TOK_CLOSE_BRACKET 26 +#define XML_TOK_LITERAL 27 +#define XML_TOK_PARAM_ENTITY_REF 28 +#define XML_TOK_INSTANCE_START 29 + +/* The following occur only in element type declarations */ +#define XML_TOK_NAME_QUESTION 30 /* name? */ +#define XML_TOK_NAME_ASTERISK 31 /* name* */ +#define XML_TOK_NAME_PLUS 32 /* name+ */ +#define XML_TOK_COND_SECT_OPEN 33 /* <![ */ +#define XML_TOK_COND_SECT_CLOSE 34 /* ]]> */ +#define XML_TOK_CLOSE_PAREN_QUESTION 35 /* )? */ +#define XML_TOK_CLOSE_PAREN_ASTERISK 36 /* )* */ +#define XML_TOK_CLOSE_PAREN_PLUS 37 /* )+ */ +#define XML_TOK_COMMA 38 + +/* The following token is returned only by XmlAttributeValueTok */ +#define XML_TOK_ATTRIBUTE_VALUE_S 39 + +/* The following token is returned only by XmlCdataSectionTok */ +#define XML_TOK_CDATA_SECT_CLOSE 40 + +/* With namespace processing this is returned by XmlPrologTok + for a name with a colon. */ +#define XML_TOK_PREFIXED_NAME 41 + +#ifdef XML_DTD +#define XML_TOK_IGNORE_SECT 42 +#endif /* XML_DTD */ + +#ifdef XML_DTD +#define XML_N_STATES 4 +#else /* not XML_DTD */ +#define XML_N_STATES 3 +#endif /* not XML_DTD */ + +#define XML_PROLOG_STATE 0 +#define XML_CONTENT_STATE 1 +#define XML_CDATA_SECTION_STATE 2 +#ifdef XML_DTD +#define XML_IGNORE_SECTION_STATE 3 +#endif /* XML_DTD */ + +#define XML_N_LITERAL_TYPES 2 +#define XML_ATTRIBUTE_VALUE_LITERAL 0 +#define XML_ENTITY_VALUE_LITERAL 1 + +/* The size of the buffer passed to XmlUtf8Encode must be at least this. */ +#define XML_UTF8_ENCODE_MAX 4 +/* The size of the buffer passed to XmlUtf16Encode must be at least this. */ +#define XML_UTF16_ENCODE_MAX 2 + +typedef struct position { + /* first line and first column are 0 not 1 */ + unsigned long lineNumber; + unsigned long columnNumber; +} POSITION; + +typedef struct { + const char *name; + const char *valuePtr; + const char *valueEnd; + char normalized; +} ATTRIBUTE; + +struct encoding; +typedef struct encoding ENCODING; + +struct encoding { + int (*scanners[XML_N_STATES])(const ENCODING *, + const char *, + const char *, + const char **); + int (*literalScanners[XML_N_LITERAL_TYPES])(const ENCODING *, + const char *, + const char *, + const char **); + int (*sameName)(const ENCODING *, + const char *, const char *); + int (*nameMatchesAscii)(const ENCODING *, + const char *, const char *, const char *); + int (*nameLength)(const ENCODING *, const char *); + const char *(*skipS)(const ENCODING *, const char *); + int (*getAtts)(const ENCODING *enc, const char *ptr, + int attsMax, ATTRIBUTE *atts); + int (*charRefNumber)(const ENCODING *enc, const char *ptr); + int (*predefinedEntityName)(const ENCODING *, const char *, const char *); + void (*updatePosition)(const ENCODING *, + const char *ptr, + const char *end, + POSITION *); + int (*isPublicId)(const ENCODING *enc, const char *ptr, const char *end, + const char **badPtr); + void (*utf8Convert)(const ENCODING *enc, + const char **fromP, + const char *fromLim, + char **toP, + const char *toLim); + void (*utf16Convert)(const ENCODING *enc, + const char **fromP, + const char *fromLim, + unsigned short **toP, + const unsigned short *toLim); + int minBytesPerChar; + char isUtf8; + char isUtf16; +}; + +/* +Scan the string starting at ptr until the end of the next complete token, +but do not scan past eptr. Return an integer giving the type of token. + +Return XML_TOK_NONE when ptr == eptr; nextTokPtr will not be set. + +Return XML_TOK_PARTIAL when the string does not contain a complete token; +nextTokPtr will not be set. + +Return XML_TOK_INVALID when the string does not start a valid token; nextTokPtr +will be set to point to the character which made the token invalid. + +Otherwise the string starts with a valid token; nextTokPtr will be set to point +to the character following the end of that token. + +Each data character counts as a single token, but adjacent data characters +may be returned together. Similarly for characters in the prolog outside +literals, comments and processing instructions. +*/ + + +#define XmlTok(enc, state, ptr, end, nextTokPtr) \ + (((enc)->scanners[state])(enc, ptr, end, nextTokPtr)) + +#define XmlPrologTok(enc, ptr, end, nextTokPtr) \ + XmlTok(enc, XML_PROLOG_STATE, ptr, end, nextTokPtr) + +#define XmlContentTok(enc, ptr, end, nextTokPtr) \ + XmlTok(enc, XML_CONTENT_STATE, ptr, end, nextTokPtr) + +#define XmlCdataSectionTok(enc, ptr, end, nextTokPtr) \ + XmlTok(enc, XML_CDATA_SECTION_STATE, ptr, end, nextTokPtr) + +#ifdef XML_DTD + +#define XmlIgnoreSectionTok(enc, ptr, end, nextTokPtr) \ + XmlTok(enc, XML_IGNORE_SECTION_STATE, ptr, end, nextTokPtr) + +#endif /* XML_DTD */ + +/* This is used for performing a 2nd-level tokenization on +the content of a literal that has already been returned by XmlTok. */ + +#define XmlLiteralTok(enc, literalType, ptr, end, nextTokPtr) \ + (((enc)->literalScanners[literalType])(enc, ptr, end, nextTokPtr)) + +#define XmlAttributeValueTok(enc, ptr, end, nextTokPtr) \ + XmlLiteralTok(enc, XML_ATTRIBUTE_VALUE_LITERAL, ptr, end, nextTokPtr) + +#define XmlEntityValueTok(enc, ptr, end, nextTokPtr) \ + XmlLiteralTok(enc, XML_ENTITY_VALUE_LITERAL, ptr, end, nextTokPtr) + +#define XmlSameName(enc, ptr1, ptr2) (((enc)->sameName)(enc, ptr1, ptr2)) + +#define XmlNameMatchesAscii(enc, ptr1, end1, ptr2) \ + (((enc)->nameMatchesAscii)(enc, ptr1, end1, ptr2)) + +#define XmlNameLength(enc, ptr) \ + (((enc)->nameLength)(enc, ptr)) + +#define XmlSkipS(enc, ptr) \ + (((enc)->skipS)(enc, ptr)) + +#define XmlGetAttributes(enc, ptr, attsMax, atts) \ + (((enc)->getAtts)(enc, ptr, attsMax, atts)) + +#define XmlCharRefNumber(enc, ptr) \ + (((enc)->charRefNumber)(enc, ptr)) + +#define XmlPredefinedEntityName(enc, ptr, end) \ + (((enc)->predefinedEntityName)(enc, ptr, end)) + +#define XmlUpdatePosition(enc, ptr, end, pos) \ + (((enc)->updatePosition)(enc, ptr, end, pos)) + +#define XmlIsPublicId(enc, ptr, end, badPtr) \ + (((enc)->isPublicId)(enc, ptr, end, badPtr)) + +#define XmlUtf8Convert(enc, fromP, fromLim, toP, toLim) \ + (((enc)->utf8Convert)(enc, fromP, fromLim, toP, toLim)) + +#define XmlUtf16Convert(enc, fromP, fromLim, toP, toLim) \ + (((enc)->utf16Convert)(enc, fromP, fromLim, toP, toLim)) + +typedef struct { + ENCODING initEnc; + const ENCODING **encPtr; +} INIT_ENCODING; + +int XmlParseXmlDecl(int isGeneralTextEntity, + const ENCODING *enc, + const char *ptr, + const char *end, + const char **badPtr, + const char **versionPtr, + const char **versionEndPtr, + const char **encodingNamePtr, + const ENCODING **namedEncodingPtr, + int *standalonePtr); + +int XmlInitEncoding(INIT_ENCODING *, const ENCODING **, const char *name); +const ENCODING *XmlGetUtf8InternalEncoding(void); +const ENCODING *XmlGetUtf16InternalEncoding(void); +int XmlUtf8Encode(int charNumber, char *buf); +int XmlUtf16Encode(int charNumber, unsigned short *buf); + +int XmlSizeOfUnknownEncoding(void); +ENCODING * +XmlInitUnknownEncoding(void *mem, + int *table, + int (*conv)(void *userData, const char *p), + void *userData); + +int XmlParseXmlDeclNS(int isGeneralTextEntity, + const ENCODING *enc, + const char *ptr, + const char *end, + const char **badPtr, + const char **versionPtr, + const char **versionEndPtr, + const char **encodingNamePtr, + const ENCODING **namedEncodingPtr, + int *standalonePtr); +int XmlInitEncodingNS(INIT_ENCODING *, const ENCODING **, const char *name); +const ENCODING *XmlGetUtf8InternalEncodingNS(void); +const ENCODING *XmlGetUtf16InternalEncodingNS(void); +ENCODING * +XmlInitUnknownEncodingNS(void *mem, + int *table, + int (*conv)(void *userData, const char *p), + void *userData); +#ifdef __cplusplus +} +#endif + +#endif /* not XmlTok_INCLUDED */ diff --git a/Utilities/ITK/Utilities/expat/xmltok_impl.c b/Utilities/ITK/Utilities/expat/xmltok_impl.c new file mode 100644 index 0000000000000000000000000000000000000000..652ce1bd825db6bd26c02ee05ab23ab42f490e41 --- /dev/null +++ b/Utilities/ITK/Utilities/expat/xmltok_impl.c @@ -0,0 +1,1773 @@ +/* +Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd +See the file COPYING for copying permission. +*/ + +#ifndef IS_INVALID_CHAR +#define IS_INVALID_CHAR(enc, ptr, n) (0) +#endif + +#define INVALID_LEAD_CASE(n, ptr, nextTokPtr) \ + case BT_LEAD ## n: \ + if (end - ptr < n) \ + return XML_TOK_PARTIAL_CHAR; \ + if (IS_INVALID_CHAR(enc, ptr, n)) { \ + *(nextTokPtr) = (ptr); \ + return XML_TOK_INVALID; \ + } \ + ptr += n; \ + break; + +#define INVALID_CASES(ptr, nextTokPtr) \ + INVALID_LEAD_CASE(2, ptr, nextTokPtr) \ + INVALID_LEAD_CASE(3, ptr, nextTokPtr) \ + INVALID_LEAD_CASE(4, ptr, nextTokPtr) \ + case BT_NONXML: \ + case BT_MALFORM: \ + case BT_TRAIL: \ + *(nextTokPtr) = (ptr); \ + return XML_TOK_INVALID; + +#define CHECK_NAME_CASE(n, enc, ptr, end, nextTokPtr) \ + case BT_LEAD ## n: \ + if (end - ptr < n) \ + return XML_TOK_PARTIAL_CHAR; \ + if (!IS_NAME_CHAR(enc, ptr, n)) { \ + *nextTokPtr = ptr; \ + return XML_TOK_INVALID; \ + } \ + ptr += n; \ + break; + +#define CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) \ + case BT_NONASCII: \ + if (!IS_NAME_CHAR_MINBPC(enc, ptr)) { \ + *nextTokPtr = ptr; \ + return XML_TOK_INVALID; \ + } \ + case BT_NMSTRT: \ + case BT_HEX: \ + case BT_DIGIT: \ + case BT_NAME: \ + case BT_MINUS: \ + ptr += MINBPC(enc); \ + break; \ + CHECK_NAME_CASE(2, enc, ptr, end, nextTokPtr) \ + CHECK_NAME_CASE(3, enc, ptr, end, nextTokPtr) \ + CHECK_NAME_CASE(4, enc, ptr, end, nextTokPtr) + +#define CHECK_NMSTRT_CASE(n, enc, ptr, end, nextTokPtr) \ + case BT_LEAD ## n: \ + if (end - ptr < n) \ + return XML_TOK_PARTIAL_CHAR; \ + if (!IS_NMSTRT_CHAR(enc, ptr, n)) { \ + *nextTokPtr = ptr; \ + return XML_TOK_INVALID; \ + } \ + ptr += n; \ + break; + +#define CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) \ + case BT_NONASCII: \ + if (!IS_NMSTRT_CHAR_MINBPC(enc, ptr)) { \ + *nextTokPtr = ptr; \ + return XML_TOK_INVALID; \ + } \ + case BT_NMSTRT: \ + case BT_HEX: \ + ptr += MINBPC(enc); \ + break; \ + CHECK_NMSTRT_CASE(2, enc, ptr, end, nextTokPtr) \ + CHECK_NMSTRT_CASE(3, enc, ptr, end, nextTokPtr) \ + CHECK_NMSTRT_CASE(4, enc, ptr, end, nextTokPtr) + +#ifndef PREFIX +#define PREFIX(ident) ident +#endif + +/* ptr points to character following "<!-" */ + +static +int PREFIX(scanComment)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) +{ + if (ptr != end) { + if (!CHAR_MATCHES(enc, ptr, ASCII_MINUS)) { + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + ptr += MINBPC(enc); + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { + INVALID_CASES(ptr, nextTokPtr) + case BT_MINUS: + if ((ptr += MINBPC(enc)) == end) + return XML_TOK_PARTIAL; + if (CHAR_MATCHES(enc, ptr, ASCII_MINUS)) { + if ((ptr += MINBPC(enc)) == end) + return XML_TOK_PARTIAL; + if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) { + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_COMMENT; + } + break; + default: + ptr += MINBPC(enc); + break; + } + } + } + return XML_TOK_PARTIAL; +} + +/* ptr points to character following "<!" */ + +static +int PREFIX(scanDecl)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) +{ + if (ptr == end) + return XML_TOK_PARTIAL; + switch (BYTE_TYPE(enc, ptr)) { + case BT_MINUS: + return PREFIX(scanComment)(enc, ptr + MINBPC(enc), end, nextTokPtr); + case BT_LSQB: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_COND_SECT_OPEN; + case BT_NMSTRT: + case BT_HEX: + ptr += MINBPC(enc); + break; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { + case BT_PERCNT: + if (ptr + MINBPC(enc) == end) + return XML_TOK_PARTIAL; + /* don't allow <!ENTITY% foo "whatever"> */ + switch (BYTE_TYPE(enc, ptr + MINBPC(enc))) { + case BT_S: case BT_CR: case BT_LF: case BT_PERCNT: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + /* fall through */ + case BT_S: case BT_CR: case BT_LF: + *nextTokPtr = ptr; + return XML_TOK_DECL_OPEN; + case BT_NMSTRT: + case BT_HEX: + ptr += MINBPC(enc); + break; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + } + return XML_TOK_PARTIAL; +} + +static +int PREFIX(checkPiTarget)(const ENCODING *enc, const char *ptr, const char *end, int *tokPtr) +{ + int upper = 0; + itkExpatUnused(enc); + *tokPtr = XML_TOK_PI; + if (end - ptr != MINBPC(enc)*3) + return 1; + switch (BYTE_TO_ASCII(enc, ptr)) { + case ASCII_x: + break; + case ASCII_X: + upper = 1; + break; + default: + return 1; + } + ptr += MINBPC(enc); + switch (BYTE_TO_ASCII(enc, ptr)) { + case ASCII_m: + break; + case ASCII_M: + upper = 1; + break; + default: + return 1; + } + ptr += MINBPC(enc); + switch (BYTE_TO_ASCII(enc, ptr)) { + case ASCII_l: + break; + case ASCII_L: + upper = 1; + break; + default: + return 1; + } + if (upper) + return 0; + *tokPtr = XML_TOK_XML_DECL; + return 1; +} + +/* ptr points to character following "<?" */ + +static +int PREFIX(scanPi)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) +{ + int tok; + const char *target = ptr; + if (ptr == end) + return XML_TOK_PARTIAL; + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) + case BT_S: case BT_CR: case BT_LF: + if (!PREFIX(checkPiTarget)(enc, target, ptr, &tok)) { + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + ptr += MINBPC(enc); + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { + INVALID_CASES(ptr, nextTokPtr) + case BT_QUEST: + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_PARTIAL; + if (CHAR_MATCHES(enc, ptr, ASCII_GT)) { + *nextTokPtr = ptr + MINBPC(enc); + return tok; + } + break; + default: + ptr += MINBPC(enc); + break; + } + } + return XML_TOK_PARTIAL; + case BT_QUEST: + if (!PREFIX(checkPiTarget)(enc, target, ptr, &tok)) { + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_PARTIAL; + if (CHAR_MATCHES(enc, ptr, ASCII_GT)) { + *nextTokPtr = ptr + MINBPC(enc); + return tok; + } + /* fall through */ + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + } + return XML_TOK_PARTIAL; +} + + +static +int PREFIX(scanCdataSection)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) +{ + static const char CDATA_LSQB[] = { ASCII_C, ASCII_D, ASCII_A, ASCII_T, ASCII_A, ASCII_LSQB }; + int i; + itkExpatUnused(enc); + /* CDATA[ */ + if (end - ptr < 6 * MINBPC(enc)) + return XML_TOK_PARTIAL; + for (i = 0; i < 6; i++, ptr += MINBPC(enc)) { + if (!CHAR_MATCHES(enc, ptr, CDATA_LSQB[i])) { + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + } + *nextTokPtr = ptr; + return XML_TOK_CDATA_SECT_OPEN; +} + +static +int PREFIX(cdataSectionTok)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) +{ + if (ptr == end) + return XML_TOK_NONE; + if (MINBPC(enc) > 1) { + size_t n = end - ptr; + if (n & (MINBPC(enc) - 1)) { + n &= ~(MINBPC(enc) - 1); + if (n == 0) + return XML_TOK_PARTIAL; + end = ptr + n; + } + } + switch (BYTE_TYPE(enc, ptr)) { + case BT_RSQB: + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_PARTIAL; + if (!CHAR_MATCHES(enc, ptr, ASCII_RSQB)) + break; + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_PARTIAL; + if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) { + ptr -= MINBPC(enc); + break; + } + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_CDATA_SECT_CLOSE; + case BT_CR: + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_PARTIAL; + if (BYTE_TYPE(enc, ptr) == BT_LF) + ptr += MINBPC(enc); + *nextTokPtr = ptr; + return XML_TOK_DATA_NEWLINE; + case BT_LF: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_DATA_NEWLINE; + INVALID_CASES(ptr, nextTokPtr) + default: + ptr += MINBPC(enc); + break; + } + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { +#define LEAD_CASE(n) \ + case BT_LEAD ## n: \ + if (end - ptr < n || IS_INVALID_CHAR(enc, ptr, n)) { \ + *nextTokPtr = ptr; \ + return XML_TOK_DATA_CHARS; \ + } \ + ptr += n; \ + break; + LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) +#undef LEAD_CASE + case BT_NONXML: + case BT_MALFORM: + case BT_TRAIL: + case BT_CR: + case BT_LF: + case BT_RSQB: + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + default: + ptr += MINBPC(enc); + break; + } + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; +} + +/* ptr points to character following "</" */ + +static +int PREFIX(scanEndTag)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) +{ + if (ptr == end) + return XML_TOK_PARTIAL; + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) + case BT_S: case BT_CR: case BT_LF: + for (ptr += MINBPC(enc); ptr != end; ptr += MINBPC(enc)) { + switch (BYTE_TYPE(enc, ptr)) { + case BT_S: case BT_CR: case BT_LF: + break; + case BT_GT: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_END_TAG; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + } + return XML_TOK_PARTIAL; +#ifdef XML_NS + case BT_COLON: + /* no need to check qname syntax here, since end-tag must match exactly */ + ptr += MINBPC(enc); + break; +#endif + case BT_GT: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_END_TAG; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + } + return XML_TOK_PARTIAL; +} + +/* ptr points to character following "&#X" */ + +static +int PREFIX(scanHexCharRef)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) +{ + if (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { + case BT_DIGIT: + case BT_HEX: + break; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + for (ptr += MINBPC(enc); ptr != end; ptr += MINBPC(enc)) { + switch (BYTE_TYPE(enc, ptr)) { + case BT_DIGIT: + case BT_HEX: + break; + case BT_SEMI: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_CHAR_REF; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + } + } + return XML_TOK_PARTIAL; +} + +/* ptr points to character following "&#" */ + +static +int PREFIX(scanCharRef)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) +{ + if (ptr != end) { + if (CHAR_MATCHES(enc, ptr, ASCII_x)) + return PREFIX(scanHexCharRef)(enc, ptr + MINBPC(enc), end, nextTokPtr); + switch (BYTE_TYPE(enc, ptr)) { + case BT_DIGIT: + break; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + for (ptr += MINBPC(enc); ptr != end; ptr += MINBPC(enc)) { + switch (BYTE_TYPE(enc, ptr)) { + case BT_DIGIT: + break; + case BT_SEMI: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_CHAR_REF; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + } + } + return XML_TOK_PARTIAL; +} + +/* ptr points to character following "&" */ + +static +int PREFIX(scanRef)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) +{ + if (ptr == end) + return XML_TOK_PARTIAL; + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) + case BT_NUM: + return PREFIX(scanCharRef)(enc, ptr + MINBPC(enc), end, nextTokPtr); + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) + case BT_SEMI: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_ENTITY_REF; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + } + return XML_TOK_PARTIAL; +} + +/* ptr points to character following first character of attribute name */ + +static +int PREFIX(scanAtts)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) +{ +#ifdef XML_NS + int hadColon = 0; +#endif + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) +#ifdef XML_NS + case BT_COLON: + if (hadColon) { + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + hadColon = 1; + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_PARTIAL; + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + break; +#endif + case BT_S: case BT_CR: case BT_LF: + for (;;) { + int t; + + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_PARTIAL; + t = BYTE_TYPE(enc, ptr); + if (t == BT_EQUALS) + break; + switch (t) { + case BT_S: + case BT_LF: + case BT_CR: + break; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + } + /* fall through */ + case BT_EQUALS: + { + int open; +#ifdef XML_NS + hadColon = 0; +#endif + for (;;) { + + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_PARTIAL; + open = BYTE_TYPE(enc, ptr); + if (open == BT_QUOT || open == BT_APOS) + break; + switch (open) { + case BT_S: + case BT_LF: + case BT_CR: + break; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + } + ptr += MINBPC(enc); + /* in attribute value */ + for (;;) { + int t; + if (ptr == end) + return XML_TOK_PARTIAL; + t = BYTE_TYPE(enc, ptr); + if (t == open) + break; + switch (t) { + INVALID_CASES(ptr, nextTokPtr) + case BT_AMP: + { + int tok = PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, &ptr); + if (tok <= 0) { + if (tok == XML_TOK_INVALID) + *nextTokPtr = ptr; + return tok; + } + break; + } + case BT_LT: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + default: + ptr += MINBPC(enc); + break; + } + } + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_PARTIAL; + switch (BYTE_TYPE(enc, ptr)) { + case BT_S: + case BT_CR: + case BT_LF: + break; + case BT_SOL: + goto sol; + case BT_GT: + goto gt; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + /* ptr points to closing quote */ + for (;;) { + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_PARTIAL; + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) + case BT_S: case BT_CR: case BT_LF: + continue; + case BT_GT: + gt: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_START_TAG_WITH_ATTS; + case BT_SOL: + sol: + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_PARTIAL; + if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) { + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_EMPTY_ELEMENT_WITH_ATTS; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + break; + } + break; + } + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + } + return XML_TOK_PARTIAL; +} + +/* ptr points to character following "<" */ + +static +int PREFIX(scanLt)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) +{ +#ifdef XML_NS + int hadColon; +#endif + if (ptr == end) + return XML_TOK_PARTIAL; + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) + case BT_EXCL: + if ((ptr += MINBPC(enc)) == end) + return XML_TOK_PARTIAL; + switch (BYTE_TYPE(enc, ptr)) { + case BT_MINUS: + return PREFIX(scanComment)(enc, ptr + MINBPC(enc), end, nextTokPtr); + case BT_LSQB: + return PREFIX(scanCdataSection)(enc, ptr + MINBPC(enc), end, nextTokPtr); + } + *nextTokPtr = ptr; + return XML_TOK_INVALID; + case BT_QUEST: + return PREFIX(scanPi)(enc, ptr + MINBPC(enc), end, nextTokPtr); + case BT_SOL: + return PREFIX(scanEndTag)(enc, ptr + MINBPC(enc), end, nextTokPtr); + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } +#ifdef XML_NS + hadColon = 0; +#endif + /* we have a start-tag */ + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) +#ifdef XML_NS + case BT_COLON: + if (hadColon) { + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + hadColon = 1; + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_PARTIAL; + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + break; +#endif + case BT_S: case BT_CR: case BT_LF: + { + ptr += MINBPC(enc); + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) + case BT_GT: + goto gt; + case BT_SOL: + goto sol; + case BT_S: case BT_CR: case BT_LF: + ptr += MINBPC(enc); + continue; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + return PREFIX(scanAtts)(enc, ptr, end, nextTokPtr); + } + return XML_TOK_PARTIAL; + } + case BT_GT: + gt: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_START_TAG_NO_ATTS; + case BT_SOL: + sol: + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_PARTIAL; + if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) { + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_EMPTY_ELEMENT_NO_ATTS; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + } + return XML_TOK_PARTIAL; +} + +static +int PREFIX(contentTok)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) +{ + if (ptr == end) + return XML_TOK_NONE; + if (MINBPC(enc) > 1) { + size_t n = end - ptr; + if (n & (MINBPC(enc) - 1)) { + n &= ~(MINBPC(enc) - 1); + if (n == 0) + return XML_TOK_PARTIAL; + end = ptr + n; + } + } + switch (BYTE_TYPE(enc, ptr)) { + case BT_LT: + return PREFIX(scanLt)(enc, ptr + MINBPC(enc), end, nextTokPtr); + case BT_AMP: + return PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, nextTokPtr); + case BT_CR: + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_TRAILING_CR; + if (BYTE_TYPE(enc, ptr) == BT_LF) + ptr += MINBPC(enc); + *nextTokPtr = ptr; + return XML_TOK_DATA_NEWLINE; + case BT_LF: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_DATA_NEWLINE; + case BT_RSQB: + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_TRAILING_RSQB; + if (!CHAR_MATCHES(enc, ptr, ASCII_RSQB)) + break; + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_TRAILING_RSQB; + if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) { + ptr -= MINBPC(enc); + break; + } + *nextTokPtr = ptr; + return XML_TOK_INVALID; + INVALID_CASES(ptr, nextTokPtr) + default: + ptr += MINBPC(enc); + break; + } + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { +#define LEAD_CASE(n) \ + case BT_LEAD ## n: \ + if (end - ptr < n || IS_INVALID_CHAR(enc, ptr, n)) { \ + *nextTokPtr = ptr; \ + return XML_TOK_DATA_CHARS; \ + } \ + ptr += n; \ + break; + LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) +#undef LEAD_CASE + case BT_RSQB: + if (ptr + MINBPC(enc) != end) { + if (!CHAR_MATCHES(enc, ptr + MINBPC(enc), ASCII_RSQB)) { + ptr += MINBPC(enc); + break; + } + if (ptr + 2*MINBPC(enc) != end) { + if (!CHAR_MATCHES(enc, ptr + 2*MINBPC(enc), ASCII_GT)) { + ptr += MINBPC(enc); + break; + } + *nextTokPtr = ptr + 2*MINBPC(enc); + return XML_TOK_INVALID; + } + } + /* fall through */ + case BT_AMP: + case BT_LT: + case BT_NONXML: + case BT_MALFORM: + case BT_TRAIL: + case BT_CR: + case BT_LF: + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + default: + ptr += MINBPC(enc); + break; + } + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; +} + +/* ptr points to character following "%" */ + +static +int PREFIX(scanPercent)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) +{ + if (ptr == end) + return XML_TOK_PARTIAL; + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) + case BT_S: case BT_LF: case BT_CR: case BT_PERCNT: + *nextTokPtr = ptr; + return XML_TOK_PERCENT; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) + case BT_SEMI: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_PARAM_ENTITY_REF; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + } + return XML_TOK_PARTIAL; +} + +static +int PREFIX(scanPoundName)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) +{ + if (ptr == end) + return XML_TOK_PARTIAL; + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) + case BT_CR: case BT_LF: case BT_S: + case BT_RPAR: case BT_GT: case BT_PERCNT: case BT_VERBAR: + *nextTokPtr = ptr; + return XML_TOK_POUND_NAME; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + } + return -XML_TOK_POUND_NAME; +} + +static +int PREFIX(scanLit)(int open, const ENCODING *enc, + const char *ptr, const char *end, + const char **nextTokPtr) +{ + while (ptr != end) { + int t = BYTE_TYPE(enc, ptr); + switch (t) { + INVALID_CASES(ptr, nextTokPtr) + case BT_QUOT: + case BT_APOS: + ptr += MINBPC(enc); + if (t != open) + break; + if (ptr == end) + return -XML_TOK_LITERAL; + *nextTokPtr = ptr; + switch (BYTE_TYPE(enc, ptr)) { + case BT_S: case BT_CR: case BT_LF: + case BT_GT: case BT_PERCNT: case BT_LSQB: + return XML_TOK_LITERAL; + default: + return XML_TOK_INVALID; + } + default: + ptr += MINBPC(enc); + break; + } + } + return XML_TOK_PARTIAL; +} + +static +int PREFIX(prologTok)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) +{ + int tok; + if (ptr == end) + return XML_TOK_NONE; + if (MINBPC(enc) > 1) { + size_t n = end - ptr; + if (n & (MINBPC(enc) - 1)) { + n &= ~(MINBPC(enc) - 1); + if (n == 0) + return XML_TOK_PARTIAL; + end = ptr + n; + } + } + switch (BYTE_TYPE(enc, ptr)) { + case BT_QUOT: + return PREFIX(scanLit)(BT_QUOT, enc, ptr + MINBPC(enc), end, nextTokPtr); + case BT_APOS: + return PREFIX(scanLit)(BT_APOS, enc, ptr + MINBPC(enc), end, nextTokPtr); + case BT_LT: + { + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_PARTIAL; + switch (BYTE_TYPE(enc, ptr)) { + case BT_EXCL: + return PREFIX(scanDecl)(enc, ptr + MINBPC(enc), end, nextTokPtr); + case BT_QUEST: + return PREFIX(scanPi)(enc, ptr + MINBPC(enc), end, nextTokPtr); + case BT_NMSTRT: + case BT_HEX: + case BT_NONASCII: + case BT_LEAD2: + case BT_LEAD3: + case BT_LEAD4: + *nextTokPtr = ptr - MINBPC(enc); + return XML_TOK_INSTANCE_START; + } + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + case BT_CR: + if (ptr + MINBPC(enc) == end) + return -XML_TOK_PROLOG_S; + /* fall through */ + case BT_S: case BT_LF: + for (;;) { + ptr += MINBPC(enc); + if (ptr == end) + break; + switch (BYTE_TYPE(enc, ptr)) { + case BT_S: case BT_LF: + break; + case BT_CR: + /* don't split CR/LF pair */ + if (ptr + MINBPC(enc) != end) + break; + /* fall through */ + default: + *nextTokPtr = ptr; + return XML_TOK_PROLOG_S; + } + } + *nextTokPtr = ptr; + return XML_TOK_PROLOG_S; + case BT_PERCNT: + return PREFIX(scanPercent)(enc, ptr + MINBPC(enc), end, nextTokPtr); + case BT_COMMA: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_COMMA; + case BT_LSQB: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_OPEN_BRACKET; + case BT_RSQB: + ptr += MINBPC(enc); + if (ptr == end) + return -XML_TOK_CLOSE_BRACKET; + if (CHAR_MATCHES(enc, ptr, ASCII_RSQB)) { + if (ptr + MINBPC(enc) == end) + return XML_TOK_PARTIAL; + if (CHAR_MATCHES(enc, ptr + MINBPC(enc), ASCII_GT)) { + *nextTokPtr = ptr + 2*MINBPC(enc); + return XML_TOK_COND_SECT_CLOSE; + } + } + *nextTokPtr = ptr; + return XML_TOK_CLOSE_BRACKET; + case BT_LPAR: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_OPEN_PAREN; + case BT_RPAR: + ptr += MINBPC(enc); + if (ptr == end) + return -XML_TOK_CLOSE_PAREN; + switch (BYTE_TYPE(enc, ptr)) { + case BT_AST: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_CLOSE_PAREN_ASTERISK; + case BT_QUEST: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_CLOSE_PAREN_QUESTION; + case BT_PLUS: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_CLOSE_PAREN_PLUS; + case BT_CR: case BT_LF: case BT_S: + case BT_GT: case BT_COMMA: case BT_VERBAR: + case BT_RPAR: + *nextTokPtr = ptr; + return XML_TOK_CLOSE_PAREN; + } + *nextTokPtr = ptr; + return XML_TOK_INVALID; + case BT_VERBAR: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_OR; + case BT_GT: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_DECL_CLOSE; + case BT_NUM: + return PREFIX(scanPoundName)(enc, ptr + MINBPC(enc), end, nextTokPtr); +#define LEAD_CASE(n) \ + case BT_LEAD ## n: \ + if (end - ptr < n) \ + return XML_TOK_PARTIAL_CHAR; \ + if (IS_NMSTRT_CHAR(enc, ptr, n)) { \ + ptr += n; \ + tok = XML_TOK_NAME; \ + break; \ + } \ + if (IS_NAME_CHAR(enc, ptr, n)) { \ + ptr += n; \ + tok = XML_TOK_NMTOKEN; \ + break; \ + } \ + *nextTokPtr = ptr; \ + return XML_TOK_INVALID; + LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) +#undef LEAD_CASE + case BT_NMSTRT: + case BT_HEX: + tok = XML_TOK_NAME; + ptr += MINBPC(enc); + break; + case BT_DIGIT: + case BT_NAME: + case BT_MINUS: +#ifdef XML_NS + case BT_COLON: +#endif + tok = XML_TOK_NMTOKEN; + ptr += MINBPC(enc); + break; + case BT_NONASCII: + if (IS_NMSTRT_CHAR_MINBPC(enc, ptr)) { + ptr += MINBPC(enc); + tok = XML_TOK_NAME; + break; + } + if (IS_NAME_CHAR_MINBPC(enc, ptr)) { + ptr += MINBPC(enc); + tok = XML_TOK_NMTOKEN; + break; + } + /* fall through */ + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) + case BT_GT: case BT_RPAR: case BT_COMMA: + case BT_VERBAR: case BT_LSQB: case BT_PERCNT: + case BT_S: case BT_CR: case BT_LF: + *nextTokPtr = ptr; + return tok; +#ifdef XML_NS + case BT_COLON: + ptr += MINBPC(enc); + switch (tok) { + case XML_TOK_NAME: + if (ptr == end) + return XML_TOK_PARTIAL; + tok = XML_TOK_PREFIXED_NAME; + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) + default: + tok = XML_TOK_NMTOKEN; + break; + } + break; + case XML_TOK_PREFIXED_NAME: + tok = XML_TOK_NMTOKEN; + break; + } + break; +#endif + case BT_PLUS: + if (tok == XML_TOK_NMTOKEN) { + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_NAME_PLUS; + case BT_AST: + if (tok == XML_TOK_NMTOKEN) { + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_NAME_ASTERISK; + case BT_QUEST: + if (tok == XML_TOK_NMTOKEN) { + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_NAME_QUESTION; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + } + return -tok; +} + +static +int PREFIX(attributeValueTok)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) +{ + const char *start; + if (ptr == end) + return XML_TOK_NONE; + start = ptr; + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { +#define LEAD_CASE(n) \ + case BT_LEAD ## n: ptr += n; break; + LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) +#undef LEAD_CASE + case BT_AMP: + if (ptr == start) + return PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, nextTokPtr); + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + case BT_LT: + /* this is for inside entity references */ + *nextTokPtr = ptr; + return XML_TOK_INVALID; + case BT_LF: + if (ptr == start) { + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_DATA_NEWLINE; + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + case BT_CR: + if (ptr == start) { + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_TRAILING_CR; + if (BYTE_TYPE(enc, ptr) == BT_LF) + ptr += MINBPC(enc); + *nextTokPtr = ptr; + return XML_TOK_DATA_NEWLINE; + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + case BT_S: + if (ptr == start) { + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_ATTRIBUTE_VALUE_S; + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + default: + ptr += MINBPC(enc); + break; + } + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; +} + +static +int PREFIX(entityValueTok)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) +{ + const char *start; + if (ptr == end) + return XML_TOK_NONE; + start = ptr; + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { +#define LEAD_CASE(n) \ + case BT_LEAD ## n: ptr += n; break; + LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) +#undef LEAD_CASE + case BT_AMP: + if (ptr == start) + return PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, nextTokPtr); + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + case BT_PERCNT: + if (ptr == start) { + int tok = PREFIX(scanPercent)(enc, ptr + MINBPC(enc), + end, nextTokPtr); + return (tok == XML_TOK_PERCENT) ? XML_TOK_INVALID : tok; + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + case BT_LF: + if (ptr == start) { + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_DATA_NEWLINE; + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + case BT_CR: + if (ptr == start) { + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_TRAILING_CR; + if (BYTE_TYPE(enc, ptr) == BT_LF) + ptr += MINBPC(enc); + *nextTokPtr = ptr; + return XML_TOK_DATA_NEWLINE; + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + default: + ptr += MINBPC(enc); + break; + } + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; +} + +#ifdef XML_DTD + +static +int PREFIX(ignoreSectionTok)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) +{ + int level = 0; + if (MINBPC(enc) > 1) { + size_t n = end - ptr; + if (n & (MINBPC(enc) - 1)) { + n &= ~(MINBPC(enc) - 1); + end = ptr + n; + } + } + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { + INVALID_CASES(ptr, nextTokPtr) + case BT_LT: + if ((ptr += MINBPC(enc)) == end) + return XML_TOK_PARTIAL; + if (CHAR_MATCHES(enc, ptr, ASCII_EXCL)) { + if ((ptr += MINBPC(enc)) == end) + return XML_TOK_PARTIAL; + if (CHAR_MATCHES(enc, ptr, ASCII_LSQB)) { + ++level; + ptr += MINBPC(enc); + } + } + break; + case BT_RSQB: + if ((ptr += MINBPC(enc)) == end) + return XML_TOK_PARTIAL; + if (CHAR_MATCHES(enc, ptr, ASCII_RSQB)) { + if ((ptr += MINBPC(enc)) == end) + return XML_TOK_PARTIAL; + if (CHAR_MATCHES(enc, ptr, ASCII_GT)) { + ptr += MINBPC(enc); + if (level == 0) { + *nextTokPtr = ptr; + return XML_TOK_IGNORE_SECT; + } + --level; + } + } + break; + default: + ptr += MINBPC(enc); + break; + } + } + return XML_TOK_PARTIAL; +} + +#endif /* XML_DTD */ + +static +int PREFIX(isPublicId)(const ENCODING *enc, const char *ptr, const char *end, + const char **badPtr) +{ + ptr += MINBPC(enc); + end -= MINBPC(enc); + for (; ptr != end; ptr += MINBPC(enc)) { + switch (BYTE_TYPE(enc, ptr)) { + case BT_DIGIT: + case BT_HEX: + case BT_MINUS: + case BT_APOS: + case BT_LPAR: + case BT_RPAR: + case BT_PLUS: + case BT_COMMA: + case BT_SOL: + case BT_EQUALS: + case BT_QUEST: + case BT_CR: + case BT_LF: + case BT_SEMI: + case BT_EXCL: + case BT_AST: + case BT_PERCNT: + case BT_NUM: +#ifdef XML_NS + case BT_COLON: +#endif + break; + case BT_S: + if (CHAR_MATCHES(enc, ptr, ASCII_TAB)) { + *badPtr = ptr; + return 0; + } + break; + case BT_NAME: + case BT_NMSTRT: + if (!(BYTE_TO_ASCII(enc, ptr) & ~0x7f)) + break; + default: + switch (BYTE_TO_ASCII(enc, ptr)) { + case 0x24: /* $ */ + case 0x40: /* @ */ + break; + default: + *badPtr = ptr; + return 0; + } + break; + } + } + return 1; +} + +/* This must only be called for a well-formed start-tag or empty element tag. +Returns the number of attributes. Pointers to the first attsMax attributes +are stored in atts. */ + +static +int PREFIX(getAtts)(const ENCODING *enc, const char *ptr, + int attsMax, ATTRIBUTE *atts) +{ + enum { other, inName, inValue } state = inName; + int nAtts = 0; + int open = 0; /* defined when state == inValue; + initialization just to shut up compilers */ + + for (ptr += MINBPC(enc);; ptr += MINBPC(enc)) { + switch (BYTE_TYPE(enc, ptr)) { +#define START_NAME \ + if (state == other) { \ + if (nAtts < attsMax) { \ + atts[nAtts].name = ptr; \ + atts[nAtts].normalized = 1; \ + } \ + state = inName; \ + } +#define LEAD_CASE(n) \ + case BT_LEAD ## n: START_NAME ptr += (n - MINBPC(enc)); break; + LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) +#undef LEAD_CASE + case BT_NONASCII: + case BT_NMSTRT: + case BT_HEX: + START_NAME + break; +#undef START_NAME + case BT_QUOT: + if (state != inValue) { + if (nAtts < attsMax) + atts[nAtts].valuePtr = ptr + MINBPC(enc); + state = inValue; + open = BT_QUOT; + } + else if (open == BT_QUOT) { + state = other; + if (nAtts < attsMax) + atts[nAtts].valueEnd = ptr; + nAtts++; + } + break; + case BT_APOS: + if (state != inValue) { + if (nAtts < attsMax) + atts[nAtts].valuePtr = ptr + MINBPC(enc); + state = inValue; + open = BT_APOS; + } + else if (open == BT_APOS) { + state = other; + if (nAtts < attsMax) + atts[nAtts].valueEnd = ptr; + nAtts++; + } + break; + case BT_AMP: + if (nAtts < attsMax) + atts[nAtts].normalized = 0; + break; + case BT_S: + if (state == inName) + state = other; + else if (state == inValue + && nAtts < attsMax + && atts[nAtts].normalized + && (ptr == atts[nAtts].valuePtr + || BYTE_TO_ASCII(enc, ptr) != ASCII_SPACE + || BYTE_TO_ASCII(enc, ptr + MINBPC(enc)) == ASCII_SPACE + || BYTE_TYPE(enc, ptr + MINBPC(enc)) == open)) + atts[nAtts].normalized = 0; + break; + case BT_CR: case BT_LF: + /* This case ensures that the first attribute name is counted + Apart from that we could just change state on the quote. */ + if (state == inName) + state = other; + else if (state == inValue && nAtts < attsMax) + atts[nAtts].normalized = 0; + break; + case BT_GT: + case BT_SOL: + if (state != inValue) + return nAtts; + break; + default: + break; + } + } + /* not reached */ +} + +static +int PREFIX(charRefNumber)(const ENCODING *enc, const char *ptr) +{ + int result = 0; + itkExpatUnused(enc); + /* skip &# */ + ptr += 2*MINBPC(enc); + if (CHAR_MATCHES(enc, ptr, ASCII_x)) { + for (ptr += MINBPC(enc); !CHAR_MATCHES(enc, ptr, ASCII_SEMI); ptr += MINBPC(enc)) { + int c = BYTE_TO_ASCII(enc, ptr); + switch (c) { + case ASCII_0: case ASCII_1: case ASCII_2: case ASCII_3: case ASCII_4: + case ASCII_5: case ASCII_6: case ASCII_7: case ASCII_8: case ASCII_9: + result <<= 4; + result |= (c - ASCII_0); + break; + case ASCII_A: case ASCII_B: case ASCII_C: case ASCII_D: case ASCII_E: case ASCII_F: + result <<= 4; + result += 10 + (c - ASCII_A); + break; + case ASCII_a: case ASCII_b: case ASCII_c: case ASCII_d: case ASCII_e: case ASCII_f: + result <<= 4; + result += 10 + (c - ASCII_a); + break; + } + if (result >= 0x110000) + return -1; + } + } + else { + for (; !CHAR_MATCHES(enc, ptr, ASCII_SEMI); ptr += MINBPC(enc)) { + int c = BYTE_TO_ASCII(enc, ptr); + result *= 10; + result += (c - ASCII_0); + if (result >= 0x110000) + return -1; + } + } + return checkCharRefNumber(result); +} + +static +int PREFIX(predefinedEntityName)(const ENCODING *enc, const char *ptr, const char *end) +{ + itkExpatUnused(enc); + switch ((end - ptr)/MINBPC(enc)) { + case 2: + if (CHAR_MATCHES(enc, ptr + MINBPC(enc), ASCII_t)) { + switch (BYTE_TO_ASCII(enc, ptr)) { + case ASCII_l: + return ASCII_LT; + case ASCII_g: + return ASCII_GT; + } + } + break; + case 3: + if (CHAR_MATCHES(enc, ptr, ASCII_a)) { + ptr += MINBPC(enc); + if (CHAR_MATCHES(enc, ptr, ASCII_m)) { + ptr += MINBPC(enc); + if (CHAR_MATCHES(enc, ptr, ASCII_p)) + return ASCII_AMP; + } + } + break; + case 4: + switch (BYTE_TO_ASCII(enc, ptr)) { + case ASCII_q: + ptr += MINBPC(enc); + if (CHAR_MATCHES(enc, ptr, ASCII_u)) { + ptr += MINBPC(enc); + if (CHAR_MATCHES(enc, ptr, ASCII_o)) { + ptr += MINBPC(enc); + if (CHAR_MATCHES(enc, ptr, ASCII_t)) + return ASCII_QUOT; + } + } + break; + case ASCII_a: + ptr += MINBPC(enc); + if (CHAR_MATCHES(enc, ptr, ASCII_p)) { + ptr += MINBPC(enc); + if (CHAR_MATCHES(enc, ptr, ASCII_o)) { + ptr += MINBPC(enc); + if (CHAR_MATCHES(enc, ptr, ASCII_s)) + return ASCII_APOS; + } + } + break; + } + } + return 0; +} + +static +int PREFIX(sameName)(const ENCODING *enc, const char *ptr1, const char *ptr2) +{ + for (;;) { + switch (BYTE_TYPE(enc, ptr1)) { +#define LEAD_CASE(n) \ + case BT_LEAD ## n: \ + if (*ptr1++ != *ptr2++) \ + return 0; + LEAD_CASE(4) LEAD_CASE(3) LEAD_CASE(2) +#undef LEAD_CASE + /* fall through */ + if (*ptr1++ != *ptr2++) + return 0; + break; + case BT_NONASCII: + case BT_NMSTRT: +#ifdef XML_NS + case BT_COLON: +#endif + case BT_HEX: + case BT_DIGIT: + case BT_NAME: + case BT_MINUS: + if (*ptr2++ != *ptr1++) + return 0; + if (MINBPC(enc) > 1) { + if (*ptr2++ != *ptr1++) + return 0; + if (MINBPC(enc) > 2) { + if (*ptr2++ != *ptr1++) + return 0; + if (MINBPC(enc) > 3) { + if (*ptr2++ != *ptr1++) + return 0; + } + } + } + break; + default: + if (MINBPC(enc) == 1 && *ptr1 == *ptr2) + return 1; + switch (BYTE_TYPE(enc, ptr2)) { + case BT_LEAD2: + case BT_LEAD3: + case BT_LEAD4: + case BT_NONASCII: + case BT_NMSTRT: +#ifdef XML_NS + case BT_COLON: +#endif + case BT_HEX: + case BT_DIGIT: + case BT_NAME: + case BT_MINUS: + return 0; + default: + return 1; + } + } + } + /* not reached */ +} + +static +int PREFIX(nameMatchesAscii)(const ENCODING *enc, const char *ptr1, + const char *end1, const char *ptr2) +{ + itkExpatUnused(enc); + for (; *ptr2; ptr1 += MINBPC(enc), ptr2++) { + if (ptr1 == end1) + return 0; + if (!CHAR_MATCHES(enc, ptr1, *ptr2)) + return 0; + } + return ptr1 == end1; +} + +static +int PREFIX(nameLength)(const ENCODING *enc, const char *ptr) +{ + const char *start = ptr; + for (;;) { + switch (BYTE_TYPE(enc, ptr)) { +#define LEAD_CASE(n) \ + case BT_LEAD ## n: ptr += n; break; + LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) +#undef LEAD_CASE + case BT_NONASCII: + case BT_NMSTRT: +#ifdef XML_NS + case BT_COLON: +#endif + case BT_HEX: + case BT_DIGIT: + case BT_NAME: + case BT_MINUS: + ptr += MINBPC(enc); + break; + default: + return ptr - start; + } + } +} + +static +const char *PREFIX(skipS)(const ENCODING *enc, const char *ptr) +{ + for (;;) { + switch (BYTE_TYPE(enc, ptr)) { + case BT_LF: + case BT_CR: + case BT_S: + ptr += MINBPC(enc); + break; + default: + return ptr; + } + } +} + +static +void PREFIX(updatePosition)(const ENCODING *enc, + const char *ptr, + const char *end, + POSITION *pos) +{ + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { +#define LEAD_CASE(n) \ + case BT_LEAD ## n: \ + ptr += n; \ + break; + LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) +#undef LEAD_CASE + case BT_LF: + pos->columnNumber = (unsigned)-1; + pos->lineNumber++; + ptr += MINBPC(enc); + break; + case BT_CR: + pos->lineNumber++; + ptr += MINBPC(enc); + if (ptr != end && BYTE_TYPE(enc, ptr) == BT_LF) + ptr += MINBPC(enc); + pos->columnNumber = (unsigned)-1; + break; + default: + ptr += MINBPC(enc); + break; + } + pos->columnNumber++; + } +} + +#undef DO_LEAD_CASE +#undef MULTIBYTE_CASES +#undef INVALID_CASES +#undef CHECK_NAME_CASE +#undef CHECK_NAME_CASES +#undef CHECK_NMSTRT_CASE +#undef CHECK_NMSTRT_CASES diff --git a/Utilities/ITK/Utilities/expat/xmltok_impl.h b/Utilities/ITK/Utilities/expat/xmltok_impl.h new file mode 100644 index 0000000000000000000000000000000000000000..da0ea60a657d660770878804e3962426e84d58ef --- /dev/null +++ b/Utilities/ITK/Utilities/expat/xmltok_impl.h @@ -0,0 +1,46 @@ +/* +Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd +See the file COPYING for copying permission. +*/ + +enum { + BT_NONXML, + BT_MALFORM, + BT_LT, + BT_AMP, + BT_RSQB, + BT_LEAD2, + BT_LEAD3, + BT_LEAD4, + BT_TRAIL, + BT_CR, + BT_LF, + BT_GT, + BT_QUOT, + BT_APOS, + BT_EQUALS, + BT_QUEST, + BT_EXCL, + BT_SOL, + BT_SEMI, + BT_NUM, + BT_LSQB, + BT_S, + BT_NMSTRT, + BT_COLON, + BT_HEX, + BT_DIGIT, + BT_NAME, + BT_MINUS, + BT_OTHER, /* known not to be a name or name start character */ + BT_NONASCII, /* might be a name or name start character */ + BT_PERCNT, + BT_LPAR, + BT_RPAR, + BT_AST, + BT_PLUS, + BT_COMMA, + BT_VERBAR +}; + +#include <stddef.h> diff --git a/Utilities/ITK/Utilities/expat/xmltok_ns.c b/Utilities/ITK/Utilities/expat/xmltok_ns.c new file mode 100644 index 0000000000000000000000000000000000000000..fa78adffce1be1658ea7f899b81390e1085e590a --- /dev/null +++ b/Utilities/ITK/Utilities/expat/xmltok_ns.c @@ -0,0 +1,98 @@ +const ENCODING *NS(XmlGetUtf8InternalEncoding)(void) +{ + return &ns(internal_utf8_encoding).enc; +} + +const ENCODING *NS(XmlGetUtf16InternalEncoding)(void) +{ +#if XML_BYTE_ORDER == 12 + return &ns(internal_little2_encoding).enc; +#elif XML_BYTE_ORDER == 21 + return &ns(internal_big2_encoding).enc; +#else + const short n = 1; + return *(const char *)&n ? &ns(internal_little2_encoding).enc : &ns(internal_big2_encoding).enc; +#endif +} + +static +const ENCODING *NS(encodings)[] = { + &ns(latin1_encoding).enc, + &ns(ascii_encoding).enc, + &ns(utf8_encoding).enc, + &ns(big2_encoding).enc, + &ns(big2_encoding).enc, + &ns(little2_encoding).enc, + &ns(utf8_encoding).enc /* NO_ENC */ +}; + +static +int NS(initScanProlog)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) +{ + return initScan(NS(encodings), (const INIT_ENCODING *)enc, XML_PROLOG_STATE, ptr, end, nextTokPtr); +} + +static +int NS(initScanContent)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) +{ + return initScan(NS(encodings), (const INIT_ENCODING *)enc, XML_CONTENT_STATE, ptr, end, nextTokPtr); +} + +int NS(XmlInitEncoding)(INIT_ENCODING *p, const ENCODING **encPtr, const char *name) +{ + int i = getEncodingIndex(name); + if (i == UNKNOWN_ENC) + return 0; + SET_INIT_ENC_INDEX(p, i); + p->initEnc.scanners[XML_PROLOG_STATE] = NS(initScanProlog); + p->initEnc.scanners[XML_CONTENT_STATE] = NS(initScanContent); + p->initEnc.updatePosition = initUpdatePosition; + p->encPtr = encPtr; + *encPtr = &(p->initEnc); + return 1; +} + +static +const ENCODING *NS(findEncoding)(const ENCODING *enc, const char *ptr, const char *end) +{ +#define ENCODING_MAX 128 + char buf[ENCODING_MAX]; + char *p = buf; + int i; + XmlUtf8Convert(enc, &ptr, end, &p, p + ENCODING_MAX - 1); + if (ptr != end) + return 0; + *p = 0; + if (streqci(buf, KW_UTF_16) && enc->minBytesPerChar == 2) + return enc; + i = getEncodingIndex(buf); + if (i == UNKNOWN_ENC) + return 0; + return NS(encodings)[i]; +} + +int NS(XmlParseXmlDecl)(int isGeneralTextEntity, + const ENCODING *enc, + const char *ptr, + const char *end, + const char **badPtr, + const char **versionPtr, + const char **versionEndPtr, + const char **encodingName, + const ENCODING **encoding, + int *standalone) +{ + return doParseXmlDecl(NS(findEncoding), + isGeneralTextEntity, + enc, + ptr, + end, + badPtr, + versionPtr, + versionEndPtr, + encodingName, + encoding, + standalone); +} diff --git a/Utilities/ITK/Utilities/gdcm/.cvsignore b/Utilities/ITK/Utilities/gdcm/.cvsignore new file mode 100644 index 0000000000000000000000000000000000000000..55f3c305b346534da50cc956633188a67442ba98 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/.cvsignore @@ -0,0 +1,37 @@ +Makefile.in +Makefile +config.cache +config.guess +config.log +config.status +config.sub +configure +libtool +ltmain.sh +aclocal.m4 +autom4te.cache +*.pyc +build +dist +MANIFEST +gdcm*.tar.gz +gdcm.spec +*Debug* +*Release* +*gdcmData* +*.ncb +*.opt +*Python.cxx +*lib* +CMakeCCompiler.cmake +CMakeCXXCompiler.cmake +CMakeCache.txt +CMakeOutput.log +CMakeSystem.cmake +CMakeTmp +DartConfiguration.tcl +DartTestfile.txt +cmake.check_cache +cmake.check_depends +cmake.depends +gdcmConfigure.h diff --git a/Utilities/ITK/Utilities/gdcm/AUTHORS b/Utilities/ITK/Utilities/gdcm/AUTHORS new file mode 100644 index 0000000000000000000000000000000000000000..ffda87cb491ce0e126684755793b3116f39ff7e2 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/AUTHORS @@ -0,0 +1,8 @@ +Boix Eric (Creatis) +Florez Leonardo (Creatis/Theralys) +Ibanez Luis (Kitware) +Malaterre Mathieu (Kitware) +Olart Emmanuel (Theralys) +Regrain Benoit (Creatis) +Rouet Jean-Michel (Philips) +Roux Jean-Pierre (Creatis) diff --git a/Utilities/ITK/Utilities/gdcm/CMake/CTestCustom.ctest.in b/Utilities/ITK/Utilities/gdcm/CMake/CTestCustom.ctest.in new file mode 100644 index 0000000000000000000000000000000000000000..58cad9a5079b2d39f3ff525c0ebe2f59a5411118 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/CMake/CTestCustom.ctest.in @@ -0,0 +1,14 @@ +SET(CTEST_CUSTOM_WARNING_EXCEPTION + ${CTEST_CUSTOM_WARNING_EXCEPTION} + "comparison is always (true|false) due to limited range of data type" + "ld: warning prebinding disabled because \\((__TEXT|__DATA|__LINKEDIT) segment \\(address = 0x[a-f0-9]+ size = 0x[a-f0-9]+\\) of (.*) overlaps with (__LINKEDIT|__TEXT|__DATA) segment \\(address = 0x[a-f0-9]+ size = 0x[a-f0-9]+\\) of (.*)" + "ld: warning prebinding disabled because dependent library: (.*).dylib is not prebound" + "gdcmjasper/(.*) warning: statement not reached" + "warning: string length `[0-9]+' is greater than the length `509' ISO C89 compilers are required to support" + "warning: string length '[0-9]+' is greater than the length '509' ISO C89 compilers are required to support" + "/.../gdcm/src/gdcmjasper/src/libjasper/(.*)" + "\"/.../gdcm/src/gdcmjpeg/jccolor.c\", line 107: warning: integer overflow detected: op \"<<\"" + "Warning W8004.*gdcmjasper[\\]src[\\]libjasper.*" + ) + + diff --git a/Utilities/ITK/Utilities/gdcm/CMake/FindDicom3Tools.cmake b/Utilities/ITK/Utilities/gdcm/CMake/FindDicom3Tools.cmake new file mode 100644 index 0000000000000000000000000000000000000000..d8176f4d00ec723c4c13a26cbae0559914ea9c91 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/CMake/FindDicom3Tools.cmake @@ -0,0 +1,34 @@ +# +# this module looks for Dicom3Tools, well right now only dciodvfy +# +# DCIODVFY_EXECUTABLE - the full path to the dciodvfy +# DCIODVFY_FOUND - If false, don't attempt to use dciodvfy + +# dicom3tools are funny to build you'll need imake +# Anyway in order not to pollute your system, you can do an in-source build +# and install which should be clean enough: +# +# ./Configure +# imake -I./config -DInstallInTopDir +# make World +# make install (will copy in ./bin) +# +# then all you need to do is export an env var DICOM3TOOLS pointing to that dir + +FIND_PROGRAM(DCIODVFY_EXECUTABLE + dciodvfy + "/tmp/" + "$ENV{DICOM3TOOLS}/bin" + "$ENV{DICOM3TOOLS}/bin/1.2.6.8." + ) + +MARK_AS_ADVANCED( + DCIODVFY_EXECUTABLE + ) + +IF (NOT DCIODVFY_EXECUTABLE) + SET(DCIODVFY_FOUND "NO") +ELSE (NOT DCIODVFY_EXECUTABLE) + SET(DCIODVFY_FOUND "YES") +ENDIF (NOT DCIODVFY_EXECUTABLE) + diff --git a/Utilities/ITK/Utilities/gdcm/CMake/FindRsync.cmake b/Utilities/ITK/Utilities/gdcm/CMake/FindRsync.cmake new file mode 100644 index 0000000000000000000000000000000000000000..6e8c6f896fa94c2f8167551e3e0c434786586538 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/CMake/FindRsync.cmake @@ -0,0 +1,19 @@ +# +# This module finds if rsync is installed +# +# RSYNC_EXECUTABLE = full path to the pike binary +# +# Typical usage for gdcm is: +# rsync -avH --delete [options] rsync.creatis.insa-lyon.fr::module localdir +# Compression option is: -z + +FIND_PROGRAM(RSYNC_EXECUTABLE + NAMES rsync + PATHS + /usr/bin + /usr/local/bin + ) + +MARK_AS_ADVANCED( + RSYNC_EXECUTABLE + ) diff --git a/Utilities/ITK/Utilities/gdcm/CMake/gdcmTestFUNCTION.cxx b/Utilities/ITK/Utilities/gdcm/CMake/gdcmTestFUNCTION.cxx new file mode 100644 index 0000000000000000000000000000000000000000..cceaa2e0a46c56f3513cb4c7bb42b17c7fc09a0b --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/CMake/gdcmTestFUNCTION.cxx @@ -0,0 +1,38 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmTestFUNCTION.cxx,v $ + Language: C++ + Date: $Date: 2006/02/02 18:26:18 $ + Version: $Revision: 1.2 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +// Minimal test for existence of __FUNCTION__ pseudo-macro +#include <string.h> + +int TestFUNCTION() +{ +#ifdef __BORLANDC__ + #ifndef __FUNCTION__ + #define __FUNCTION__ __FUNC__ + #endif +#endif + const char *f = __FUNCTION__; + int r = strcmp( "TestFUNCTION", f); + return r; +} + +int main() +{ + return TestFUNCTION(); +} + diff --git a/Utilities/ITK/Utilities/gdcm/CMake/gdcmValgrind.supp b/Utilities/ITK/Utilities/gdcm/CMake/gdcmValgrind.supp new file mode 100644 index 0000000000000000000000000000000000000000..f152efeb3a06b9880182af6153ceb25a73c4c470 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/CMake/gdcmValgrind.supp @@ -0,0 +1,129 @@ +{ + <insert a suppression name here> + Memcheck:Param + write(buf) + fun:__write_nocancel + obj:/usr/X11R6/lib/libX11.so.6.2 + fun:_X11TransWrite + obj:/usr/X11R6/lib/libX11.so.6.2 +} +{ + <insert a suppression name here> + Memcheck:Free + fun:free + fun:__GI__dl_deallocate_tls + fun:vgArch_thread_exit + fun:thread_exit_wrapper +} +{ + <insert a suppression name here> + Memcheck:Leak + fun:malloc + fun:__cxa_get_globals + fun:_ZSt18uncaught_exceptionv + fun:_ZNSo6sentryD1Ev +} +{ + <insert a suppression name here> + Memcheck:Leak + fun:malloc + fun:XextCreateExtension + fun:__glXInitialize + fun:glXGetConfig +} +{ + <insert a suppression name here> + Memcheck:Leak + fun:calloc + fun:_dlerror_run + fun:dlsym + fun:__errno_location +} +{ + <insert a suppression name here> + Memcheck:Leak + fun:malloc + fun:OpenDriver + fun:__glXRegisterExtensions + fun:__glXNewIndirectAPI +} +{ + <insert a suppression name here> + Memcheck:Leak + fun:malloc + fun:_dl_map_object_internal + fun:openaux + fun:_dl_catch_error_internal +} +{ + <insert a suppression name here> + Memcheck:Leak + fun:malloc + fun:_dl_map_object_deps_internal + fun:dl_open_worker + fun:_dl_catch_error_internal +} +{ + <insert a suppression name here> + Memcheck:Leak + fun:malloc + fun:__glXstrdup + fun:OpenDriver + fun:__glXRegisterExtensions +} +{ + <insert a suppression name here> + Memcheck:Leak + fun:malloc + fun:_dl_map_object_internal + fun:dl_open_worker + fun:_dl_catch_error_internal +} +{ + <insert a suppression name here> + Memcheck:Leak + fun:malloc + fun:_dl_new_object + fun:_dl_map_object_from_fd + fun:_dl_map_object_internal +} +{ + <insert a suppression name here> + Memcheck:Leak + fun:malloc + fun:dl_open_worker + fun:_dl_catch_error_internal + fun:__GI__dl_open +} +{ + <insert a suppression name here> + Memcheck:Leak + fun:calloc + fun:_dl_check_map_versions_internal + fun:dl_open_worker + fun:_dl_catch_error_internal +} +{ + <insert a suppression name here> + Memcheck:Leak + fun:calloc + fun:_dl_new_object + fun:_dl_map_object_from_fd + fun:_dl_map_object_internal +} +{ + <insert a suppression name here> + Memcheck:Leak + fun:malloc + fun:__glXNewIndirectAPI + fun:glXMakeCurrent + fun:_ZN22vtkXOpenGLRenderWindow11MakeCurrentEv +} +{ + <insert a suppression name here> + Memcheck:Leak + fun:malloc + fun:__fgl_glapi_add_entrypoint + fun:__driRegisterExtensions + fun:__glXRegisterExtensions +} diff --git a/Utilities/ITK/Utilities/gdcm/CMakeLists.txt b/Utilities/ITK/Utilities/gdcm/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..529ba7033d1a61848b5c636f9bdb394ecb98e4d1 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/CMakeLists.txt @@ -0,0 +1,151 @@ +PROJECT(GDCM) +CMAKE_MINIMUM_REQUIRED(VERSION 2.0) +# okay in fact you need at least cmake 2.0.4 to get swig working properly + +#----------------------------------------------------------------------------- +# GDCM version number, usefull for packaging and doxygen doc: +SET(GDCM_MAJOR_VERSION 1) +SET(GDCM_MINOR_VERSION 2) +SET(GDCM_BUILD_VERSION 0) +SET(GDCM_VERSION + "${GDCM_MAJOR_VERSION}.${GDCM_MINOR_VERSION}.${GDCM_BUILD_VERSION}") + +#----------------------------------------------------------------------------- +# datadir in CMake: +SET(GDCM_DATA_DIR "/share/gdcm/" CACHE INTERNAL + "Install location for data (relative to prefix).") +MARK_AS_ADVANCED(GDCM_DATA_DIR) + +#----------------------------------------------------------------------------- +# Provide compatibility options. +OPTION(GDCM_LEGACY_REMOVE "Remove all legacy code completely." OFF) +OPTION(GDCM_LEGACY_SILENT "Silence all legacy code messages." OFF) +MARK_AS_ADVANCED(GDCM_LEGACY_REMOVE GDCM_LEGACY_SILENT) + +#----------------------------------------------------------------------------- +# Build shared lib by default +SET(GDCM_BUILD_SHARED_LIBS ${BUILD_SHARED_LIBS}) + +#OPTION(GDCM_DEBUG "Turn verbosity of some statement ON." OFF) +#MARK_AS_ADVANCED(GDCM_DEBUG) +SET(GDCM_DEBUG 0) + +#----------------------------------------------------------------------------- +# Test if compiler defines the pseudo-macro __FUNCTION__ +IF("GDCM_COMPILER_HAS_FUNCTION" MATCHES "^GDCM_COMPILER_HAS_FUNCTION$") + MESSAGE(STATUS "Checking support for __FUNCTION__ in compiler") + TRY_COMPILE(GDCM_COMPILER_HAS_FUNCTION + ${GDCM_BINARY_DIR}/CMakeTmp/Function + ${GDCM_SOURCE_DIR}/CMake/gdcmTestFUNCTION.cxx + OUTPUT_VARIABLE OUTPUT) + IF(GDCM_COMPILER_HAS_FUNCTION) + MESSAGE(STATUS "Checking support for __FUNCTION__ -- yes") + SET(GDCM_COMPILER_HAS_FUNCTION 1 CACHE INTERNAL "Support for extension C __FUNCTION__") + WRITE_FILE(${CMAKE_BINARY_DIR}/CMakeOutput.log + "Determining if the C compiler supports __FUNCTION__ " + "passed with the following output:\n" + "${OUTPUT}\n" APPEND) + ELSE(GDCM_COMPILER_HAS_FUNCTION) + MESSAGE(STATUS "Checking support for __FUNCTION__ -- no") + SET(GDCM_COMPILER_HAS_FUNCTION 0 CACHE INTERNAL "Support for extension C __FUNCTION__") + WRITE_FILE(${CMAKE_BINARY_DIR}/CMakeError.log + "Determining if the C compiler supports __FUNCTION__ " + "failed with the following output:\n" + "${OUTPUT}\n" APPEND) + ENDIF(GDCM_COMPILER_HAS_FUNCTION) +ENDIF("GDCM_COMPILER_HAS_FUNCTION" MATCHES "^GDCM_COMPILER_HAS_FUNCTION$") + +#----------------------------------------------------------------------------- +# Build directory on which many applications depend +SUBDIRS( + Dicts + src +) + +# Set the place for the public dictionary, must be set before gdcmConfigure.h +SET( GDCM_PUB_DICT_PATH "${CMAKE_INSTALL_PREFIX}${GDCM_DATA_DIR}") + +#----------------------------------------------------------------------------- +# Big endian thing: +INCLUDE (${CMAKE_ROOT}/Modules/TestBigEndian.cmake) +TEST_BIG_ENDIAN(GDCM_WORDS_BIGENDIAN) + +INCLUDE (${CMAKE_ROOT}/Modules/CheckIncludeFile.cmake) +CHECK_INCLUDE_FILE("stdint.h" CMAKE_HAVE_STDINT_H) +IF(UNIX) #Avoid polluting Win32 cmakecache + CHECK_INCLUDE_FILE("inttypes.h" CMAKE_HAVE_INTTYPES_H) +ENDIF(UNIX) + +# Check if header file exists and add it to the list. +INCLUDE (${CMAKE_ROOT}/Modules/CheckIncludeFiles.cmake) +MACRO(CHECK_INCLUDE_FILE_CONCAT FILE VARIABLE) + CHECK_INCLUDE_FILES("${GDCM_INCLUDES};${FILE}" ${VARIABLE}) + IF(${VARIABLE}) + SET(GDCM_INCLUDES ${GDCM_INCLUDES} ${FILE}) + ENDIF(${VARIABLE}) +ENDMACRO(CHECK_INCLUDE_FILE_CONCAT) + +# Need those header for GetMacAddress in Util +# This is tricky as you need to figure out the proper order to +# test the inclusion of files +CHECK_INCLUDE_FILE_CONCAT("unistd.h" CMAKE_HAVE_UNISTD_H) +CHECK_INCLUDE_FILE_CONCAT("stdlib.h" CMAKE_HAVE_STDLIB_H) +IF(UNIX) #Avoid polluting Win32 cmakecache + CHECK_INCLUDE_FILE_CONCAT("sys/ioctl.h" CMAKE_HAVE_SYS_IOCTL_H) + CHECK_INCLUDE_FILE_CONCAT("sys/socket.h" CMAKE_HAVE_SYS_SOCKET_H) + CHECK_INCLUDE_FILE_CONCAT("sys/sockio.h" CMAKE_HAVE_SYS_SOCKIO_H) + CHECK_INCLUDE_FILE_CONCAT("net/if.h" CMAKE_HAVE_NET_IF_H) + CHECK_INCLUDE_FILE_CONCAT("netinet/in.h" CMAKE_HAVE_NETINET_IN_H) + CHECK_INCLUDE_FILE_CONCAT("net/if_dl.h" CMAKE_HAVE_NET_IF_DL_H) + CHECK_INCLUDE_FILE_CONCAT("net/if_arp.h" CMAKE_HAVE_NET_IF_ARP_H) +ENDIF(UNIX) + +#----------------------------------------------------------------------------- +# Test if os defines a lenght for sockaddr +# only doing the test when we have sys/socket +IF( ${CMAKE_HAVE_SYS_SOCKET_H} ) + IF("HAVE_SA_LEN" MATCHES "^HAVE_SA_LEN$") + STRING(ASCII 35 POUND) + FILE(WRITE ${GDCM_BINARY_DIR}/CMakeTmp/gdcmTestHAVESALEN.c + "${POUND}include <sys/types.h>\n" + "${POUND}include <sys/socket.h>\n" + "int main() { struct sockaddr sa; sa.sa_len = 0; }") + MESSAGE(STATUS "Checking if ifreq has a sa_len") + TRY_COMPILE(HAVE_SA_LEN + ${GDCM_BINARY_DIR} + ${GDCM_BINARY_DIR}/CMakeTmp/gdcmTestHAVESALEN.c + OUTPUT_VARIABLE OUTPUT) + IF(HAVE_SA_LEN) + MESSAGE(STATUS "Checking if ifreq has a sa_len -- yes") + SET(HAVE_SA_LEN 1 CACHE INTERNAL "Support if ifreq has a sa_len") + WRITE_FILE(${CMAKE_BINARY_DIR}/CMakeOutput.log + "Determining if ifreq has a sa_len" + "passed with the following output:\n" + "${OUTPUT}\n" APPEND) + ELSE(HAVE_SA_LEN) + MESSAGE(STATUS "Checking if ifreq has a sa_len -- no") + SET(HAVE_SA_LEN 0 CACHE INTERNAL "Support if ifreq has a sa_len") + WRITE_FILE(${CMAKE_BINARY_DIR}/CMakeError.log + "Determining if ifreq has a sa_len" + "failed with the following output:\n" + "${OUTPUT}\n" APPEND) + ENDIF(HAVE_SA_LEN) + ENDIF("HAVE_SA_LEN" MATCHES "^HAVE_SA_LEN$") +ENDIF( ${CMAKE_HAVE_SYS_SOCKET_H} ) + +#----------------------------------------------------------------------------- +# Do the OpenJPEG export thing +IF (WIN32) + IF (BUILD_SHARED_LIBS) + SET(OPJ_EXPORTS 1) + ELSE (BUILD_SHARED_LIBS) + SET(OPJ_STATIC 1) + ENDIF (BUILD_SHARED_LIBS) +ENDIF (WIN32) + + +CONFIGURE_FILE(${GDCM_SOURCE_DIR}/gdcmConfigure.h.in + ${GDCM_BINARY_DIR}/gdcmConfigure.h @ONLY IMMEDIATE) + +INSTALL_FILES(/include/InsightToolkit/gdcm/src .h gdcmConfigure.h) + diff --git a/Utilities/ITK/Utilities/gdcm/ChangeLog b/Utilities/ITK/Utilities/gdcm/ChangeLog new file mode 100644 index 0000000000000000000000000000000000000000..d1ced5d25ff7cc7b61603ec049e41a37a328992e --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/ChangeLog @@ -0,0 +1,4121 @@ +Thu Aug 25 16:59:49 2005 by jpr + gdcmBinEntry.cxx + Now Print displays the BinEntry Content (if it's printable, and loaded) + Usefull for a lot od Implicit VR 'Bin'Entry (if we knew there VR, they wouldn't + be Bin ...) + Appreciate the difference having a look at PrintFile result for + gdcmData/SIEMENS_MAGNETOM-12-MONO2-FileSeq0.dcm. + +Thu Aug 25 16:55:47 2005 by jpr + gdcmUtil.cxx + Add methods to check the 'printability' of a bin area + +Thu Aug 25 15:45:40 2005 by jpr + gdcmBinEntry.cxx + According to Mathieu's suggestion, Print now display FL BinEntries in a human + readable form + +Thu Aug 25 15:12:43 2005 by jpr + gdcmDocEntry.cxx + According to Mathieu's suggestion, *all* the elements 0x000 + are now named 'Group Length' (even if they belong to a Shadow Group') + +Wed Aug 24 14:09:13 2005 by jpr + gdcmDocEntry.cxx,h, gdcmDocEntrySet.cxx,h + Removal of QD patch for Private Sequence + Immplicit VR. + Add a clean solution (Backtracking if an Item Starter is found + out of any SQItem) + +Tue Aug 23 14:57:49 2005 by jpr + gdcmDocument.cxx + Brutal patch, waiting till we find a clever way to guess + if a doc entry is a Sequence, + - when it's odd number + - and the file is Implicit VR Transfert Syntax +It solves temporarily some Philips Medical Systems image problems + +Mon Aug 22 18:17:54 200 by jpr + gdcmUtil.cxx + Save a *few* microseconds at run time : inline method Util::GetVersion() + ;-) + +Tue Aug 23 14:58:49 2005 by jpr + gdcmSeqEntry.cxx, gdcmDocEntry.cxx + Improve 'Print' methods + +Sat Aug 20 11:10:24 2005by jpr + TestWriteSimple.cxx + Use new style FileHelper contructor + +Sat Aug 20 11:04:50 2005 by jpr + gdcmFileHelper.cxx + FileHelper::Initialize() doesn't call GrabInformationFromFile(), + in order not to do the job twice when using new style FileHelper Constructor. + +Fri Aug 19 18:31:07 2005 by malaterre + gdcmCommon.h + ENH: Provide a GetVersion function, apparently need for python + +Fri Aug 19 15:12:15 2005 by jpr + gdcmFileHelper.cxx + Initialize UserFunction pointer to 0, even for 'deprecated' form + of constructor. + +Sat Jul 30 20:27:00 2005 by jpr + gdcmFileHelper.cxx, gdcmPixelReadConvertor.cxx + User is now allowed to pass a Pointer to a function of his own + to allow modification of pixel order (i.e. : Mirror, TopDown, ) + to gdcm::FileHeleper, using SetUserFunction(userSuppliedFunction) + described as : void userSuppliedFunction(uint8_t *im, gdcm::File *f); + NB : the "uint8_t *" type of first param is just for prototyping. + User will Cast it according what he founds with f->GetPixelType() + See ctkgdcmSerieViewer for an example + +Sat Jul 30 20:13:24 2005 by jpr + gdcmSerieHelper.cxx + Add SerieHelper::IsCoherent() method to allow checking that the files with same + Serie UID have the same sizes and pixel type. + +Fri Jul 29 17:07:16 2005 by jpr + gdcmSerieHelper.cxx + User may now use + SetSortOrderToDirect() or SetSortOrderToReverse() + to choose the ways the File* will be sorted. + +Thu Jul 21 06:55:50 2005 by jpr + AnonymizeDicomDir.cxx, AnomymizeNoLoad.cxx, PrintFile.cxx, PrintDicomDir.cxx + Unify user interface + +Thu Jul 21 06:55:30 2005 by jpr + exSerieHelper.cxx + Add an example of use for SerieHelper + +Thu Jul 21 07:00:15 2005 by jpr + gdcmSerieHelper.cxx + Extend 'Restriction' syntax : + void SerieHelper::AddRestriction(uint16_t group, uint16_t elem, + std::string const &value, int op) + op belongs to : + /// \brief comparaison operators + enum CompOperators { + GDCM_EQUAL = 0, + GDCM_DIFFERENT, + GDCM_GREATER, + GDCM_GREATEROREQUAL, + GDCM_LESS, + GDCM_LESSOREQUAL + }; + +Wed Jul 20 15:39:00 2005 by jpr + AnonymizeNoLoad.cxx + AnonymizeNoLoad user can now ask for anonymization of 'BinEntries' + (e.g. Private entries when the TS is Implict VR) + AnonymizeNoLoad filein=... rubout=0x0009-0x0001,0x0013-0x1100 + Thx to Luca Picello for reporting pb and supplying data to fix the bug. + +Wed Jul 20 16:49:41 2005 by jpr + gdcmFile.cxx + Use GDCM_LEGACY for DicomDir, as well + +Wed Jul 20 15:31:01 2005 by jpr + gdcmFile.cxx + We can now anonymize 'BinEntries' as well + +Wed Jul 20 15:29:42 2005 by jpr + gdcmArgMgr.cxx + Add ArgMgrGetXInt16Enum to decode from the command line pairs of unsigned int + 16, written in hexadecimal. + (usefull to allow terminal user to pass the (private) elements he wants to + anonymize) + +Tue Jul 19 17:25:53 2005 by jpr + gdcmFile.cxx + Add some comments on the 'Patient Position' + +Tue Jul 19 11:04:58 2005 by jpr + gdcmSerieHelper.cxx + Add SerieHelper::AddGdcmFile(File *header) method. + * \brief add a gdcm::File to the first (and supposed to be unique) list + * of the gdcm::SerieHelper. + * \warning : this method should be used by aware users only! + * User is supposed to know the files he want to deal with + * and consider them they belong to the same Serie + * (even if their Serie UID is different) + * user will probabely OrderFileList() this list (actually, ordering + * user choosen gdm::File is the sole interest of this method) + * Moreover, using vtkGdcmReader::SetCoherentFileList() will avoid + * vtkGdcmReader parsing twice the same files. + * *no* coherence check is performed, but those specified + * by SerieHelper::AddRestriction() + +Mon Jul 18 12:20:20 2005 by jpr + gdcmCommon.cxx + In order to prepare the future extension of SerieHelper::AddRestriction (key, + string, operator) + operator = { EQUAL, DIFFERENT, LESS, LESSOREQUAL, GREATER, GREATEROOREQUAL} + add method + bool Util::CompareDicomString(const std::string &s1, const char *s2, int op) + +Sun Jul 17 06:27:49 2005 by jpr + gdcmSerieHelper.cxx + Use new style for Loading files + +Tue Jul 12 19:08:12 2005 by jpr + gdcmCommon.cxx, gdcmSQItem.cxx + To speed up DicomDir, instead of copying -and removing the source afterwards- + each entry of the SQItem (found after gdcm::Document parsing) towards + the gdcm::Object belonging to the gdcm::DicomDir, we just copy + the chained list itself. + +Tue Jul 12 16:55:43 2005 by jpr + AnonymizeNoLoad.cxx + AnonymizeNoLoad has now one more option : + dirin= + to give the (single Patient) directory name whose content we want to anonymize. + +Mon Jul 11 10:20:25 2005 by jpr + gdcmDicomDirStudy.cxx + Reorder methods + +Fri Jul 8 21:07:12 2005 by jpr + gdcmDicomDir... + Add the VISIT object within DicomDir + +Fri Jul 8 12:15:08 2005 by jpr + gdcmDicomDir... + Use new style for DicomDir loading + +Fri Jul 8 16:36:48 2005 by jpr + gdcmFileHelper.cxx + To remain unimpared, gdcm::FileHelper class needs also its + void FileHelper::SetLoadMode(int loadMode) + void FileHelper::SetFileName(std::string const &fileName) + bool FileHelper::Load() + +Thu Jul 7 19:31:53 2005 by jpr + Example/*.cxx + Begin of kosherization of Example + New 'gdcm2' style. + +Thu Jul 7 18:37:40 2005 by jpr + gdcmDocument.cxx + On the way to gdcm2 ... + Now, the stand way to use a file is : + gdcm::File *f = new gdcm::File(); + f->SetLoadMode ( user say here what he wants *not* to load ); + f->SetFileName("myFile.gdcm"); + f->Load(); + Old styles are kept, not to break the C++ API. + - gdcm::File *f = new gdcm::File("myFile.gdcm"); + - f->Load("myFile.gdcm"); + Due to the syntaxic abilities of Python maybe some troubles will occur + (not sure ...) + +Thu Jul 7 15:55:39 2005 by jpr + gdcmDocument.cxx + Comment out the time consuming, never used/useless + 'Extended tag' stuff for Sequence embedded Entries + +Thu Jul 7 15:11:38 2005 by jpr + gdcmDocument.cxx + Move code lines LTTG so save some CPU time. + (hope so) + +Tue Jun 7 13:12:10 2005 CEST by jpr + Example/*.cxx + Use Argument Manager in 'utilities' + +Thu Jul 7 12:12:32 2005 by jpr + gdcmFile.cxx + Due to something stupid in the gdcm::File constructor, the file was parsed + twice when we used old style, e.g : + gdcm::File *f = new gdcm::File(fileName); + instead of new style, e.g. : + gdcm::File *f = new gdcm::File( ); + f->SetLoadMode ( choose what you want *not* to load here ); + f->Load( filename ); + +Wed Jul 6 11:53:43 2005 by jpr + TestAllReadCompareDicom.cxx, TestReadWriteReadCompare.cxx + Now TestAllReadCompareDicom.cxx TestReadWriteReadCompare.cxx accept a third + param, in order not to have to recompile to gdcm::Debug::DebugOn(). + +Wed Jul 6 17:18:42 2005 by jpr + gdcmDocument.cxx + According to Mathieu's requirement, Load twice the same file keeps the rseult of + the first Load (instead of doing it twice) + +Wed Jul 6 11:25:12 2005 by jpr + gdcmDocument.cxx + - Clean out the Entries if a Document is parsed more than once + - Uncomment (usefull) warning messages + +Wed Jul 6 10:42:33 2005 by jpr + gdcmDocument.cxx + - Comment out a for the moment too much verbose warning message. + - Delay some statement as late as possible, to save some CPU time when they're + useless + +Wed Jul 6 13:01:08 2005 by jpr + gdcmFile.cxx + Now gdcmFile::Load() returns false if file is not gdcm parsable + Only gdcmDocument::Load() did it, before. + Thx to Benoit for reporting bug + +Sun Jul 3 14:42:04 2005 by jpr + gdcmDocument.cxx + Should avoid some troubles with 'no length' SQItems within 'true length' + Sequences. + Thx to Loic Boussel for providing data to fix the bug. + +Sun Jul 3 14:42:04 2005 by jpr + gdcmDocument.cxx + Should avoid some troubles with 'no length' SQItems within 'true length' + Sequences. + Thx to Loic Boussel for providing data to fix the bug. + +Sun Jul 3 14:47:23 2005 by jpr + gdcmSQItem.cxx + Enh warning message + +Fri Jul 1 13:25:51 2005 by jpr + gdcmPixelReadConvert.cxx + Initialize RLEInfo and JPEGInfo to 0 a avoid further problems + (e.g. PrintFile on a DICOMDIR document) + +Thu Jun 30 16:49:02 2005 by jpr + gdcmFile.cxx + Enhance gdcm::File::IsReable() heuristics to be able to process some Loic + Boussel's Hall of Shame Dicom images + +Wed Jun 29 17:58:33 2005 by jpr + gdcmDocument.cxx + Add the NO_SHADOWSEQ load mode + +2005-06-26 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * Quite a few new dictionaries were added in gdcm. The file: + gdcm/Dict/README should always explain were the info was found + (in case of double check). Also some dict are still only + express as 'template' (they contain 'xx'), therefore + a python script should be run first to generate a full dict. + In the longer term this python script should be replaced by + a cmake script. + +2005-06-25 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * dicomV3.dic is deprecated in favor of gdcm.dic + There is now a dictionary per family: + - dicomV3.dic -> DICOM V3 + - Papyrus.dic -> Papyrus + - NIH.dic -> tags that were never allowed in the main standard + +Fri Jun 24 12:50:20 2005 CEST by jpr + gdcmFile.cxx + Pixel Spacing related problems : update comments. + Thx to D. Clunie for providing data to check the code + +Fri Jun 24 12:55:58 2005 by jpr + Summer nights are really too hot to sleep. + Coding style : kosherization of all the 'if's (300 amongst 900 were haram) + +Thu Jun 23 11:20:23 2005 by jpr + gdcmDocument.cxx + Extend warning message, for debugging purpose + +Wed Jun 22 10:11:23 2005 by jpr + gdcmFile.cxx + Coding Style + +Wed Jun 22 10:00:29 2005 by jpr + gdcmPixelReadConvert.cxx + Fix misstyping, while removing spurious \t characters + +Wed Jun 22 09:52:32 2005 by jpr + gdcmPixelReadConvert.cxx + Some constructors (at least one ...) use BitsAllocated =! BitsStored for + negative Pixels. + That break at lot of viewers ... + We now *propagate the sign bit* upon the unused ones, better than masking them + out. + Thx to Luca Picello for profiding data to fix the bug + +Wed Jun 22 09:53:52 2005 by jpr + gdcmFileHelper.cxx + gdcm images are now "GDCM 1.1" built. + +Mon Jun 20 19:10:17 2005 by jpr + gdcmFileHelper.cxx + Avoid re writing Palette Color Lookup Table UID when Palette Color is removed + +Mon Jun 20 17:58:53 2005 by jpr + gdcmDocument.cxx + Preventive bug fix for LUT Data. + I said : LUT Date, *not* Palette Color + +Sun Jun 19 17:57:29 2005 by jpr + gdcmDocumentcxx + To avoid warnings at compile time + +Fri Jun 17 14:27:52 2005 by jpr + gdcmRLEFrames.cxx + Try to solve RLE pb + +Fri Jun 17 14:36:07 2005 by jpr + gdcmDocument.cxx + Add comments + +Fri Jun 17 14:35:00 2005 by jpr + gdcmFileHelper.cxx + Add some accessors for debugging purpose + +Tue Jun 14 15:56:41 2005 by jpr + gdcmPixelReadConvert.cxx + Now gdcm deals with 16 bits per pixel images with 16 bits Palette colors + (3 * 65536 short int ...) + Nice fat header. + "Segmented Palettes" pb still pending, but I never saw any viewer dealing with it. + +Mon Jun 13 17:43:48 2005 by jpr + gdcmPixelReadConvert.cxx + Some more oddities dealt with. + Doesn't work yet with 65536 entries 16 Bits LUT (?!?), with 16 bits pixels. + Still looking for accurate info on the web about it + +Fri Jun 10 16:05:38 2005 by jpr + gdcmDocument.cxx + Bug fix in Load method. + Thx to Benoit for providing fix. +2005-06-08 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmUtil.cxx : change call to Util::Format to sprintf because of + lantency with the Util::Format function + +Tue Jun 7 15:48:35 2005 by jpr + gdcmUtil.cxx + The highy time consuming method GetMacAdress is now called just once + +Tue Jun 7 11:58:29 2005 by jpr + gdcmDicomDirElement.cxx + Use TranslateToKey better than Format + +Tue Jun 7 12:07:20 by jpr + gdcmDictEntry.cxx + Remove some spurious calls to Format + // according to 'Purify', TranslateToKey is one of the most + // time consuming methods. + // Let's try to shorten it ! + +Mon Jun 6 14:37:58 2005 + class ArgMgr (for Arguments Manager) is designed for + command line arguments management + (to make programmer's live easier) + (could be used for any kind of 'command line program') + +2005-06-07 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * Adding users file in CVSROOT for mail blaming + +2005-06-04 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * Adding potential support for JPEG-LS DICOM files. + +Fri Jun 3 18:05:23 2005 by jpr + gdcmDocument.cxx + Fix VR processing, to be CP-288 conform. + Now we can parse any kind of DICOM SR. + +Fri Jun 3 11:05:15 2005 by jpr + gdcmDocument.h + Doxygenation + +Thu Jun 2 15:42:18 2005 by jpr + gdcmDocument.cxx + Add warning about Load Mode + +Thu Jun 2 16:20:14 2005 by jpr + gdcmFile.cxx + Harden gdcm::File::IsReadable(), in order not to be confused any longer + by lost of Pixel Element + +Fri May 27 12:51:00 2005 by jpr + gdcmFileHelper.cxx + To avoid pushing out twice the meta elements, wile trying to write 'ACR-NEMA- + style. + And avoid some memry leaks -hope so- + +Wed May 25 14:54:17 2005 by jpr + gdcmDocument.cxx + Should avoid some memory leaks + +2005-05-22 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * Adding potential support for mpeg and jpeg2000 through two new lin + - JasPer for JPEG2000 + - libmpeg2 from the MPEG consortium + Also adding intial work to use this lib. + +Fri May 20 10:27:55 2005 by jpr + gdcmFileHelper.cxx + To avoid warning. + (this time, it's wasn't dangerous at run time) + +Thu May 19 17:31:21 2005 by jpr + gdcmFileHelper.cxx + FIX possible troubles when checking + 'Hight Bit Position' vs 'Bits Allocated' and 'Bits Stored' + Thx to Mathieu for reporting bug + +Wed May 18 12:12:07 2005 by jpr + gdcmDocument.cxx + Fix : now dcm deals with 'No preamble', Big Endian Explicit VR group 0002. + Thx to Dennis Hu for providing a sample image to fix the bug. + +Tue May 17 14:44:09 2005 by jpr + gdcmFile.cxx + ENH : According to David Clunie's advice, we check now 'Imager Pixel Spacing' + before 'Pixel Spacing', when we want to get X or Y Spacing. + +Tue May 17 19:10:49 2005 by jpr + gdcmFileHelper.cxx + ENH : Now, FileHelper::CheckMandatoryElements() makes some consistency checking, + at LTTG (Least Time To Go) + around Bits Allocated, Bits Stored, High Bit Position, + to avoid unaware user to mess up the stuff. + +Tue May 3 11:43:04 2005 by jpr + gdcmDicomDir.h, .cxx + Load returns now a bool (allow user not to call IsReadable() ) + +Tue May 3 11:51:06 2005by jpr + gdcmFileHelper.cxx + Now the gdcm::File remains unimpaired after writting, in any case + +Fri Apr 29 17:10:55 2005by jpr + gdcmDocument.cxx + Don't abort the prog when File not open + +Wed Apr 27 12:00:35 2005 by jpr + gdcmFile.cxx + Removal of now useless lut-related stuff + +Wed Apr 27 11:52:27 2005 by jpr + gdcmFile.cxx + Pb of 'Bits Allocated = 12' is now dealt with in + FileHelper::CheckMandatoryElements, no longer in File::Write. + Thx to Mathieu for reporting bug. + +2005-04-26 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * Testing/TestAllReadCompareDicom.cxx : update the test printed results and + description. + +Tue Apr 26 18:18:23 2005 by jpr + gdcmDocument.cxx + Should leave gdcm::Document constructor in a much quicker + and much cleaner way when anything wrong occurs. + +Tue Apr 26 18:25:49 2005 by jpr + gdcmPixelReadConvert.cxx + Prepare MPEG Dicom encapsulated processing (within a loooong future) + +Fri Apr 22 14:59:58 2005 by jpr + gdcmDocument.cxx + Modify Print() output + +Fri Apr 22 15:37:57 2005 by jpr + gdcmTS.cxx + Prepare (future) MPEG integration + +Thu Apr 21 09:40:00 2005 by jpr + gdcmTS.cxx + Taking into account Dicom MPEG + +2005-04-20 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * FIX : Numerical exception on borland (cannot divide by 0, doh !) + But this is a case where we should really signify the user there is + few chance the serie is really a serie... + +2005-04-20 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * FIX : on X, the python part is correctly installed. All files are + installed in gdcm sub-directory + +Tue Apr 19 11:58:19 2005 by jpr + gdcmDocEntry + Should suppress some warnings from Borland compiler + +2005-04-19 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * Builder/ : add something to facilitate the RPM creation of gdcm + +2005-04-15 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * Fix gdcmDirList::IsDirectory. Apparently borland did not like the ending + '/' + * Also fix compilation on gcc 3.3.5 does not have ios::failure either ... + +Thu Apr 14 16:26:19 2005 by jpr + gdcmDicomDir.h, .cxx + Now, user can ask gdcm::DicomDir to skip SeqEntries or shadow groups, when + possible : + // Old style (still available) : + dcmdir = new gdcm::DicomDir(dirName, true); + + // new style (user is allowed no to load Sequences an/or Shadow Groups) + dcmdir = new gdcm::DicomDir( ); + dcmdir->SetParseDir(true); + dcmdir->SetLoadMode(NO_SEQ | NO_SHADOW); + dcmdir->Load(dirName); + +2005-04-11 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * vtk/vtkGdcmWriter fix bug when writing spacing. The Y spacing comes first + then the X spacing. + * Fix compilation on gcc 2.96 (which does not have ios::failure) + +Mon Apr 4 17:15:24 2005 by jpr + gdcmFileHelper.cxx + Fix stupid bug when writting ACR-NEMA image from 'ACR-LibIDO' one. + +2005-04-05 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmDictGroupName.[h|cxx] : add a correlation between a group (number) + and it's representation name (for the NIH) + +2005-03-31 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmPixelReadConvert.cxx : problems of around of double to uint8, when + conversion of YBR to RGB pixels. So, now, the conversion is made using + integers only + +2005-03-30 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * Testing/TestAllReadCompareDicom.cxx : now use test files (invented file + format) to replace 'at-run' dicom files generated by the + TestAllReadCompareDicom test + +Tue Mar 22 12:29:37 2005 by jpr + gdcmDocument.cxx + * FIX : element 0x0000 of shadow groups is now force to a ValEntry, + and it's VR is forced to UL + * ENH : user id now allowed to tell he doesn't want to deal with Sequences + and/or with Shadow groups + use SetLoadMode (NO_SEQ | NO-SHADOW); + +Tue Mar 22 12:40:13 2005 by jpr + gdcmFileHelper.cxx + *FIX Restore pushed out elements + +Fri Mar 11 12:08:31 2005 by jpr + gdcmDocEntry.cxx + Remove spurious #define MAX_SIZE_PRINT_ELEMENT_VALUE + +Fri Mar 11 12:12:13 2005 by jpr + gdcmFile.cxx + Final removal of gdcmFileHelper::InitializeDefaultFile(); + +Wed Mar 9 20:29:38 2005 by jpr + gdcmDicomDir.h, .cxx + Add Anonymize method (not yet fully checked) + +2005-03-07 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmFileHelper.cxx : remove memory leaks and bugs when writing files + +Wed Mar 2 18:18:32 2005by jpr + gdcmFile.cxx + Fix gdcm::FileHelper::CheckMandatoryElements() to take into account David + Clunie's remarks. + +2005-02-22 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmFileHelper.cxx : JPR bad personal choices fix + +Mon Feb 21 18:45:41 2005 by jpr + gdcmFileHelper.cxx + * Replace method CheckMetaElements by CheckManadatoryElements + To deal with the pb of UID's, and with Type 1 an Type 2 Entries + (probabely some stuff still missing) + * We shall have to decide the way we proceed to allow user 'freeze' Serie UID + between a given call and the next one (to add images to a Serie he just + created) + * We shall have to decide the way we proceed to allow user 'freeze' Study UID + between a given call and the next one, or to reuse an already existing + Study UID (i he wants to add his own Series to an already existing Study) + +Thu Feb 17 17:18:33 2005 by jpr + gdcmFile.cxx + To avoid further pb, Initialize defaults now Photochromatic Interpretation to + MONOCHROME2 (low values = dark), better than MONOCHRONE1. + Thx to Benoit for reporting bug + +Thu Feb 17 11:56:20 2005 by jpr + gdcmUtil.cxx + Prepare FileMetaInformationVersion (group 0002) management + +Thu Feb 17 12:02:47 2005 by jpr + gdcmFile.cxx + Group 0002 management + +Thu Feb 17 12:03:32 2005 by jpr + gdcmDocEntryArchive.cxx + Fix comments + +Wed Feb 16 11:19:19 2005 CET by jpr + gdcmPixelReadConvert.cxx + Taking into account MONOCHROME1 + Signed Pixels (?!) + +Tue Feb 15 19:12:34 2005 by jpr + gdcmFile.cxx + Taking into account the difference between MONOCHROME1 (low values = bright) + and MONOCHROME2 (low values = dark) + +Mon Feb 14 11:45:04 2005by jpr + gdcmDocument.cxx + Remove some useless mask operations, to save CPU time + +Mon Feb 14 15:51:10 2005 by jpr + gdcmUtil.cxx + *never* forget to re-compile just *before* committing! + +Mon Feb 14 15:34:27 2005 by jpr + gdcmUtil.cxx + First commit on the post 1.0 (Version? / Tag? / Branch?) : + Fix Doxygen warnings + +Mon Feb 14 11:45:47 2005 by jpr + gdcmValEntry.cxx + remove useless comments + +2005-02-11 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * Testing/TestMAkeIcon.cxx : complete the test + +2005-02-10 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * Testing/TestWriteSimple.cxx, TestSequence.cxx : fix memory leaks + +Fri Feb 11 16:22:18 2005 by jpr + gdcmDocEntrySet.cxx + Typo, comments, doxygenation + +Thu Feb 10 11:55:26 2005 by jpr + gdcmFile.cxx + AnonymizeNoLoad improvement + +Thu Feb 10 10:07:19 2005 by jpr + gdcmFile.cxx + Duplicate Matthieu's hack to prevent bombing in Anonymize + +Thu Feb 10 12:20:34 2005by jpr + gdcmDocEntrySrt.cxx + The following gdcm::DocEntrySet methods, no re-definable is child classes are no + longer virtual + virtual ValEntry *GetValEntry(uint16_t group, uint16_t elem); + virtual BinEntry *GetBinEntry(uint16_t group, uint16_t elem); + virtual SeqEntry *GetSeqEntry(uint16_t group, uint16_t elem); + virtual bool SetValEntry(std::string const &content, + virtual bool SetBinEntry(uint8_t *content, int lgth, + virtual bool SetValEntry(std::string const &content, ValEntry *entry); + virtual bool SetBinEntry(uint8_t *content, int lgth, BinEntry *entry); + virtual ValEntry *InsertValEntry(std::string const &value, + virtual BinEntry *InsertBinEntry(uint8_t *binArea, int lgth, + virtual SeqEntry *InsertSeqEntry(uint16_t group, uint16_t elem); + +2005-02-09 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmFileHelper.[h|cxx] : now correctly set the VR of the datas when + writting the file + +2005-02-09 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * Test/VTKTestWriteSeq.cxx : add a VTK test to write sequences + +2005-02-09 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * Test/ : accelerate tests (it's not very significant accelerations). + Remove TestCopyDicom that is redundant with TestCopyRescaleDicom + +Mon Feb 7 15:48:34 2005 by jpr + gdcmDicomDir.h, .cxx + Add some commented out lines to prepare future version of 'Full DICOMDIR' stuff + + +2005-02-07 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * Testing/TestSequence.cxx : add test for sequences of images... test that + we have the same serie or the same study UID + +2005-02-07 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * gdcmPython/gdcm.i : bug fix. Now string are correctly converted in python + string type + * src/gdcmDict.h : remove commented code + * src/gdcmDocument.cxx : initialize values + * src/gdcmFile.cxx : bug fix when reading values + * gdcmPython/demo/ : change file names. Remove useless files + +Sun Feb 6 15:31:09 2005 by jpr + gdcmDicomDirStudy.h + Update comments for DicomDir stuff + +Sun Feb 6 15:39:35 2005 by jpr + gdcmDocument.cxx + * Add method File::AnonymizeNoLoad, to allow anomymizing files + even when the pixels are not gdcm Readable + * Add methods File::AddAnonymizeElement and File::ClearAnonymizeList + to allow user to choose the elements whose value + he wants to white out / replace + +2005-02-04 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmFile.cxx : remove the default array of initialization. + The static array contained pointers to non-static values (comming from + strings). To have coherences, when creating files, these values can't be + static. So, the array can't be static, too ! To simplify, the array have + been replaced by repeted lines to insert values in the File + +Fri Feb 4 15:49:01 2005 by jpr + gdcmDocEntry.cxx + * Add GetFirstValEntry + GetNextValEntry, for Python users + * Some more Doxygenation + typo fixing + +2005-02-03 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmBinEntry.cxx : bug fix for BIG_ENDIAN part when writing the content + * gdcmPython/gdcm.i : rename gdcmHeader to gdcmHelper + +Thu Feb 3 18:12:46 2005 by jpr + gdcmPixelReadConvert.cxx + Fix Doxygen warning + +2005-02-02 Jean-Pierre Roux <jpr@creatis.univ-lyon1.fr> + * FIX SQItem::AddEntry inserts now *in the right place* any Entry + (Dicom Element) into the Sequence Item + +2005-01-31 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/*.cxx : first parss to normalize file organisation + +2005-01-31 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmDirList.[h|cxx] : add method to find a directory + * Test/TestAllReadCompareDicom.cxx : bug fix under Windows + +2005-01-31 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * Finish cleaning up my JPEG mess. Should be ok now. + * Getting toward a RLE very similar to JPEG. Every RLE stuff is now self + contained within the RLE* class(doh!) + +2005-01-30 Jean-Pierre Roux <jpr@creatis.univ-lyon1.fr> + * SerieHeader::SetDirectory() allow recursive exploration of the Directory + * SerieHeader::AddFileName() creates as many Coherent Files lists + (same Serie UID) as it founds different Serie UID + amongst the files instead of discarting any file + that doesn't match with the first one he found. + * SerieHeader::OrderGdcmFileList has now one parameter : + the Coherent Files list the user wants to sort + * SerieHeader::GetFirstCoherentFileList() | + * SerieHeader::GetLastCoherentFileList() | allow to parse + the set of Coherent Files lists + * const SerieHeader::GdcmFileList &GetGdcmFileList() is kept, for backwards + compatibility (it returns the *first* Coherent Files list, + since there was only one before) + * Test/TestSerieHeader gets gdcmData as a default root directory + +2005-01-28 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * Remove friend between DocEntry and File classes + * Remove friend between PixelReadConverter and RLEFramesInfo, + JPEGFragmentsInfo + +2005-01-28 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmFile.cxx, gdcmDocument.cxx : fix the bug on the group|element + 0002|0000. The value was incorrect. + +2005-01-28 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * vtk/vtkGdcmWriter.[h|cxx] : add the gestion of UID + +2005-01-28 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmUtil.cxx : compilation fix on Win32 + * src/gdcmUtil.[h|cxx] : Set the default GDCM UID in a static constant + variable, to be easy found. Add methods to change the default UID. + Amelioration of the CreateUniqueUID to use the correct default UID. + * src/gdcmFile.cxx : correct use of the CreateUniqueUID method to create + a new file + +2005-01-28 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * Test/TestVR.cxx : fix memory leaks + +2005-01-27 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * Rewrite the base 256 to base 10 conversion, using string operation only. + This allows us to get rid of the problematic 64bits integer type (does not + always exist on target platform). + +2005-01-27 Jean-Pierre Roux <jpr@creatis.univ-lyon1.fr> + * Add construct and destructor to class gdcm::Debug to close the debug file + automatically + * Don't let uset to open twice the same file + * gdcm has now an official UID prefix, + supplied by http://www.medicalconnections.co.uk + 1.2.826.0.1.3680043.2.1143 + (Thx to Mathieu for providing URL) + * Add a forty-entries private Dicom Dictionary (Philips MR Intera) + to be able to perform some more tests + * gdcm::ContentEntry : Contructors and Destructor are now protected, + in order to be sure no user will try to use them. + (at user level, only the children classes are meaningfull) + +2005-01-26 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * move RLEInfo & JPEGInfo from Document to File + +2005-01-26 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * FIX : remove so many friend between classes + +2005-01-25 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmDocEntrySet.cxx : Bug fix when getting the value + * src/gdcmContentEntry.[h|cxx], gdcmValEntry.cxx : amelioration of code + +2005-01-25 Jean-Pierre Roux <jpr@creatis.univ-lyon1.fr> + In order to avoid missbehaviour : + . gdcm::DocEntry is now specialized in + - gdcm::SeqEntry (Dicom Sequence) as opposed to : + - gdcm::ContentEntry (Dicom entry with a 'content') + . gdcm::ContentEntry is specialized in + - gdcm::ValEntry (Dicom entry with a std::string representable value, i.e. + characters value, or integers) + - gdcm::BinEntry (Dicom entry with a non strig representable value + (user hasn't any longer to thing about the precedence of his dynamic_casts) + +2005-01-25 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * Test/VTKTest*.cxx : bug fix under linux + +2005-01-25 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/ : rename some methods on Entry (SetXxx, InsertXxx) to have a better + use with python. Some methods are moved from Document to ElementSet or + DocEntrySet. The equivalent methods to ElementSet have been added to + SQItem and are virtual in DocEntrySet. Methods that may have the same code + in SQItem and ElementSet is directly placed in DocEntrySet + +2005-01-25 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * Test/VTKTest*.cxx : remove the show variable in each test method because + it's useless (the viewer variable replace this variable) + +2005-01-25 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmDocument.cxx : bug fix on potential memory leak + * src/gdcmSQItem.cxx : initialize the SQItemNumber value in the constructor + * src/gdcmSQItem.[h|cxx], gdcmElementSet.[h|cxx], gdcmDicomDir*.[h|cxx] : + Add ClearXxx methods to remove all the content of the list or map + * gdcmDocEntrySet.h : add GetFirst/NextEntry in pure virtual + +2005-01-25 Jean-Pierre Roux <jpr@creatis.univ-lyon1.fr> + * methods ReplaceOrCreate renamed as Insert + (nobody will be any longer confused by 'CreateOrReplace') + +2005-01-24 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * Grealty simplify the JPEg decompression, no need to differenciate based on + the JPEG possible type (with/without fragment, with/without multiple frame). + Everything is done throught the JPEG IO Suspension mechanism in IJG + +2005-01-24 Jean-Pierre Roux <jpr@creatis.univ-lyon1.fr> + * Stage 3 of normalization : + in order to avoid any missunderstanding while reading method names : + - All the methods xxxEntry now deal with dicom Entries + - Methods GetEntry splitted into + GetEntryValue + GetEntryBinArea + - Method SetEntry renamed as SetEntryValue + - Method SetEntryBinArea let as it was + +2005-01-24 Jean-Pierre Roux <jpr@creatis.univ-lyon1.fr> + - Add empty nutshell for JPEG-LS (JPG-LS in NOT jpeg 'lossless') + - Position correctly the entry points for JPEG2000 and JPEG-LS + (Now Fragments info is get from the file, even for JPEG2000 and JPEG-LS) + +2005-01-22 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmDicomDirElement.h, gdcmDict.h : rename AddNewXxx methods to AddXxx. + * src/gdcmDict.h : rename GetDictEntry moethod to GetEntry, to be coherent + with other method names + * gdcmPython/gdcm.i : bug fix. Add the typemaps for the TagName type + * Test/TestDicomDirElement.cxx : add new test + +2005-01-22 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * Finish the CreateUniqueUID stuff. Seems to compiled/runs on every + plateforms ITK support. Had some troubles with uint64_t on Win32, go to + http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclang/html/_langref_data_type_ranges.asp + for more info. Basically you can not used 'unsigned' __int8 in an ostream. + So can't you use __int64 in ostream at all. + +2005-01-22 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * bug fix for compilation on MSVC6 + * gdcmPython/gdcm.i : rename of classes missed + +2005-01-21 Jean-Pierre Roux <jpr@creatis.univ-lyon1.fr> + * Stage 2 of names normalization : + - A gdcm::Document is now either a gdcm::DicomDir or a gdcm::File + (easy to understand ...) + - gdcm::FileHelper replaces old class gdcm::File + +2005-01-20 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * gdcmDicomDirElement.[h|cxx] : change the AddEntry method. Now, it gets a + type and not a string. So, there remove problems on the format of the + string. + +2005-01-20 Jean-Pierre Roux <jpr@creatis.univ-lyon1.fr> + * Add Example/TestPapyrus.cxx + - reads a Papyrus file (gdcm::Header compliant), + - gets the pixels of all the images, using low level iterators + - writes an multiframes Dicom image. + (Just to show it's *possible* to do that) + Uses SQItems accessors (we could use it as a 'Test' program, to improve test + coverage ...) + +2005-01-20 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmDicomDirObject.h : set the FillObject method in protected. + Thus, DicomDirXXX are created with a flad that indicates if the created + object is empty or not (when not empty, the DicomDirElement is used to + fill the object) + +2005-01-20 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmDicomDir.cxx : simplify the NewPatient method, like made in + gdcm::DicomDirPatient, gdcm::DicomDirStudy, gdcm::DicomDirSerie + +2005-01-20 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmSQItem[h|cxx] : rename some methods to have coherent names + +2005-01-20 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmDicomDir*.[h|cxx] : rename methods to be logik in their name. + Remove all access to the hash-tables or lists in the objects. + +2005-01-20 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmDebug.h : remove the Debug test in the gdcmErrorMacro + * src/gdcmDocument.[h|cxx] : rename the Initialise method to Initialize, to + be complient with all the gdcm source code + +2005-01-19 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmDocEntry.h : DocEntry is now secure. User can't change the + DictEntry or the VR. + +2005-01-19 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * gdcmPython/ : change GDCM_DATA_PATH to GDCM_DATA_ROOT to be complient with + all in gdcm + +2005-01-19 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * Test/ : rename VTK tests to have a best name for the tests + * gdcmPython/demo/*.py.in : Change the InitTraversal/GetNextEntry use to + GetFirstEntry/GetNextEntry use + +2005-01-18 Jean-Pierre Roux <jpr@creatis.univ-lyon1.fr> + * In SerieHeader::ImagePositionPatientOrdering() + // a Dicom 'Serie' may contain scout views + // and images may have differents directions. + // -> More than one may have the same 'pos' + // Sorting has then NO meaning ! + Thx to Eduardo Davila for reporting bug. + +2005-01-18 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * Test/ShowDicom.cxx, ShowDicomSeq.cxx, TestWriteWithVTK.cxx : change the + test. Now it's on image content and not on the resulting visualisation... + might solve the problem on linux when using the OpenGL drivers + +2005-01-18 Jean-Pierre Roux <jpr@creatis.univ-lyon1.fr> + * ENH for DicomDir, DicomDirPatient, DicomDirStudy, + DicomDirSerie, DicomDirImage + Dict, DictSet classes : + -add method GetFirstEntry to replace call to InitTraversal+GetNextEntry + -remove InitTraversal method. + * UPD Test programs + Example programs + +2005-01-18 Jean-Pierre Roux <jpr@creatis.univ-lyon1.fr> + * remove useless and never updated keyword \ingroup + * Solve pb when structure (list, map, ...) is empty. + Thx to Benoit for reporting bug + +2005-01-18 Jean-Pierre Roux <jpr@creatis.univ-lyon1.fr> + * Taking into account of 'Transfer Syntax' value + (for 'true' Dicom V3 files, the 'ACR-NEMA' heuristics sometimes gives + unaccurate result) + +2005-01-17 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmUtil.cxx : bug fix to find the Windows MAC address. Now, there + is no memory access violation + * gdcmPython/demo : add python demos using VTK + +2005-01-16 Jean-Pierre Roux <jpr@creatis.univ-lyon1.fr> + * FIX 'Dictionnary' is now spelt 'Dictionary' + 'wether' is now spelt 'whether' + 'archieve' is now spelt 'archive' ;-) + +2005-01-15 Jean-Pierre Roux <jpr@creatis.univ-lyon1.fr> + * ADD DicomDir, DicomDirPatient, DicomDirStudy, DicomDirSerie, DicomDirImage + related methods, in order not to expose internal mechanisms + InitTraversal(); + GetNextEntry(); + * REM methods that exposed internal mechanisms : + DicomDir::GetDicomDirPatients() + DicomDirPatient::GetDicomDirStudies() + DicomDirStudy::GetDicomDirSeries() + DicomDirSerie::GetDicomDirImages() + * UPD Test programs : + makeDicomDir.cxx + BuildUpDicomDir.cxx + TestDicomDir.cxx + * UPD Example program + PrintDicomDir.cxx + * ADD DictSet methods + InitTraversal() + GetNextEntry() + +2005-01-15 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * Removed the Print/indent/default parameter mess. There is absolutely no + reason to have to methods, moreover with the second taking the ostream as + *SECOND* parameter. This was clearly a bad hack to get things compile. + +2005-01-15 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * Complete rewrite of the GetMacAddress code. Now the code is *much* + smaller (no more MacOSX specific crap). A lot more POSIX oriented. + Unfortunately the main code does not work on SunOS, thus provide a specific + code for this platform only (and Win32 of course). Since this seems to be + working, change CreateUniqueUID to use GetMACAddress instead of the + problematic GctestetIPAddress + +2005-01-14 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * Unfortunately to be able to test gdcmDirList I had to break the API + a little. Now the class is not a std::list anymore but has a member + std::vector (more ITK compatible). Allow unit testing on Win32 and + shared libs. + +2005-01-14 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * Update SerieHeader to take into account a Serie Instance UID to properly + sort DICOM files + +2005-01-13 Jean-Pierre Roux <jpr@creatis.univ-lyon1.fr> + * ENH - Comment out Mathieu's (dangerous) Super Hack + for dealing with BIGENDIAN processors + - Move equivalent stuff to BinEntry::WriteContent + When necessary, 16 Bits Pixels are swapped in a small buffer + and then written. This avoid allocating a huge buffer, in + PixelWriteConvertor, and avoid modifying the Pixel Area. + Note : + Probabely, the same operation will have to be done when we want + to write image with Big Endian Transfert Syntax, + and we are working on Little Endian Processor + +2005-01-14 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmDocument.[h|cxx] : comment all methods concerning a flat hash + table. + * src/gdcmElementSet.[h|cxx] : rename Initialize into InitTraversal + * src/gdcmDict.[h|cxx] : add InitTraversal/getNextEntry methods to parse + all the dict content. + * src/gdcmDictEntry.cxx : add a carriage return at the end of the DictEntry + print + * Test/TestDict.cxx : add a new test for the dict classes + +2005-01-13 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * src/gdcmDebug.h : Adding an option to redirect debug stream to a + file. Debug is yanked if compiled with NDEBUG + +2005-01-13 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmDictSet.h : set the default output to the os variable + * src/gdcmDictEntry.[h|cxx] : add the Print method + * gdcmPython/demo/ : add a new test + +2005-01-13 Jean-Pierre Roux <jpr@creatis.univ-lyon1.fr> + * merging of Test/PrintDicomDir and Test/TestDicomDir + * removal of now redundant Test/PrintDicomDir + * enhancement of Example/PrintDicomDir + +2005-01-13 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * Now, python test might work on systems + * Add the PrintDicomDir test + +2005-01-13 Jean-Pierre Roux <jpr@creatis.univ-lyon1.fr> + * FIX : First entry following group 0002 was lost for + Explicit Big Endian Transfer Syntax files + (group and elem not swaped) + +2005-01-12 Jean-Pierre Roux <jpr@creatis.univ-lyon1.fr> + * FIX : Old quick and dirty 'optimistic' heuristic to deal with + Big Endian Transfer Syntax supposed the group following 0002 + begins always by element 0000 (element 0000 is *optional*) + To avoid further troubles, let's be pessimistic, and use + Document::HandleOutOfGroup0002() method + * FIX : comparison between GDCM_NOTLOADED and Transfer Syntax + (related pb not yet solved) + +2005-01-12 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * Bug fix for the python part use + * Now, PrintHeader.py pass... but outside the ctest use. shit ! + +2005-01-12 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * gdcmPython/gdcm.i : bug fix when compiling with MSCV + +2005-01-11 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * Untangle TransferSynatx from gdcm::Document. Now Document only manipulate + a string and should ask the global TS dict what are the propreties of + the transfer syntax + +2005-01-11 Jean-Pierre Roux <jpr@creatis.univ-lyon1.fr> + * Replace confusing name SwitchSwapToBigEndian name by SwitchByteSwapCode + * Add the Document::HandleOutOfGroup0002(uint16_t group) method + to swap the Swap Code, at parsing time, when we come out of group 0002 + and Transfer Syntax is Big Endian + We should be able to read now 'true DICOM" Big Endian coded images + * Add optional run time SetDebugOn (last param) for PrintHeader, PrintFile + * Replace the french 'Transfert Syntax' by the english 'Transfer Syntax' + +2005-01-10 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * Hopefully fix the bug on MacOSX and static global initialization. + This is the only -minor- patch I found that both please MacOSX and VS6. + Other patch would be to declare a const std::string & GDCM_UNFOUND() instead, + but this would require a lot of change. Another approach would be that Global + create those string and GDCM_UNFOUND becomes a pointer to a string (which + gdcm::Global would destroy at exit). + +2005-01-08 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * Fix bug on MacOSX with static initialization in a multy threaded + environment. static const string in a header file used to be ill + initialized provoquing the freeze of any tests. patch should solve this + issue. + +2005-01-08 Jean-Pierre Roux <jpr@creatis.univ-lyon1.fr> + * According to Benoit's suggestion, and without any objection from anybody + - methods SetxxxByNumber and GetxxxByNumber renamed as Setxxx and Getxxx + - methods Dict::Print() and Dict::PrintByKey() merged into Dict::Print() + - method gdcmDicomDirObject::GetEntry() renamed as + gdcmDicomDirObject::GetEntryHT() to avoid confusion (and compile error) + +2005-01-07 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * Now gdcm::Debug is clearly a copy/paste of VTK approach. You can manipulate + you debug/warning message just as c++ streams which make them very convinient + to use. Once this is stabilize I will change the ostringstrem to be + redirected to a file (ofstream). + * Properly support C99 extension: __FUNCTION__ which allow us to display + the name of the function call (GNUC also allow __PRETTY_FUNCTION__ for c++) + +2005-01-07 Jean-Pierre Roux <jpr@creatis.univ-lyon1.fr> + * Removal of useless and dangerous methods : + GetEntryByName, GetEntryVRByName, GetDocEntryByName, SetEntryByName + GetDocEntryByName, GetEntryByName, GetDictEntryByName + * Removal of usless methods : + Dict::PrintByName, Dict::GetDictEntryByName + * Commenting out of probabely useless methods : + Dict::GetDictEntryNames() + Dict::GetDictEntryNamesByCategory() + DictSet::GetPubDictEntryNames() + DictSet::GetPubDictEntryNamesByCategory() + * ENH : New Dicom Dictionary (with Value Multiplicity) is now used + * ENH : Use dicomTS.dic as described in 2004 version + * ENH : Removal out of the Dicom Dictionary of non dicom 'fourth' field + Add to the Dicom Dictionary of Dicom 'Value Multiplicity' field + Add Accessors on VM (Value Multiplicity), and VM related methods + * ADD : Add a list of 'Dicom Attribute types', as found in + http://medical.nema.org/dicom/2004/04_15PU.PDF + Unused till now... + * ADD : Add dicomGroupNameAbbreviations.dic + should be used to write a method to replace the former + Dict::GetDictEntryNamesByCategory() + +2005-01-07 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmDocEntry.[h|cxx] : now the ReadLength is the length of the data + to read in the file... and only it ! Length is the efective length of the + data in the DocEntry structure + +2005-01-07 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * Change the gdcmDebug approach. Remov the global static debug 'dbg'. + And now use a static function call instead, with a global variable. i + This is much closer to the VTK approach. Hopefully should be bulletproof + and easier to use...hopefully + +2005-01-06 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * Adding GetMACAddres very alpha for now. This is tricky to be cross plateform. + +2005-01-06 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmDocument.[h|cxx] : remove all copy of DocEntry when parsing a file + +2005-01-06 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmDocEntrySet.[h|cxx], gdcmDocument.[h|cxx] : amelioration of + ValEntry, BinEntry, SeqEntry creation or replace + +2005-01-06 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmDictEntry.h : now, the IsVRUnknown is correct + * src/gdcmDocument.[h|cxx] : simplify the search of VR value when parsing + a file + * src/gdcmDocEntrySet.cxx : now the created DocEntry without values is good + when specifying the VR + * src/gdcmVR.[h|cxx] : add usefull method to test the validity of a VR + * src/gdcmDocEntry.cxx : amelioration of print + +2005-01-05 Jean-Pierre Roux <jpr@creatis.univ-lyon1.fr> + * ADD : Add the method Util::IsCurrentProcessorBigEndian + (we'll need it for 'Explicit VR Big Endian' Transfert Syntax) + * ADD Method Document::ComputeGroupLength + * ENH : now parsing creates a Vitual DictEntry for Pixels Element, + in order to allow further VR modification by user + * REM : removal of once-called method File::WriteBase + integration of its code in formerly one-line method File::Write + +2005-01-05 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmCommon.h : add the GDCM_UNKNOWN constant. This constant is to + replace the different values "??", "Unkn", "Unknown". + * src/gdcmDicomDirElement.h, gdcmDictEntry.h, gdcmDictSet.h, + gdcmDocEntry.cxx, gdcmDocEntrySet.[h|cxx], gdcmDocument.h, gdcmSQItem.cxx, + gdcmVR.cxx : use the GDCM_UNKNOWN constant. + * Appears a bug in gdcmDictEntry : IsVRUnknown always returns false... bad + +2004-12-16 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmBase.[h|cxx] : new base class. Contains the PrintLevel and an + empty Print Method + * Set the gdcm::Base class to some Printable classes + +2004-12-16 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmFile.[h|cxx] : add the Print method + * src/gdcmPixelReadConvert.[h|cxx] : add the generalized Print method + * src/gdcmDocEntrySet.h : generalize the Print with the PrintLevel + * src/gdcmDocument.h : remove the PrintLevel informations + * Example/PrintFile.cxx : use the new gdcm::File::Print + +2004-12-16 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmFile.cxx : Add the code of ReplaceOrCreateByNumber to not have + problems when compiling with the python wrapping + +2004-12-16 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmFile.cxx : bug fix. Omitted a Push in the DocEntryArchive when + writting in ImplicitVR + +2004-12-12 Jean-Michel Rouet <jm.rouet@noos.fr> + * src/gdcmPixelReadConvert.[h|cxx], src/gdcmJpeg*.cxx : new handling of + JPEG decompression, especially when dicom frames are split into several + JPEG Fragments. This makes use of jpeg decompression from memory buffer. + This solves reading for example gdcm-JPEG-Lossless_Thoravision.dcm. + +2004-12-10 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmHeader.cxx : change the initialisation of default header. + Now, this header is readable by gdm, e-film, DicomWorks + +2004-12-10 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmFile.[h|cxx], gdcmPixelReadConvert.[h|cxx] : change the API. + Rename Decompressed to Raw + * Use the API changes in gdcm::File. + * vtk/vtkGdcmWriter.[h|cxx] : add the possibility to write in other modes + Memory leaks fixed + +2004-12-10 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * vtk/vtkGdcmWriter.cxx, Example/WriteDicomSimple.cxx : add comments for + each added entry in the header. Replace the 'Planes' field by the 'Number + of Frames' field + +2004-12-09 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * vtk/vtkGdcmWriter.[h|cxx] : now can write stack of images. + * vtk/vtkWriteDicom.cxx : can write 2D stack or 3D image + +2004-12-09 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * Example/WriteDicomSimple.cxx : example to write a dicom file from nothing. + At this time, this image isn't readable by e-film... waiting JPR help to + solve it. + +2004-12-09 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmPixelReadConvert.cxx : bug fix when would forcing load of a + DocEntry. Now use methods of the Document ! + +2004-12-09 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * Test/ShowDicomSeq.cxx : bug fix + +2004-12-08 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * vtk/vtkGdcmReader.[h|cxx] : bug fix. Plane order isn't inverted + * vtk/vtkGdcmWriter.[h|cxx] : correctly write images (the Y axis is inverted) + * Test/ShowDicomSeq.cxx : new test to verify the use of AddFileName method + * Test/ShowDicom.cxx, TestWriteWithVTK.cxx : set the threshold of regression + test to 0.0 + * Test/TestCopyRescaleDicom.cxx : remove unused variable + * Test/CMakeLists.txt : add the creation of the gdcmDataSeqImages.h file + containing found sequences + +2004-12-07 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * Test/ShowDicom.cxx, TestWriteWithVTK.cxx : bug fix, now this test pass + not at all time + * Test/TestCopyRescaleDicom.cxx : rearrange the test to correctly pass... + Some fields in BinEntry must be copied to not seg fault when making the : + gdcm::File *copy = new gdcm::File( copyH ); + and tests are now made on good variables + +2004-12-07 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * vtk/vtkGdcmWriter.[h|cxx] : add a first version of vtkGdcmWriter + * src/gdcmValEntry.cxx : bug fix when setting the value. Problems of odd + length + * src/gdcmHeader.cxx : Remove a useless call to Util::DicomString + * Add vtkGdcmWriter example and test + +2004-12-07 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * Test/TestUtil.cxx : reformat the source code + * vtk/vtkGdcmReader.cxx : remove and change prints + * src/gdcmValEntry.[cxx|h] : now set the length of the value when calling + SetValue + * src/gdcmBinEntry.[cxx|h] : SetValue method don't set the length + * src/*.cxx : remove all useless call to SetLength of a ValEntry object + +2004-12-07 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmPixelWriteConvert.[h|cxx] : ficnished this class + * src/gdcmFile.cxx : finished the correctly use of PixelWriteConvert + +2004-12-06 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmDocument.cxx : bug fix when opening the file. All read is followed + by an eof to prevent all bad read of the file... and in this case, the + file isn't readable. + +2004-12-06 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * Example/Volume2Dicom.cxx : comment unused variables + * Test/PrintDicomDir.cxx : comment unused variables + * Test/BuildUpDicomDir.cxx : remove dbg.Verbose. Remove the FIXME. + * src/SQItem.[h|cxx] : remove the PtagHT variable. Remove the AddDocEntry + method that is redondant with AddEntry. + * src/gdcmDocEntrySet.h : add pure virtual methods common to ElementSet and + SQItem + +2004-12-04 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * Bug fix due my last commit (compilation under Windows). + * Example/Volume2Dicom : bug fix in the file and reformatting source code + * src/gdcmFile.h : bug fix. Variable type and variable name had same name + +2004-12-03 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * Huge cleanup: + - Remove printf / sprintf + - include iostream AFTER gdcm so we don't get warnings + - GDCM_NO_ANSI_STRING_STREAM shouldn't be used explitely ouside of gdcm + source + - Also remove tons of include from header files, hopefully this should + speeup the compilation time, since it was becoming a dog slow. + - Remove gdcm.h as it include way too many files and slow down compilation + (plus it is not up to date) + - remove 'using namespace std' this is BAD ! + +2004-12-03 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * Remove memory leaks on the DicomDir + * Remove some useless data in DicomDirObject + * Add usefull methods in SQItem, to be complient withe the ElementSet + +2004-12-03 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmFile.[h|cxx] : now use FileType instead of TWriteType. + +2004-12-03 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmPixelWriteConvert.[h|cxx] : new class to write data (and in the + future, with convertion) + * src/gdcmFile.[h|cxx] : the PixelWriteConverter instance replace Pixel_Data + and ImageDataSize values. Remove the method to get the PixelReadConverter + from the output of the class + +2004-12-03 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * Rename src/gdcmPixelConvert.[h|cxx] to src/gdcmPixelReadConvert.[h|cxx] + +2004-12-02 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * vtk/vtkGdcmReader.cxx : correct error in vtkDebugMacro, vtkWarningMacro + and vtkErrorMacro use. + * gdcmPython/gdcm.i : corrections to avoid warnings at compilation + +2004-12-02 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * Test/TestCopyDicom.cxx : the new dicom created is created empty, without + file name in input + * src/gdcmSeqEntry.cxx : bug fix in destruction of an element + * src/gdcmHeader.cxx : bug fix. Keep the string, otherwise it is destroyed. + The string leaves only in the fonction. So when we make a .c_str(), we + get the pointeur on the first element, element that will be destroyed + immediately after thee instruction. + * src/gdcmDocument.cxx : remove memory leaks. Bug fix when testing if the + file has been opened : the test must be made on the content of the + pointer and not directly on the pointer ! + Code formatting + +2004-12-02 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * gdcmPython/gdcm.i : change gdcmHeaderHelper to gdcmSerieHeader. Now, + the python part recompiles + +2004-11-30 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * Test/ShowDicom.cxx : Change the test to only open one vtkImageViewer. + Otherwise, under linux (Graphic card : NVidia / SE : FedoraCore 1) the + X session is killed (for my computer... it seems to not be identic on + all linux) + +2004-11-30 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * Test/ShowDicom.cxx : now can be used with an off-screen rendering to + avoid problems (otherwise, the difference test between the visible image + and the reference is incorrect. If the reference is greater than the + screen resolution, it's produce errors). + Can be used for only one image. Can be used with a visible flag. + * vtk/vtkGdcmReader.cxx : remove commented codes. + * vtk/vtkGdcmReader.h : add the gdcmCommon.h include file to avoid warnings + under windows at compilation + * vtk/vtkgdcmViewer.cxx : reformat the file. Apply a default window/level + for grayscale images + * vtk/GdcmToBaseline.cxx : new program to easy create the reference image + +2004-11-30 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmFile.[h|cxx] : bug fix for ACR-LIBIDO files when writting the file + * Test/TestAllReadCompareDicom.cxx, TestReadWriteReadCompare.cxx : add + tests on the image size X, Y, Z + +2004-11-26 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * Remove some useless methods in gdcm::Document, gdcm::Header and gdcm::File + * Rename gdcmHeaderHelper.[h|cxx] to gdcmSerieHeader.[h|cxx] to be coherent + between the class name and the file name + +2004-11-25 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/ : fix compilation warnings for the Write method (2 different + proto). So Rename 'Write(ifstream* fp' into 'WriteContent(ifstream* fp' + fix compilation warnings for the gdcm::Document::TransferSyntaxStrings + variable... create a static method in gdcm::Document to access to + this variable content. + +2004-11-25 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmDocument.[h|cxx] : set the Transfert Syntax values to the header + file, to be accessed by other files (like gdcmFile). Remove commented + code. Move the change of the header to the gdcmFile, using the + DocEntryArchive + * src/gdcmHeader.[h|cxx] : the write is completely made in the Header. + To be sure of that (and simplify calls), the Write of the header now + gets a file name and not a file pointer (std::ifstream). + * src/gdcmFile.[h|cxx] : apply the write file type to the header, using the + DocEntryArchive. Remove all open of the written file + +2004-11-25 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * vtk/vtkGdcmReader.cxx : compilation bug fix for the vtk part + +2004-11-25 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmDocument.cxx : fix bug... test if the fp is opened to use it + * src/gdcmPixelConvert.cxx : calculate the image size when while the grab of + the header. + * src/gdcmFile.[h|cxx] : remove PixelRead and ImageDataSizeRaw variables and + some corresponding methods. Write correctly the file and check before + write + * Test/TestCopyDicom.cxx, TestReadWriteReadCompare.cxx, + TestAllReadCompareDicom.cxx : pass the write of images to RGB and test + is now on RGB data (as before my last commit + * Example/PrintHeader.cxx, PrintFile.cxx : repad files. + +2004-11-24 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmBinEntry.cxx, gdcmSeqEntry.cxx, gdcmSQItem.cxx, gdcmValEntry.cxx : + Add a print information of the type of the entry + * src/gdcmDocument.cxx : add the write of the preambule of a Dicom file. + It was in the gdcmFile, and all write have been regrouped + * src/gdcmFile.[h|cxx] : add methods to get the Raw data elements and size. + Write correctly all dicom files (in decompressed mode only at this time) + * Test/ : test on files are now made using Raw data and not color data if + any. + * Example/PrintFile.cxx : add more printings + +2004-11-24 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * Amelioration of code, remove some code copy. For the loading of + BinEntry (in gdcmDocument), add the test to verify if the file is already + opened or not. + +2004-11-24 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmDocEntryArchive.[h|cxx] : bug fix and add a method to temporary + remove a DocEntry in the header (push an empty DocEntry) + * src/gdcmFile.[h|cxx] : remove some useless variables, methods and code + lines. Bug fix in the initialization of the PixelConvert and the + DocEntryArchive + * src/gdcmElementSet.[h|cxx] : add methods Initialize and GetNext to + use in TestCopyDicom (now this test can run under windows... but fails) + * Test/TestCopyDicom.cxx : amelioration of the test : + - test the pixels written + - add test points to quickly find where is the error + - can set a file name input and output in arguments + * Test/TestAllReadCompareDicom.cxx, TestReadWriteReadCompare.cxx : + amelioration of the test output + +2004-11-23 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmDocEntryArchive.cxx : complete the print function, that prints + all replaced DocEntry's + * src/gdcmFile.[h|cxx] : remove all changes of the header when getting data. + Now, each needed DocEntry to modify is duplicated, modified and inserted + to the header using DocEntryArchive. Thus, after save, we can restore the + header initial state. + +2004-11-22 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmFile.h : fix compilation errors on zorglub linuc computer + +2004-11-19 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmDocEntry.cxx : remove the copy of the DictEntry... there isn't + correct to copy it. The DictEntry is specified at the DocEntry creation, + then, it musn't change in the time. + * src/gdcmDocEntryArchive.[h|cxx] : new class. It's goal is to change the + header correctly. At this time, the change is only made for the first + level of the Document. In the future, it might consider sequences. + The change is made by replacing a DocEntry by an other that is created + outside the class. The old value is kept. When we restore the header + status, the added DocEntry is deleted and replaced by the old value. + * src/gdcmElementSet.h : Set the DocEntryArchive like friend. + * src/gdcmFile.[h|cxx] : Use the gdcmDocEntryArchive. Add methods to + set the write type to explicit VR, implicit VR or ACR. Add methods to set + the write mode to native, decompressed or RGB (but not used at this time) + +2004-11-15 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmSeqEntry.cxx : add initialisation of variable SeqTerm + * src/gdcmDocument.cxx : add delete of DocEntry's to remove some memory leaks + +2004-11-15 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmDocument.cxx : now, when using the ReplaceOrCreateByNumber to + set a BinEntry, the binArea is copied (like to set a ValEntry, the string + is copied). + * Test/TestCopyDicom.cxx, Example/TestCopyDicom.cxx : the image data isn't + set because already copied when copying the BinEntry's of the header + * Test/TestAllReadCompareDicom.cxx : remove warnings + +2004-11-15 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * FIX : now, the DocEntries are all deleted in the gdcmElementSet. + Two problems appear when doing it : + - with the gdcmFile : when the GetImageData method is called, the pixels + are stored in the gdcmPixelConvert, but a gdcmBinEntry link to these + data (pixels). And each structure destruct the data when it's + destructed. So we have two destructions for the same data. To solve it, + a flag is added in the gdcmBinEntry to indicate if the BinEntry owns the + data or not. If it doesn't own data, then they will not destroyed by + the gdcmBinEntry. + - with the gdcmDicomDir : the sequences (gdcmSQItem) contain DocEntry + elements. The DicomDir* (DicomDirPatient, etc.) inherit from SQItem. + Thus destruct the DicomDir* elements and the TagHT of the ElementSet + create a double destruction of the same DocEntry's. So, to solve it, + the TagHT is simply cleared and the DicomDir* elements are destroyed. + * TODO : add an entry concerning memory leaks in the DicomDir + +2004-11-15 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * FIX : src/gdcmDocument.cxx Remove obvious code in the destructor + * FIX : src/gdcmPixelConvert : Set to NULL the deleted structures in the + squeeze method + +2004-11-15 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * FIX: src/gdcmUtil.cxx : to compile with MSVC6 + * src/gdcmDocument.cxx : fix memory leaks. Fix possible bugs : use an object + after it have been deleted + +2004-11-16 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * FIX: src/* fix the doxygen warnings. + * src/gdcmVR.cxx: removed some redundant tests (e.g. LO) + * src/gdcmDocument.cxx: FIX ::ComputeRLEInfo() rleSegmentOffsetTable[] + was erroneously defined with a size of 15 instead of 16. [many thanks + to Jean Michel Rouet for pointing out this bug]. + +2004-11-15 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + 1. Finish merging JMR patch for writting DICOM from scratch + 2. Fix -hopefully- bug with MONOCHROME and space vs null character + 3. Use const ref when possible + 4. Add a new function InitializeDefaultHeader, which create a template DICOM header (CT image for now) + 5. A few more comments + 6. CreateUniqueUID can now be called without parameter" + +2004-11-15 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * ENH: Slightly bigger patch: + 1. Getting toward full integration of JMR patch for writting dicom from scratch + 2. Update Test to test part of this patch: CreateUniqueUID + 3. File was not close properly in gdcmDict + 4. Use of typedef is to be prefered when possible (gdcmDict.cxx) + 5. Use of const ref instead of copy (speed issue) + 6. Remove temporary (duplicate) string in TranslateToKey + 7. Mark extremely dangerous code as such (gdcmDocument.cxx and AddEntry fallback case) + 8. Do not repeat virtual in subclasses + 9. Implemented in gdcm::Util two new function: GetIPAddress, and CreateUniqueUID + +2004-11-15 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * Apply first patch toward better string comparison when dealing with broken + DICOM files. Essentially the string could be padded with a space instead + of a null character as defined by standard + +2004-11-15 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmDocument.[cxx|h] : fix memory leaks. The return is suppressed + because never used... and in the same time, that's remove some memory leaks + +2004-11-15 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmFile.cxx : now delete the PixelConvert instance. + * In examples and tests : change the type of image data variables from void* + to uint8_t*. Remmove all delete on image data variables + +2004-11-10 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmDocument.cxx : Set the file pointer TP to 0 in the constructors. + Verify the file pointer value before open the file, and if it's not null, + a verbose message is generated. + Close correctly the file when the file isn't considered dicom-like. The + correctly close is a call to CloseFile. + When closing the file pointer, test if its not null to close the file. + * src/gdcmPixelConvert.cxx : bug fix for the SIEMENS_GBS_III-16-ACR_NEMA_1.acr + file. For an uncompressed image, the copied data correspond in the least + case to the image size (calculated) or the image size specified in the + header. A verbose is generated if these two size mismatch + +2004-11-09 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * Test/TestAllReadCompareDicom.cxx : test the existence of the directory + using an 'ifstream' other than a 'FILE *'. The previous solution ('FILE *') + break under windows (with msvc6 compilation). + +2004-11-09 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmDicomDir.h : bug fix for the last Boix's commit (problem when + compiling with MSVC6) + +2004-11-09 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * Bugs fix for the Windows build with VC6 + * CMakeLists.txt : bug fix - The include of the VTK lib is made only when it's + needed (only for projects required VTK). If the VTK is included in all + projects, there is conflicts with the jpeg lib of vtk when compiling the + gdcmjpeg[8,12,16] projects. The first conflict is on the jmorecfg.h file. + * src/gdcmUtil.h : export binary_write methods. Otherwise, there's problems + when compiling the gdcm_wrap.cxx file (created by the compilation of the + gdcm.i file) + * vtk/vtkGdcmDemo.cxx : remove the use of std namespace for the cerr use + (like it's already made for the cout use). Otherwise, conflict with the + std::cerr of vtk. + +2004-11-09 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * src/gdcmDicomDit.h the Method typedef is now local to DicomDir class. + * gdcmPython/gdcm.i: + - comments on the DicomDir::Method related usage added. + - now that we use the namespace gdcm, a lot of internal classes do + NOT need to be wrapped anymore. + * gdcmPython/demo/DicomDirProgressMethod.py (that uses the above + DicomDir::Method) new example added. + +2004-11-05 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * Improve string manipulation. I now inforce the notion of 'DicomString' + A DicomString can contain as many \0 as they want + and it is *always* of even length. + We only support odd length for very rare case. + And in the near future this should be removed. + +2004-11-03 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * /binary_write/ gdcm source. Now even on big endian we are writting + little endian. This should -heopfully- fix some tests + +2004-11-03 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * Now the dictionary is compiled into gdcm lib. This is a default + behavior, thus any dic file specified is picked before failback to + the one comiled into lib + +2004-10-27 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * Change internals for gdcmDict. Don't use any 'new' any more. + This should definitely solve any leak problem, and we should be + as fast as before, as long as don't modify too much the dictionary. + +2004-10-25 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * STYLE: ivars should start with a capital letter. + * Accessors should be const to avoid people starting modifying stuff (since this is a ref). + * remove 'virtual' as Style specify subclasses shouldn't reuse the keyword + +2004-10-22 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * Doc/Dicom2004_Part5.pdf added (thanks to JPR). + * Dicts/dicomTS2004.dic, dicomV3VM2004.dic, groupNameAbbreviations2004.dic + new 2004 dictionaries added (thanks to JPR). + * FIX dashboard warning RLEFrame::NumberFragments is now of type unsigned int + * CLEANUP_ROUND (15) for gdcmPixelConvert + - RLEFrame::NumberFragments is now of type unsigned int + - gdcmFile::GetImageData(), GetImageDataIntoVector(), GetImageDataRaw() + are now all based on PixelConverter. ::GetImageDataIntoVectorRaw() + no longer exists. + +2004-10-21 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * Initial work in gathering all transfer syntax accessors. clearly + IsDecompressed/IsJPEG2000/IsJPEGLossless/IsRLELossless shouldn't be all + ivars, but only one transfersyntax (class) ivar with equivalent method on + the class. + +2004-10-21 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * Removed all FILE* ref and replace by ifstream/ofstream. For now I use a temp + solution with the two files jdatadst.cxx and jdatasrc.cxx, this need to be + discussed (plus I didn't like having a 2000 lines patch not commited) + +2004-10-21 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * src/gdcmDocument.cxx: wrong type on return fixed (thanks dashboard) + * CLEANUP_ROUND (14) for gdcmPixelConvert + - PixelConvert::GetLutRGBA(FILE*) is now GetLutRGBA() (no fp needed) + - PixelConvert::BuildRGBImage()(FILE*) is now BuildRGBImage() (no fp needed) + - File::GetImageDataIntoVector() doesn't need unnecessary OpenFile() and + CloseFile() anymore. + - File::GetImageDataRaw() doesn't call GetImageDataIntoVectorRaw() + anymore and hence avoids storing a copy of PixelConvert::Decompressed + into File::Pixel_Data. + +2004-10-20 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * src/gdcmDocument.cxx ftell() return properly stored in a long (i.e. + no longer depends on's programmers PMS = Preposterous Mood Swings ;). + * CLEANUP_ROUND (13) for gdcmPixelConvert + Substituted File::ParsePixelData() with PixelConvert::Print() new + method: + - src/gdcmParsePixels.cxx removed (only contained File::ParsePixelData()) + - src/gdcmRLEFrame.cxx, gdcmJPEGFragment.cxx added. Added a ::Print() + method to those classes. + - src/gdcmFile.[cxx|h]: + -- Added a ::Print() method. + -- PixelConverter is now a reference instead of a member. + -- gdcmPython/gdcm.i: added "using namespace gdcm" in order for + gdcm_wrap.cxx to "understand" File::GetPixelConverter() + +2004-10-18 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * Doc/CMakeLists.txt, doxygen.config.in: when dot is present the + collaboration diagram and inheritance diagram should be generated with + doxygen. + * Doc/Website/Sidebar.html: Dashboard is now also in the sidebar. + * gdcmPython/gdcm.i: gdcmRLEFramesInfo.h gdcmJPEGFragmentsInfo.h are + pointlessly wrapped (see + http://www.creatis.insa-lyon.fr/pipermail/dcmlib/2004-October/000692.html ) + * CLEANUP_ROUND (12) for gdcmPixelConvert (sugar is my friend stage) + - Header::GetLUTRGBA() moved to PixelConvert::GetLutRGBA() + - vtk/vtkGdcmReader.cxx: adapted to displacment of Header::GetLUTRGBA() + - Document::RLEInfo and JPEGInfo are now pointer members (Swig thing) + - src/gdcmFile.[cxx|h] and gdcmPixelConvert.[cxx|h]: + -- File::Initialise: PixelConverter setup moved away to + PixelConverter::GrabInformationsFromHeader() + -- File::GetImageDataIntoVector(): Lut R + Lut G + Lut B color table + interpretation moved away to PixelConverter::BuildRGBImage() + +2004-10-16 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * Remove GDCM_EXPORT keyword from gdcm::DirList due to : + http://support.microsoft.com/support/kb/articles/Q168/9/58.ASP + +2004-10-15 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * src/gdcmDebug.cxx last ditch attempt to get warning/error messages + displayed on Win32 when a brutal abort() occurs (because of uncatched + exception). See TODO new entry of this commit for more on this. + * TODO added new entry. + * CLEANUP_ROUND (12) for gdcmPixelConvert (nicotine is my friend stage) + src/gdcmFile.[cxx|h] and gdcmPixelConvert.[cxx|h]: + - HandleColor is no longer called from gdcmFile.cxx + - gdcmPixelConvert.cxx clean up on method arguments and internal + variable names for semantical coherence. + +2004-10-14 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * Finished lossless transition, not only do we now read all lossless jpeg + images, without the need of the Cornwell lib, but we do read them properly now + * To reduce code (well to avoid code duplication), I defined a common place + for jpeg read/write: gdcmJpeg.cxx. Now gdcmJpeg[8,12 16] include this file and + redefine symbols. This is not perfect but this the best solution I found for a + compilation time jpeg option. + +2004-10-13 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * Update jpeg ijg lib to support lossless jpeg implementation + For more info look in jpeg/libijg/README.GDCM.txt for necessary steps to + reproduce at home. + * Also added a special copyright for dcmtk since we use their bugfixes. + Thanks dcmtk crew ! + +2004-10-13 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * Doc/Website/MailingList.html added (Sidebar.html changed accordingly). + * gdcmPython/gdcm.i: fix for compilation of wrappers (Note: %include order + matters, as stated in warning note at beginning of %include section). + * src/gdcmDicomDir*.[cxx|h]: coding style + * src/gdcmDocument.h: doxygen \ref seems uncompatible with \todo. + * src/gdcmJpeg8.cxx: doxygen fix. + * CLEANUP_ROUND (12) for gdcmPixelConvert (seing the ligth stage) + src/gdcmFile.[cxx|h] and gdcmPixelConvert.[cxx|h]: color handling moved + from File:: to PixelConvert::. + +2004-10-12 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * CLEANUP_ROUND (11) for gdcmPixelConvert (cafeine is my friend stage) + src/gdcmFile.[cxx|h] and gdcmPixelConvert.[cxx|h]: + - more code moved away from File:: to PixelConvert:: + - fat setup of PixelConverter set in place in File::Initialise. + +2004-10-12 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * Apply patch for namespace in gdcm. Didn't rename files for keeping a sort of + namespace at the file system level. So now you should convert your examples + like this: + gdcmHeader -> gdcm::Header + It would be nice if people keep in mind to no open the namespace, since it + allows compilation on broken plateform which were defining common symbol in + the standard namespace (like LP, Unknown ...) + +2004-10-10 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * CLEANUP_ROUND (10) for gdcmPixelConvert (Xanax is my friend stage) + The JPEG fragments are now parsed at the same stage than the RLE + information. All code related to JPEG is now in gdcmPixelConvert: + - src/gdcmJPEGFragment.h and gdcmJPEGFragmentsInfo.[h|cxx] added + - src/gdcmJpeg12.cxx, gdcmJpeg2000.cxx and gdcmJpeg8.cxx no longer + export a gdcmFile:: method. Those are simply global functions + (for the time being this is better than having them attach to + either gdcmFile:: or gdcmPixelConvert::). + - src/gdcmDocument.[cxx|h], gdcmDocument:: now parser the JPEG fragments + and stores the result in a gdcmJPEGFragmentsInfo. + - src/gdcmFile.[cxx|h] and gdcmPixelConvert.[cxx|h]: all JPEG related + code (among other stuff) moved away from gdcmFile:; to + gdcmPixelConvert:: + +2004-10-08 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * src/gdcmCommon.h now declares int8_t for non stdint.h plateforms. + * CLEANUP_ROUND (7) for gdcmPixelConvert (lost at sea) + - src/gdcmFile.h gdcmPixelConvert.cxx gdcmPixelConvert.h gdcmRLE.cxx: + clean up of RLE related code. + * CLEANUP_ROUND (8) for gdcmPixelConvert (end of RLE nigthmare) + - src/gdcmRLE.cxx removed + - src/gdcmPixelConvert.cxx all RLE code is now in PixelConvert:: + - src/CMakeLists.txt gdcmFile.[cxx|h] changed accordingly + - src/gdcmRLEFrame*.h gdcmPixelConvert is now a friend class. + * CLEANUP_ROUND (9) for gdcmPixelConvert + - src/gdcmFile.[cxx|h} gdcmPixelConvert.[cxx|h], SwapZone(), + ConvertReorderEndianity(), ConvertDecmpres12BitsTo16Bits() moved + away from gdcmFile:: to gdcmPixelConvert::. + +2004-10-07 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * CLEANUP_ROUND (5) for gdcmPixelConvert (Upshit creek without a paddle) + - src/gdcmDocument.[cxx|h] Parse7Fe0 renamed to ComputeRLEInfo. + This is because Parse7Fe0 used to parse the pixels to compute the + length. This task was passed over to FindDocEntryLengthOB() a long + time ago, EXCEPT I forgot the OW case... + Hence Parse7Fe0 was no longer necessary. When renaming to ComputeRLEInfo + we just recylce the code for parsing RLE fragments and computing + offsets. + * CLEANUP_ROUND (6) for gdcmPixelConvert (man, I need a paddle bad) + - src/gdcmRLE.cxx: is now much simpler and avoids code replication + with the retired Parse7Fe0(). + - src/gdcmRLEFrame.h: type fix for properly computing OffSet[] + - src/gdcmDocument.cxx: segments offset are now correct + clean up. + +2004-10-06 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * CLEANUP_ROUND (3) for gdcmPixelConvert (nightmare stage) + - src/gdcmRLEFramesInfo.[cxx|h], gdcmRLEFrame.h added + - src/gdcmDocument.[cxx|h] ::Parse7FE0 now sets up the RLEInfo. + - src/CMakeLists.txt: alphabetic order reodering + new entries. + * CLEANUP_ROUND (4) for gdcmPixelConvert + - src/gdcmDocument.[cxx|h] ::ParseDES and ::ParseSQ no longer bother + to return an unused length. + +2004-10-09 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * Remove all sprintf from the code to centralize in one spot in gdcmUtil + this should be cleanner from the plane view. The iostream are erally a pain + to use to do simple stuff. + +2004-10-04 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * Redo the compilation of the ijg jpeg library. Now only one source is + necesseray. No need to rename file by hand what so ever. CMake handle the + copying of the file within different directory, configure header file to + modify some symbol. The only addition made to ijg wasd a mangle table so + that symbol are different whether we are within 8bits or 12bits. + +2004-10-01 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * Added documentation of vtkgdcmReader on Website: + - testvtkGdcmReader.cxx renamed to vtkGdcmDemo.cxx (to be compatible + with it's binary name). + - vtk/vtkGdcmDemo.cxx and vtkgdcmViewer.cxx: added comments for + the Website to be more complete. + - Doc/doxygen.config.in: vtk/vtkGdcmReader.cxx now appears on + doxygenated documentation. + - Doc/DoxyVtkGdcmReaderExamples.txt added + (see http://www.creatis.insa-lyon.fr/Public/Gdcm/html.developper/ + DoxyVtkGdmReaderExamples.html ) + * src/win32, vtk/win32 manually maintained .dsp and .dsw removed. + * CLEANUP_ROUND (3) for gdcmPixelConvert + - src/gdcmFile.cxx, gdcmFile.h splitting GetImageDataIntoVectorRaw + +2004-09-29 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * CLEANUP_ROUND (2) for gdcmPixelConvert + - src/gdcmFile.cxx, gdcmFile.h splitting GetImageDataIntoVectorRaw + +2004-09-29 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * CLEANUP_ROUND for gdcmPixelConvert: + - src/gdcmFile.cxx, gdcmFile.h, gdcmHeader.cxx, gdcmHeader.h clean up + - src/gdcmPixelStuff[h|cxx] removed + - src/gdcmPixelConvert[h|cxx] added. Preparatory work included. + - src/CMakeLists.txt changed accordingly + * GDCMHOME clean up: + - MANIFEST.in, WrapSwig.py, WrapVTK.py, distutilsWrapping.py and + gdcmVersion.py moved to newly created ATTIC related + gdcmPython/SetupOldies/ directory. + * Autotools clean up: + - */*/Makefile.am removed AT EXCEPTION of gdcmPython/Makefile.am + - autogen.sh configure.in acinclude.m4 python.m4 removed + +2004-09-27 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * src/*.cxx *.h Reference to License.htm fixed to License.html. + * Doc/CMakeLists.txt, doxygen.config.in: fix. + * Doc/Website/ConformanceSummary.html, minimal conformance statement added. + +2004-09-24 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * TODO updated with Mathieu suggestions. I proposed a template for + describing TODO entries and used it for new entries. + * Added Doc/Website/CodingStyle.html, Developpers.html, + DeveloppersPython.html, GdcmDataCvs.html and + DownloadVersion0_1.html, DownloadVersion0_3.html. + * Some Doc/*.txt Doxygen files (which do not really concern the + documentation itself, but the website) moved to html and + placed in directory Doc/Website: + - Doc/DoxyDevelInstal.txt moved to Doc/Website/Developpers.html + - Doc/DoxyInstallation.txt moved to Doc/Website/Installation.html + - Doc/DoxyIntroduction.txt included in Doc/Website/Main.html + * Doc/DoxyfileDeveloppers, DoxyfileUsers, Makefile.am oldies removed. + * CMakeLists.txt changed accordingly. + * DEVELOPPER spread out in Doc/Website/Developpers.html, CodingStyle.html, + DeveloppersPython.html + * INSTALL nows refers to Doc/Website/Installation.html + +2004-09-23 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * Added Doc/Website directory, that contains a first raw version + of gdcm Web site. + +2004-09-23 Jean-Pierre Roux + * FIX In order not to be poluted any longer by casting problems, + the member VoidArea of gdcmBinEntry is now uint8_t* (instead of void *) + we can now delete[] it safely + * VoidArea is now called BinArea (less confusing name), + and all the methods called ...VoidArea... are now ... BinArea... + * class gdcmObject is now called gdcmDicomDirObject (less confusing name) + +2004-09-22 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * src/gdcmDocument.cxx: gdcmDocument::~gdcmDocument() doesn't clear (nor + clear) TagHT, which is an inherited member of gdcmElementSet. It is + up to the destructor of gdcmElementSet to clean up TagHt and it's + pointed content. + +2004-09-21 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * Test/CMakeLists.txt: update to follow gdcmData renamings. + * src/gdcmCommon.h, gdcmDocument.cxx: doxygen typos + +2004-09-17 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * ENH: added some utility method that builds a flat dictionary + holding all the Dicom entries contained in the recursive structure + of a gdcmElementSet. Refer to add FlatHashTablePrint.cxx for + an example of usage. + - src/gdcmDocument.[h|cxx] added BuildFlatHashTableRecurse() and + BuildFlatHashTable() that build a flat dictionary. + - src/gdcmElementSet.h: added a new private GetTag() accessor. + gdcmDocument is now a friend of gdcmElementSet. + - src/gdcmElementSet.cxx: clean up. + - Example/FlatHashTablePrint.cxx added. + - Example/CmakeLists.txt changed accordingly + +2004-09-16 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * gdcmDocEntrySet::SQDepthLevel and gdcmDocEntrySet::BaseTagKey attributes + moved away from gdcmDocEntrySet (since this class is an abstract class + acting like an interface). SQDepthLevel and BaseTagKey are now + in class + - src/gdcmDocEntrySet.[h|cxx] removal of SQDepthLevel and BaseTagKey + and associated accessors. Doxygenation of the class. + - src/gdcmSQItem.[h|cxx] SQDepthLevel and BaseTagKey and associated + accessors added. + - src/gdcmSeqEntry.[h|cxx]: constructor doesn't handle depth anymore. + Use SQDepthLevel accessor instead. ::Print() adapted. + - src/gdcmElementSet.cxx changed according to changes in gdcmSeqEntry. + - src/gdcmDocument.cxx changed accordingly. + +2004-09-13 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * Preparation of writing a gdcmHeader iterator: generalisation of gdcmTagKey + - The following is the doxygen comment of the typedef declaration + of gdcmTagKey in src/gdcmCommon.h: + gdcmTagKey is made to old an "universal" (as in URL, Universal + Ressource Locator) key to a gdcmDocEntry i.e. a dicom tag. + A dicom tag always has a group and an element, but a set of tags + embeded in various (optionally nested) sequences and sharing + the same group and element all share the same (group, element) + "identifier". Hence the (group, element) cannot be used as an + identifier (in gdcm we shall refer to a "TagKey") of a tag. + In order to construct a proper tag identifier (i.e. a key) we + consider the following definition of a TagKey: + - let Group, Element be the string representation of the + group and element dicom tag members, + - let ItemNumber be the string representation of the integer + index of the considered item number of a sequence, + Let the key of a tag embeded in a sequence, noted SeqTag, be + the form: + /ItemNumber#Group|Element + where "/", "#" and "|" are characters acting as separators. + Then the general form of a gdcmTagKey is given by: + Group|Element<SeqTag> + where <SeqTag> means NO or many instances of SeqTag. + Hence the gdcmTagKey of a tag not "leaving" in a sequence is the + string e.g. + 0028|1201 + but the gdcmTagKey of a tag "embeded" is the first item of + a sequence, itself nested in the third item of a sequence is the + string e.g. + 0004|1220/2#0008|0082/0#0008|0090 + - src/gdcmDocEntry.h: added a new Key (of type gdcmTagKey) member, in + order to hold the new sequence compatible key. Previously, the + GetKey() method would look in the underlying gdcmDictEntry. + - src/gdcmDocEntry.cxx: + -- constructor now copies the underlying DictEntry key, in the local + Key member. + -- ::Print: displays the member Key, instead of the (group, element). + - src/gdcmCommon.h: added some comments on typedef gdcmTagKey. + - src/gdcmDocEntrySet.h:xi + -- ::ParseDES() now setups the gdcmTagKey of the sequence it is parsing. + -- now has a new BaseTagKey member. + -- STYLE. + * src/gdcmValEntry.[h|cxx], src/gdcmBinEntry.[h|cxx]: the member VoidArea, + previously a member of gdcmValEntry, moved to gdcmBinEntry were is + truly belongs. + This poses the problem with the semantics of the following lines + LoadEntryVoidArea(0x0028,0x1201); // R LUT + LoadEntryVoidArea(0x0028,0x1202); // G LUT + LoadEntryVoidArea(0x0028,0x1203); // B LUT + in gdcmDocument::gdcmDocument(std::string const & ). Please refer + to the long FIXME note for what the problem is. Nevertheless in + order to get things working the dicom dictionary was altered ! + Please fix things urgently... + * Dicts/dicomV3.dic WRONGLY altered (this means we introduced a uncorrect + information), see above note on moving the member VoidArea. Nevertheless + the following entries previously correctly set as US are now inproperly + set to OW: + 0028 1201 OW IMG Red Palette Color Lookup Table Data + 0028 1202 OW IMG Green Palette Color Lookup Table Data + 0028 1203 OW IMG Blue Palette Color Lookup Table Data + * src/gdcmDocEntry.[h|cxx], src/gdcmSeqEntry.h: SQDepthLevel member + of gdcmDocEntry moved to gdcmSeqEntry. + * src/gdcmSeqEntry.cxx: STYLE. + +2004-08-04 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * Test/TestAllEntryVerify.cxx minor fix and added comments. + +2004-08-03 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * gdcmPython/testSuite.py: all the test suite in python is now moved + to it's C++ version (see gdcmData/TestAllEntryVerifyReference.txt) + * Test/CMakeLists.txt adapted to renaming of files in gdcmData + * gdcm/TODO and src/gdcmDictSet.h cleaned up frow the "TODO Swig" oldies + +2004-08-02 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * gdcmPython/CMakeLists.txt: SWIG_FLAGS doesn't declare includeall + to avoid inclusion recursion until STL is reached. + * src/gdcmDocument.[h|cxx]: exceptions substituted to errno C-style + mecanism. errno.h is not included in gdcm anymore. + * src/gdcmException.h: introduced new gdcmFormatUnexpected class + (gdcmFormatError now inherits from gdcmFormatUnexpected). + * TODO updated + * gdcmPython/testSuite.py checks on CR-MONO1-10-chest.dcm moved to + gdcmData/TestAllEntryVerifyReference.txt + * Test/TestAllEntryVerify.cxx is now effective (used always return true) + * src/gdcmDocument.[cxx|h]: constructors no longer use the bool + exception_on_error parameter. + - src/gdcmFile.[cxx|h], src/gdcmHeader.[cxx|h] changed accordingly, + - vtk/vtkGdcmReader.cxx changed accordingly, + - Example/*.cxx and Test/*.cxx changed accordingly. + +2004-07-06 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * src/gdcmDicomDir.cxx, gdcmDocEntrySet.cxx: removed inclusion of errno.h + * src/gdcmDocument.[h|cxx], gdcmFile.[h|cxx], gdcmHeader.[h|cxx]: + enable_sequences removed from gdcmHeader constructor and dependencies. + * Example/PrintHeader.cxx: fixed accordingly (enable_sequences removal). + * gdcmPython/demo/PrintHeader.py: dummy fix. + * src/gdcmDocument.[h|cxx], gdcmFile.[h|cxx], gdcmHeader.[h|cxx]: + skip_shadow removed from gdcmHeader constructor and dependencies. + * Example/*.cxx and Test/*.cxx changed accordingly. + +2004-07-27 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * Test/CMakeLists.txt: newly re-introduced SIEMENS_Sonata-12-MONO2-SQ.dcm + in gdcmData (previously known as E00001S03I0015.dcm) is blacklisted. + +2004-07-21 Jean-Pierre Roux + * FIX Now, Parsing and Printing a DICOMDIR do work! + ( troubles remain in makeDicomDir and BuildUpDicomDir :-( + +2004-07-20 Jean-Pierre Roux + * FIX Some brain damaged headers have Zero-Lenght fields + for 'Transfert Syntax UID', or 'Media Stored SOP Class UID'. + +2004-07-19 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmCommon.h, gdcmDict.cxx, gdcmTS.cxx : bug fix for msvc6 compilation + * src/gdcmDebug.[h|cxx] : bug fix for msvc6 compilation. Replace the dbg + variable (instance of gdcmDebug) by a definition macro, and the instance + is now in static in the gdcmDebug class + * src/gdcmSQItem.h : (FIXME) remove an undefined method + * Test/PrintAllDocument.cxx : bug fix in the result of the test + +2004-07-06 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * WARNING: ctest now depends more tightly on gdcmData. You should + check out gdcmData properly for things to run smoothly... + * src/gdcmDocument.cxx MAX_SIZE_LOAD_ELEMENT_VALUE is set back to 0xfff + (4096) for "ctest -R TestAllEntryVerify" to be able to run (i.e. + we need the pixels not be loaded in order to use the ValEntry + that displays position and size). + * Test/TestAllEntryVerify.cxx a new low level test now seems fair. + This is a C++ based equivalent of gdcmPython/testSuite.py that should + be deprecated. If you have any doubts about the advantages of a + modern scripting language (read Python) versus grass root C++ (i.e. + without lex + yacc, because of gdcm commitement to MS-VC++, sighhh), + I suggest you compare TestAllEntryVerify.cxx (639 lines, without the + reference file gdcmData/TestAllEntryVerifyReference.txt) and testSuite.py. + Anyhow, consider documenting the gdcmData images in + gdcmData/TestAllEntryVerifyReference.txt (and please run ctest before + commiting changes). + * Test/CMakeLists.txt: + - now uses TestAllEntryVerify.cxx + - specific comments on oldACR00001.ima (now renamed in gdcmData + to SIEMENS_GBS_III-16-ACR_NEMA_1.acr) moved away to + gdcmData/TestAllEntryVerifyReference.txt + * TODO updated. + +2004-07-02 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * src/*.[h|cxx] : typedef clean up + - guint16 and guint32 removed. Use ISO C uint16_t, uint32_t instead. + - TagKey renamed to gdcmTagKey (for external usage) + - VRKey renamed to gdcmVRKey (for external usage) + - removal of typedef duplication. + - Removed all unecessary inline keyword from class inline definitions. + - Some method|function(void) declarations replaced with method|function(). + * src/jpeg/libijg12/jdhuff12.c: + - printf polluting ctest removed. + - TAB removal for comminting + * Test: + - TestAllReadCompareDicom.cxx: added a test that compares all the + images in gdcmDataImages.h with corresponding images in + gdcmData/BaselineDicom/. When baseline images are not present + this test creates them. + Note: we need to validate each reference image, but before that + I'd like to rename them with a more explicit name... + - CMakeLists.txt: changed accordingly. + * Example/*.cxx: examples now only include gdcm.h (as opposed to + including each header needed). + +2004-07-01 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * Test/*.cxx and Example/*.cxx: moved some examples away from the + test suite to the Example directory. Are concerned: + - PrintHeader.cxx + - TestDcm2Acr.cxx + - TestFindTags.cxx + - TestWrite.cxx was + - TestWriteSimple.cxx + * Test/CMakeLists.txt: added some comments on reasons for black listing + image gdcmData/oldACR00001.ima + +2004-06-30 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * Test/CmakeList.txt: removed the following from black list (to be coherent + with removal from gdcmData): + - gdcm-MR-PHILIPS-16-Multi-Seq.fixed.dcm + - gdcm-MR-PHILIPS-16.dcm + - US.3405.1.dcm + Added the following because after last cvs update, they cause + ctest -R TestReadWriteReadCompare + to segfault: + - gdcm-MR-SIEMENS-16-1.acr + - oldACR00001.ima + * Test/TestReadWriteReadCompare.cxx was properly written (with a call + to gdcmFile::SetImageData()) BUT since gdcmFile is brain damaged (see + new comments in this file) we temporarily (sigh) move to a weaker + form of test... + * Test/CmakeList.txt: with the change to Test/TestReadWriteReadCompare.cxx + we don't need to black list the following images anymore: + - 8BitsUncompressedColor.dcm + - OT-PAL-8-face.dcm + - US-PAL-8-10x-echo.dcm + * src/gdcmDocument.[h|cxx]: RE-Reverting to version 1.42 with the proper + fixes and the beautified code ;-) + This fixes the bug introduced in version 1.42 (when beautifying) + that made the parsing of 8BitsRunLengthColor.dcm unproper. + Note: ctest was blind to this bug (this means we need to still + improve the test suite). The bug could be detected by using + gdcmbin/bin/PrintDocument $GDCM_DATA/8BitsRunLengthColor.dcm + or by using + gdcmbin/bin/ReadWrite $GDCM_DATA/8BitsRunLengthColor.dcm + and by displaying the (garbage) produced file temp.XDCM... + +2004-06-29 Jean-Pierre Roux + FIX : - remove Frog's beautified, but never checked 'Parse7FE0' code, + - replace by uggly but working old code :-( + A lot of things should be OK again. + It's really urgent to have a test suite that *tests*, + to prevent Frog's beautifying sessions to break all the stuff + (twice, withing a fortnigh ...) + +2004-06-28 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * Test/TestWriteRead.cxx and TestReadWrite.cxx merged (because of + redundancy) to added Test/TestReadWriteReadCompare.cxx + * Test/CmakeList.txt: because the compare test of + Test/TestReadWriteReadCompare.cxx fails, the following images are + black listed: - 8BitsUncompressedColor.dcm + - OT-PAL-8-face.dcm + - US-PAL-8-10x-echo.dcm + * src/gdcmDocument.cxx: for broken (non DICOM V3 conformal) images + (e.g. gdcm-JPEG-LossLess3a.dcm see comments in + gdcm/gdcmPython/testSuite.py for details) ::FindDocLengthOB() had + and ad-hoc kludge. This kludge is now removed, and on encountering + such an image (OB field brain damaged) we set errno. Then in + ::FindDocLength() we "fix" the length as being ALL what remains + in the file (until EOF). We then proceed, hoping for the best... + This fixes a SegFault in ShowDicom when trying to write such an + image. + * Test/CmakeList.txt: 8BitsRunLengthColor.dcm is now blacklisted + (because TestWriteRead breaks on it, after a non conformal commit?). + ctest now runs properly, except for MakeDicomDir (which was always + broken) and the Python related stuff (still not fixed). + +2004-06-24 Jean-Pierre Roux + ADD : Examples/WriteRead, that acts like the former Test/TestWriteRead + FIX : Test/TestReadWrite now iterates on all the file names + (instead of infinite loop) + ENH : Test/TestWriteRead now iterates on all the file names + +2004-06-28 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * Test/TestReadWrite.cxx: now uses all the images of gdcmData. + +2004-06-24 Jean-Pierre Roux + FIX : - now Write drops LUT Descriptors and LUTs (if any) + when SamplesPerPixel =3 + - now Write is no longer confused by + 'BitsAllocated = 12" and 'BitsStored=12" + - "UN" value representation Elements are now written correctly + (their legth is stored on 4 bytes -just like OB, OW, and SQ-) + ENH : - now gdcmHeader has its own Write methods + (in order to split the job that has not to be done + for gdcmDicomDir) + +2004-06-23 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * Test/PrintAllDocument.cxx: looping on files is now effective. It used to + loop on the same image until memory went out. + Note: this means we still have gobs of memory loss in PrintDocument + * src/gdcmDocument.cxx: fixes problem on parsing on file + gdcmData/16BitsJpegLosslessGrayScale.dcm. + +2004-06-24 Jean-Pierre Roux + FIX : Write - All the Sequences and Sequence Item are now written + as 'no length' stuff, and a Sequence Delimitor aor an Item Delimitor + is added a the end, when necessary. + - A lot of brain-damaged images, that were read correctly are + now written correctly + - length compatible BinEntry are now loaded correctly + (even for odd groups) + Note : only Explicit Value Representation was checked. + (question : is implicit VR really necessary for gdcm ?) + +2004-06-23 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * DEVELOPPER: added a proposition of coding style. + * src/gdcmDocEntry.h: removed every inline declaration (for test of + coding style). + +2004-06-23 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * gdcmDocEntry::PrintCommonPart() and ::WriteCommonPart() removed. + Use the gdcmDocEntry::Print() and Write() instead. + * src/gdcmDocument.cxx: bug fix. + +2004-06-22 Jean-Pierre Roux + FIX : gdcmDocument.cxx + - Now we do recognize the JpegLossLess format (there was a misstyping in + code 'beautyfication' :-( + - Now we automaticaticaly load the Luts, if any + +2004-06-22 Jean-Pierre Roux + In order : to write Sequences, whatever their imbrication level, + : to allow user to create his own Sequences + a lot of modif where necessary (adding, moving, or virtualising methods) + + WARNING : save your own sources *before* cvs up ! + + - gdcmBinEntry + ADD virtual void Write(FILE *fp, FileType filetype); + + - gdcmDocEntry + ADD virtual void Write(FILE *fp, FileType filetype); + ADD void gdcmDocEntry::WriteCommonPart(FILE *fp, FileType filetype); + + - gdcmDocEntrySet + ADD virtual void Write (FILE *fp, FileType filetype)=0; + ADD virtual gdcmDocEntry *GetDocEntryByNumber(guint16 group,guint16 element) = 0; + ADD gdcmDocEntry *GetDocEntryByName(std::string name); + ADD virtual std::string GetEntryByNumber(guint16 group,guint16 element) = 0; + ADD std::string GetEntryByName(TagName name); + ADD gdcmDictEntry *NewVirtualDictEntry(guint16 group, + guint16 element, + std::string vr = "unkn", + std::string fourth = "unkn", + std::string name = "unkn"); + ADD gdcmValEntry *NewValEntryByNumber(guint16 group, guint16 element); + ADD gdcmBinEntry *NewBinEntryByNumber(guint16 group, guint16 element); + ADD gdcmDocEntry *NewDocEntryByNumber(guint16 group, guint16 element); + ADD gdcmDocEntry *NewDocEntryByName (std::string Name); + ADD gdcmDictEntry *GetDictEntryByName (std::string Name); + ADD gdcmDictEntry *GetDictEntryByNumber(guint16, guint16); + REM virtual gdcmDocEntry *NewDocEntryByNumber(guint16 group, guint16 element)=0; + REM virtual gdcmDocEntry *NewDocEntryByName (std::string Name)=0; + + - gdcmDocument + ADD virtual bool WriteF(FileType type); // New stuff, with recursive exploration + ADD virtual std::string GetEntryByName (TagName tagName); + ADD virtual std::string GetEntryVRByName (TagName tagName); + REM virtual bool Write(FILE *, FileType); + REM virtual void WriteEntryTagVRLength(gdcmDocEntry *tag, + FILE *_fp, FileType type); + REM virtual void WriteEntryValue(gdcmDocEntry *tag,FILE *_fp,FileType type); + REM virtual bool WriteEntry(gdcmDocEntry *tag,FILE *_fp,FileType type); + REM virtual bool WriteEntries(FILE *_fp,FileType type); + REM virtual std::string GetEntryByName (std::string tagName); + REM virtual std::string GetEntryVRByName (std::string tagName); + REM gdcmDictEntry *GetDictEntryByName (std::string Name); + REM gdcmDictEntry *GetDictEntryByNumber(guint16, guint16); + REM gdcmDictEntry *NewVirtualDictEntry(guint16 group, + guint16 element, + std::string vr = "unkn", + std::string fourth = "unkn", + std::string name = "unkn"); + REM gdcmDocEntry *NewDocEntryByNumber(guint16 group, guint16 element); + REM gdcmDocEntry *NewDocEntryByName (std::string Name); + REM gdcmValEntry *NewValEntryByNumber(guint16 group, guint16 element); + REM gdcmBinEntry *NewBinEntryByNumber(guint16 group, guint16 element); + + - gdcmElementSet + ADD virtual void Write(FILE *fp, FileType filetype); + + - gdcmSeqEntry + ADD virtual void Write(FILE *fp,FileType filetype); + + - gdcmSQItem + ADD virtual void Write(FILE *fp, FileType filetype); + ADD virtual std::string GetEntryByNumber(guint16 group, guint16 element); + REM std::string GetEntryByNumber(guint16 group, guint16 element); + REM std::string GetEntryByName(TagName name); + + - gdcmValEntry + ADD virtual void gdcmValEntry::Write(FILE *fp, FileType filetype); + +2004-06-21 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * Test/TestWriteSimple.cxx: fix to gdcmHeader-gdcmHeaderHelper revamping. + The default constructor invoked by the line + gdcmHeader *f1 = new gdcmHeader( header ); + was gdcmHeader::gdcmHeader(bool) instead of the expected + gdcmHeader::gdcmHeader(std::string const &, bool = false, bool, bool). + Hence the parsing wasn't executed... See also below. + * src/gdcmHeader.h: the declaration of gdcmHeader::gdcmHeader(bool) + as explicit constructor didn't do the trick to fix the above problem. + Could anyone explain why ? + * src/gdcmBinEntry.cxx, gdcmValEntry.cxx: gdcmBinEntry::Print() now + properly calls gdcmValEntry::Print() (that was weed out from + code related to gdcmBinEntry). + +2004-06-20 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * In order to fix memory leaks: + - Test/TestWriteSimple.cxx: added cleaning of free store through + some delete calls. + - src/gdcmBinEntry.cxx: fix to avoid SegFault. + - src/gdcmDicomDir.[cxx|h]: fixed initialisation in constructor + gdcmDicomDir::gdcmDicomDir(bool) [either the constructor itself + (through the call to ::AddDicomDirMeta()) or the destructor + would crash when deleting uninitialized ::metaElems]. + - src/gdcmDictEntry.cxx: annotation of ununderstood memory leak. + - src/gdcmDocument.cxx: + -- ::~gdcmDocument() destructor now cleans up all dictionary entries + from dynamic stores. + -- ::ParseDES() misplaced deletion of temporary NewDocEntry + was causing memory leaks. + - src/gdcmSQItem.cxx: + -- ::~gdcmSQItem() dummy code cleaned (learned that deletion is + cleanly handled with polymophism: sorry but my milage is low). + -- ::SetEntryByNumber(string, guint16, guint16) now cleanly allocates + a gdcmValENtry, and makes no assumption on type (gdcmDocEntry, + gdcmSeqEntry vs gdcmValEntry) of existing entry (when present). + This avoids SegFaulting. + - src/gdcmSQItem.h: coding style. + * Conclusion: + - Test/TestWriteSimple still severely sucks. The output image content + (when $(GDCMDATA_HOME)/012345.002.050.dcm in input) is brain + damaged when displayed with vtkgdcmViewer. + - on memory leaks: TestWriteSimple leaks really less (see entry + of 2004-06-18 in Changelog file for the call to valgrind). + - on segfaults: ctest now passes all the tests but one (no more + segfaults). + * Erroneous leading white fix: + - src/gdcmDict.cxx: getline(from,xxx) doesn't remove the leading + white[s] (as opposed to from >> xxx, that removes it [them]. + - src/gdcmTS.cxx: ditto. + - gdcmPython/testSuite.py: dirty related kludge removed. + * src/*: remaining references to gdcmParser removed. + * src/*[cxx|h]: added copy[way]left header. + + +2004-06-18 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * In order to fix writing of dicom files: + - Test/TestWriteSimple.cxx: a simpler example of writing. + - Test/CMakeLists.txt changed accordingly. + - src/gdcmDocument.cxx: + -- The destructor now recursilvely removes potential sequences. + -- Bug fix in ::IsJPEG2000() + -- ::ReplaceOrCreateByNumber(std::string, guint16, guint16) + now handles promotion of gdcmDocEntry to gdcmValEntry in a cleaner + manner. + -- ::GetValEntryByNumber(guint16, guint16) now defined (as opposed + to only declared) and build on top of + ::GetDocEntryByNumber(guint16, guint16). + -- ::SetEntryByNumber() now uses GetValEntryByNumber(group, element) + - src/gdcmElementSet.[h|cxx]: added ::RemoveEntry(gdcmDocEntry *) + for usage in destructor and treatement of promotion in + ::ReplaceOrCreateByNumber(). + - src/gdcmSQItem.cxx: destructor should better handle his job. + Test/TestWriteSimple now runs (or at least it DOES something). + * We can now start hutting memory links. A good starting point is: + valgrind -q --skin=memcheck --leak-check=yes --leak-resolution=high + --num-callers=100 --show-reachable=yes gdcmTests TestWriteSimple + $(GDCMDATA_HOME)/012345.002.050.dcm foo.dcm + +2004-06-18 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * Valgrind note: after Mathieu Malaterre teached me how to read + the valgrind FAQ ;-] (see http://valgrind.kde.org/faq.html), I + learned that: + Using gcc, you can force the STL to use malloc and to free memory as + soon as possible by globally disabling memory caching. + With 3.2.2 and later, you should export the environment variable + GLIBCPP_FORCE_NEW before running your program. + By setting GLIBCPP_FORCE_NEW, STL related memory leak messages of gdcm + simply vanish (it is still not clear to me, whether this means that + STL std::string leaks or if valgrind believes it leaks...). + * Fixing of SegFault of Test/makeDicomDir (as shown by ctest or by + running bin/gdcmTests makeDicomDir): + - src/gdcmDicomDir.cxx: dynamic casting used + clean up. + - Test/makeDicomDir.cxx now properly traps empty lists and returns + with 1. + NOW, makeDicomDir cleanly fails (in ctest terminology) instead of + SegFaulting (I drowned in DicomDir related code when trying to + understand why the list is empty...). + * src/gdcmDocument.h: first BSD license header try. + * Doc/License.txt added. + +2004-06-15 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * src/gdcmDocument.[h|cxx]: + - Clean up of the Transfer related predicates. They are now all based + on new method isGivenTransferSyntax, that (should) handle properly + the padding problem. + - general clean up, simplification, and coding style. + - Specific clean up of Parse7FE0() (umproperly named actually). + * gdcmPython/testSuite.py: an odd temporary kludge introduced. + +2004-06-14 Jean-Pierre Roux + * gdcmSeqEntry.cxx + - fix the display of Sequence Delimitor (SQDepthLevel pb) + - fix the display of SQItem ordinal number + - add the GetSQItemByOrdinalNumber method + - remove some useless never written private methods + +2004-06-14 Jean-Pierre Roux + * gdcmBinEntry.cxx + - adding a constructor taking a gdcmDocEntry as an input param + - ReplaceOrCreateByNumber now returns : + a gdcmBinEntry * if a Binary (void *) value is passed as a param + a gdcmValEntry * if a string value is passed as a param + * dcmDocument.cxx + - SetEntryByNumber now allows setting gdcmValEntry or gdcmBinEntry, + according to the param type (no longer sets a gdcmDocEntry) + - GetValEntryByNumber, GetBinEntryByNumber added + - NewValEntryByNumber and NewBinEntryByNumber added + * gdcmFile.cxx + - Pixel Data are now linked to the (7fe0,0010) elements, after reading + * gdcmSQItem.h + - GetSQItemNumber and SetSQItemNumber added, to provide + a (relative) Item identier inside a given Sequence + \warning : some pb remaining around this number + will be solved asap + - AddEntry now takes the Item Number as a param + * gdcmValEntry.cxx + - adding a constructor taking a gdcmDocEntry as an input param + +2004-06-14 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * Memory leak hunt with the following command: + valgrind --leak-check=yes --leak-resolution=high --num-callers=40 + --show-reachable=yes gdcmTests PrintDocument + It looks like many (all?) leaks are due to the STL (or a bad usage + of the STL. The lines producing the leaks now have a comment with + a "MEMORY LEAK" tag: you can retrieve them with + grep "MEMORY LEAK" src/* + Here are two typical examples which I can't help fixing: + ----- + #include <string> + int main() { + std::string name; + char * test = "babo"; + name = test; //// <--- valgrind detects 960 bytes lost in + //// call to std::string::operator=(char const*) + name.clear(); //// Doesn't help ! + return 0; + } + ----- + #include <string> + #include <iostream> + int main() { + std::string line; + std::cout << "Type a bunch of characters followed by RETURN: "; + getline(std::cin, line); //// <--- valgrind dectects a loss + //// of 1320 bytes in call to + /// std::basic_istream<>& std::getline<> + return 0; + } + ----- + + +2004-06-10 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * src/gdcmHeader.[cxx|h]: + - Predicates on the Transfer syntax (of the form Is[JPEG|RLE]*) + and related, moved away to gdcmDocument. + - Accessors (on the form [Get|Set]Entry*) set up to expose publicly + the corresponding protected accessors of inherited class + gdcmDocument, removed ! As a consequence gdcmFile had to be + declared friend of class gdcmDocument (see below). + - operator< moved to gdcmDocument (in fact it belongs to gdcmDicomDir). + - Clean up of undefined or unused methods. + * src/gdcmFile.[cxx|h]: added SetEntryByNumber (in order to take into + account the changes to gdcmHeader.h). + * src/gdcmDocument.h: + - gdcmFile is now a friend class (in order to take into account the + changes to gdcmHeader.h). + - Predicates on the Transfer syntax (of the form Is[JPEG|RLE]*) added + (see changes to gdcmHeader.h). + - Accessors (reading on the form GetEntry*) are now public. + - Clean up of undefined or unused methods. + * src/gdcmDocument.cxx: + - adaptation to changes to gdcmDocument.h + - ::OpenFile now writes a verbose message when file cannot be opened. + - some std::string properly set to VRKey + * src/gdcmDicomDir.h: historical references to gdcmHeader changed to + references to gdcmDocument. + * Test/TestFindTags.cxx: changed accordingly to above changes. + * gdcmPython/testSuite.py: adapted to renaming of acr files in + cvs repository gdcmData. + +2004-06-09 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * src/gdcmValEntry.h: member voidArea type changed from char* to void*. + * src/gdcmBinEntry.h: member voidArea commented out, since it potentially + conflicts with gdcmValEntry::voidArea. + * src/gdcmValEntry.cxx: unmatching comment wiped out. + * src/gdcmVR.[h|cxx]: added two predicates that partition the possible + Value representation between StringRepresentable and BinaryRepresentable. + * src/gdcmDocument.cxx: + - method ParseDES: proper indentation restored and usage of + gdcmVR::IsVROfGdcmStringRepresentable wired in. + - method LoadDocEntry: the fingerprint left in the SetValue() of + unloaded entries (length > MaxSizeLoadEntry) had curiously been + removed. Reverting to previous code segment with the proper + dynamic_cast< gdcmValEntry* >. + Note: this was (partially) breaking the python test suite + (gdcmPython/testSuite.py) that made usage of the above + fingerprint to check presence of "Pixel Data". + * src/gdcmDocEntry.h: coding style. + * gdcmPython/__init__.py: environement variable GDCM_DATA_PATH is + now taken into account. + * gdcmPython/gdcm.i: adaptation to the new internal representation + of gdcm (exit gdcmParser, hello gdcmDocument). + * gdcmPython/testSuite.py: quick and dirty fix for loading vtkgdcmPython + on posix. + * gdcmPython/demo/PrintHeader.py: doesn't use the gdcmDocument::Print() + anymore, but instead prints the loaded Python dictionary. + * .... alas, the python testSuite is still broken. + +2004-05-18 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * gdcmPython/gdcm.i : remove useless lines concerning the gdcmGlobal + gdcmGlob + * gdcmPython/setup.py : replace the use of cvar.gdcmGlob to gdcmGlobal + * src/gdcmUtil.h : export methods + +2004-05-16 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * Some more cleanup/enhancement in gdcmPython/CMakeLists.txt getting close + to right behavior + * Initial addition of automatic python testing + * Initial addition of automatic image comparison + +2004-05-04 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmCommon.h, gdcmDicomDir.cxx, gdcmFile.cxx, gdcmHeaderHelper.h, + gdcmParser.cxx, gdcmParser.h : bug fix for the Microsoft .Net compilation + +2004-05-04 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmFile.cxx, gdcmHeader.cxx : bug fix for the msvc compilation + * Test/ShowDicom.cxx : bug fix for msvc compilation + * vtk/vtkgdcmViewer.cxx : bug fix for msvc compilation + +2004-05-04 Jean-Pierre Roux + * ADD Taking into account the 'Dicom Sequences' leads up to introduce + new concepts (and new classes) : + a 'gdcmDocument' is composed of a set of Doc Entries, that are + - elementary gdcmDocEntries (former gdcmHeaderEntries) + - Sequence Doc Entries (gdcmSeqEntries) + a Sequence is composed of Items. + Each item is a set of Doc Entries (this is recursive) + The non uniqueness of the 'Dicom tag' is due to this recursivity + (never taken into account) + Our unability to add a new 'entry' in the header + at the proper location (neither in the H-Table (map or multimap), + nor in the Chained List is also due to this recursivity. + Don't try, right now, to use/modify/compile these new sources : + nothing is finished. + We just commit all the stuff, 'as is', in order not to loose it. + +2004-05-04 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * vtk/vtkGdcmReader.cxx : bug fix in the setting of file name + +2004-05-03 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * vtk/vtkGdcmReader.cxx : bug fix when loading a list of files using the + file prefix (SetFilePrefix) + +2004-05-02 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * Add a new test: ShowDicom, for now this is just the c++ version of + checkRead.sh, later it will be able to compare the image read against a + baseline. + * Replace the DEBUG on the stack with a global entry in cmake interface: + GDCM_DEBUG, so you can turn verbosity ON/OFF for debug statement. + +2004-04-30 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * Add an example subdir, with a real example on how to read + write a + dicom image + +2004-04-30 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * Doc/gdcmUML.xmi added raw UML class view (umbrello format) + * Doc/CMakeLists.txt: the main page is now properly differentiated + between the developper and user version. + * Doc/doxygen.config.in: dropped search related obsolete flags + * src/gdcmParser.h, gdcmHeader.h: doxygenation + +2004-04-29 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * DEVELOPPER: added some helpfull comments for compile/test/install + when using cmake. + +2004-04-29 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * ENH: 1. Remove remp solution of gdcmTests.cxx+ gdcmMain directly in + src directory, now generated in the build dir. + 2. Tests as mentionned smarter + 3. Some clean up + 4. Add a new method in gdcmDict that return the PubDict by name + this is interesting for 3rd party lib like ITK, + where we could set the institution name / patient name... + + * ENH: 1. Now the test suite is working for real + 2. All binaries are now output in the gdcm-bin directory + (this was not true before) + +2004-04-28 Jean-Pierre Roux + * ENH add the provisional gdcmHeader::SQDepthLevel to allow + SeQuence indented printing of Dicom Header. + * ENH merge methods gdcmParser::Parse and gdcmParser::LoadHeaderEntries + into the single gdcmParser::LoadHeaderEntries for efficiency purpose. + Computation of SQDepthLevel is now part of gdcmHeader constructor + * ENH add self defined param 'new' to PrintHeader to 'show' the SeQuence + tree-like structure of a Dicom Header. + * FIX Test code cleaning + +2004-04-25 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * ENH: Adding automatic testing + 1. Need a DartConfig.cmake to submit to public + 2. Add a test driver gdcmTest.cxx + 3. gdcmTestMain, an helper for the main test driver gdcmTest + 4. Files in Test don't have a main anymore, this becomes interesting + when we add more and more tests, thus dsw don't have to load + too many projects + * ENH: Adding a GDCM_DATA_ROOT for testing + * ENH: Remove redundancie about GDCM_DICT stuff, now we only need to modify + one file instead of seven + some small cleanup + +2004-04-22 Jean-Pierre Roux + * ENH Minor changes to the Print() methods. + * ADD gdcmParser::PrintEntryNiceSQ() to allow SQ-indented + Header printing. Example given with : + > PrintHeader fileName 2 new + (SQ based tree-like structure still to be done for the Header ...) + +2004-04-22 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * ENH: Some cosmetic clean up for compilation with -W -Wall -Werror + 1. I have added some unsigned where needed + 2. Some function parameter not used -> (void) + 3. In gdcmDicomDir.cxx, add GDCM_DICOMDIR_NONE case + 4. g++ don't like character '\' in comment + 5. #define jpeg_create_decompress jCreaDecompress + this really need to be fixed + 6. virtualize destructor of gdcmObject ... leakage + 7. sscanf(g->first.c_str(),"%x",&gr_bid); + this also really need to be fixed + 8. gdcm/src/jpeg/libijg8/CMakeLists.txt, + remove compression file + (as we only do decompression, right ?) + * ENH: Change malloc/calloc/free with c++ equivalent + +2004-04-21 Jean-Pierre Roux + * FIX gdcmHeaderHelper::GetXSpacing + when a single value is found (bug ?), xpacing is now + defaulted to yspacing + +2004-04-19 Jean-Pierre Roux + * ADD gdcmData/Wrist.pap (PAPYRUS 3.0 -single frame-) for checking purpose + * ENH add parameters : + bool exception_on_error = false, + bool enable_sequences = false, + bool ignore_shadow = false + to the gdcmFile constructors to be full gdcmParser compliant + * FIX vtk/vtkGdcmReader.cxx now uses enable_sequences = true in gdcmFile + to allow reading of PAPYRUS 3.0 files + +2004-04-06 Jean-Pierre Roux + * ADD gdcmData/E00001S03I0015.dcm for SQ checking purpose + +2004-04-02 Jean-Pierre Roux + * ADD : Test/checksequence.sh, for a general recap on SQ pb + * FIX : gdcmParser::WriteEntryTagVRLength emprovement of special treatement + for Philips spurious Tag fffe|0000 while rewritting Dicom files + +2004-03-30 Jean-Pierre Roux + * FIX gdcmParser::ReplaceOrCreateByNumber shouldn't seg fault any more + for ACR file, written out as DICOM files (hope so...) + +2004-03-30 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * src/gdcmParser.[cxx|h] and gdcmHeader.[cxx.h]: gdcmHeader::Write split + in WriteEntryTagVRLength and WriteEntryValue. Those methods were + moved to base class gdcmParser and only the specialisation is kept + in gdcmHeader. + * src/gdcmParser.[cxx|h]: ReplaceOrCreateByNumber(char*, guint16, guint16) + trashed out (because ReplaceOrCreateByNumber(string, guint16, guint16) + already does the job. + * src/gdcmDicomDir.[cxx|h]: WriteDicomDirEntries renamed to WriteEntries + (to be consistent with gdcmParser::WriteEntries). + +2004-03-30 Benoit Regrain + * vtk/vtkGdcmReader.[h|cxx] : fix the read of 3 gdcmHeader when making an + upate of the object's instance. It's passed to 2 in the unfavorable + case : one in the ExecuteInformation, one in the ExecuteData + +2004-03-29 Jean-Pierre Roux + * ENH : Check on file type to be written moved + from gdcmParser::WriteEntry to gdcmParser::WriteEntries + * FIX : gdcmObject::ResetBoundaries now stops properly + when end-of-list is reached + : gdcmVersion modified (as Benoit Regrain asked) + +2004-03-29 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * src/gdcmParser.cxx: removal of all TAB character. Indentation fixed. + * src/gdcmUtil.cxx: added forgotten iostream include. + * src/gdcmCommon.h: FileType enum entry DICOMDIR removed (since + equivalent to ExplicitVR in existing code). + +2004-03-27 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * src/gdcmUtil.[cxx|h] split in two. Additional file gdcmGlobal.[cxx|h] + now contains all the gdcmGlobal related code. + * minor coding style and doxygenation changes. + +2004-03-26 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * src/gdcmUtil.[cxx|h] split in two. Additional file gdcmDebug.[cxx|h] + now contains all the Debug related code. + * minor clean-up of includes in src/*.cxx + * src/gdcmUtil.[cxx|h] _cleanString C style function (replaced with + CreateCleanString) removed. + * src/gdcmUtil.[cxx|h] _CreateCleanString renamed to CreateCleanString + * Doc/DoxyMainPageUser.txt added. + * Doc/Doc/DoxyfileUsers updated to version 1.3.4 of Doxygen. + * src/gdcmCommon.h now defines getcwd for Win32 (moved away from + src/gdcmDirList.cxx) + +2004-03-24 Jean-Pierre Roux + * FIX a lot of little surface modifications to be doxygen 1.3.6 compliant + +2004-03-23 Jean-Pierre Roux + * FIX Now gdcmFile::SwapZone doesn't seg faults any longer for + big endian made volumes + * ENH Now gdcmParser constructor and destructor are protected to forbid + end user to instanciate class gdcmParser + (only gdcmHeader and gdcmDicomDir are meaningfull) + +2004-03-22 Benoit Regrain + * FIX : src/gdcmDicomDir.cxx : make windows compilable + * FIX : gdcmPython/gdcm.i : change gdcmStudy to gdcmDicomDirStudy and + gdcmSerie to gdcmDicomDirSerie + +2004-03-19 Jean-Pierre Roux + * ENH Now the tree-like structure describing a DICOMDIR comming from + an already existing DICOMDIR file is consistent with + the home-made tree-like structure build ex-nihilo + or build from the files held (recursively) in a Directory + functions gdcmDicomDir::CheckBoundaries() + gdcmObject::SetBoundaries() added + +2004-03-17 Jean-Pierre Roux + * REM (Eric Boix bug) : removal of meaningless + gdcmDicomDirImage::NewImage function. + * FIX now file names and directory name are written properly in the + DICOMDIR + * FIX now gdcmDicomDir constructor may be call without any trick + about the name + +2004-03-16 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * FIX (JPR bug) : src/gdcmDicomDirImage.cxx added missing definition + of gdcmDicomDirImage::NewImage as empty function. + +2004-02-28 Jean-Pierre Roux + * ENH add gdcmDicomDir:NewPatient + add gdcmDicomDirPatient:NewStudy + add gdcmDicomDirStudy:NewSerie + add gdcmDicomDirSerie:NewImage + to allow making gdcDicomDir object. + * ADD PrintDicomDir executable that uses gdcmDicomDir tree-like structure + (as opposite to the gdcmHeader chained list) + +2004-02-11 Benoit Regrain + * FIX : memory leaks and the set of ArgDelete methods in gdcmDicomDir + when using from python + +2004-02-10 Benoit Regrain + * FIX : bug fix in the gdcmDirList for the recursivity in directories + * FIX : in gdcmDicomDir when the directory is empty + * ENH : add callback and methods to get the progression of dicomDir + directory parsing + +2004-02-06 Jean-Pierre Roux + * ENH : - now gdcmDicomDir::CreateDicomDir() returns also the meta elements + - GDCM_META added to gdcmDicomDirType + - class gdcmMeta created + * ENH : - A brief summary is now displayed at the beginning of + 'testDicomDir' to help disaster magnitude estimation + * REM : Now useless Test/explDICOMDIR.cxx + +2004-02-05 Benoit Regrain + * ENH : add methods in gdcmObject to get the hash table or the list of + header entries + * FIX : wrapping python for ListPatient, ListStudy, ListSerie, ListImage + * FIX : wrapping python for TagHeaderEntryHT + +2004-02-04 Benoit Regrain + * FIX : even length for some strings when writting the dicom dir + * FIX : sort the images in the dicom dir + * FIX : Bug fix for python use of dicom dir + * ADD : a python demo + +2004-02-04 Jean-Pierre Roux + * FIX : Final solution (?) for icone embedded images + * FIX : dicomVR.dic Overlay group is not *only* 6000, but 60xxx + (see http://medical.nema.org/dicom/2003/03_06PU.PDF) + add groups 6002, 6004, 6006, to allow 'clean' parsing of + gdcmData/gdcm-MR-SIEMENS-16.acr1 + * ENH add gdcmData/checkWriteExplicit.sh gdcmData/checkWriteImplicit.sh + to make full checking easier + +2004-02-04 Benoit Regrain + * FIX : WriteEntries : coding style & logic in parameters + * FIX : Set the elements to create the DicomDir in a dictionary file + +2004-02-03 Benoit Regrain + * gdcmDirList : to parse a hard drive directory in recursive (or not) + * gdcmDicomDir : add the load of directory + * Bug fix and print add-on + +2004-02-03 Jean-Pierre Roux + * ENH gdcmParser : allows "DICM" files, with NO group '0002' + * FIX handling 'non string elements' unsecure area (LUT, overlays, etc) + * FIX Dicts/dicomV3.dic : Add a few missing 'group length' Elements + * FIX gdcmParser.cxx : 'group length' elements are now considered + as integers, even for shadow groups, when file is Implicit VR + +2004-02-02 Jean-Pierre Roux + * FIX : gdcmWrite : equal_range() for multimap doesn't return a 'second' + iterator on last + of the last synonym :-( + * FIX : gdcmWrite::WriteBase : method stops if Pixels not yet Read (except + for DICOMDIR ;-) + * ENH gdcmData/checkWrite.sh :modif for full check of Explicit VR writting + * FIX taking into account the possible 7fe0,0010 multiplicity + * FIX add GRPixel,NumPixel,countGrPixel (gdcmParser protected members) + to allow removal of references to 7fe0,0010, to deal with + ACR-NEMA images, when 0028,0200 is meaningfull + +2004-01-31 Jean-Pierre Roux + * FIX gdcmParser::WriteEntries : when a VR is tagged as 'Unknown' + no longer writes 'Un' on disk + * FIX SQ elements with actual length are now dealt with corectly + * FIX gdcmFile::WriteBase make the difference, for color images, between + the length (for Palette expanded images) + and Raw Length (non expanded image + Palette) + * FIX Dicts/dicomV3.dic : removal of 'CTX' (context dependant) VR + (that broke Write). Replaced by UL. + Aware user will reload the field if he + thinks it's necesssary + +2004-01-30 Jean-Pierre Roux + * gdcmParser::CheckSwap() now defaults the filetype to ACR + when 'dirty Acr' is found, to be compliant with the new + IsReadable() methods. + + * gdcmHeaderHelper :add Pixel Type 'FD', for dealing with 'double' images. + (no DOUBLE images in kosher DICOM, + but so usefull for people that miss them ;-) + + * add Test/testDicomDir.cxx, Test/makeDicomDir.cxx , Test/explDICOMDIR.cxx + DICOMDIR related utilities (not checked as Windoze compliant) + +2004-01-28 Jean-Pierre Roux + * upgrade GdcmHeaderEntry Print Method for DICOMDIR + +2004-01-27 Jean-Pierre Roux + * gdcmParser constructor has a new boolean param,'ignore_shadow', + to allow skipping the shadow elements, to save memory space. + The TRUE value for this param has to be used + with a FALSE value for the 'enable_sequence' param. + ('public elements' may be embedded in 'shadow Sequences') + * gdcmHeader methods now deal with 'embedded icones images' in the header + (even when an 'icone image sequence' is announced by the + element (0x0088,0x0200), but there is NO icone at all ... + + * gdcmHeader sometimes Image Location value doesn't follow + the supposed processor endianity (see gdcmData/cr172241.dcm). + Fixed + + * gdcmHeader add the method + IterHT GetHeaderEntrySameNumber(grPixel,numPixel); + to get *all* the Header Entries with the same tag. + GetHeaderEntrySameName is probabely *useless* + (no meaning : Name is *not* an identifier within the Dictionary) + +2004-01-26 Benoit Regrain + * Bug fix in the print of hexadecimal representations. Remove long fields + in the print and add a third level of print to print them + +2004-01-23 Benoit Regrain + * Bug fix on field having a VR = 'UI'. Assume that is a string field + * Bug fix on test suite after remove the strip made on not string fields + * Split the IsReadable method between gdcmParser which test that the file + is dicom and gdcmHeader which test that it's an image file + +2004-01-22 Benoit Regrain + * DicomDir : clean code, add methods, set variables in protected or private + * gdcmUtil : bug fix for the clean string method + +2004-01-19 Benoit Regrain + * Add the use of shadow dictionaries + * bug fix and coding style + +2004-01-19 Benoit Regrain + * src/gdcmFile.cxx : bug fix concerning the close of file + * src/gdcmParser.[h|cxx] : remove obvious Pub informations + * Add the update of header entries using the shadow library + +2004-01-19 Benoit Regrain + * removal of file gdcmHeader2.cxx + * split class gdcmHeader into gdcmParser and gdcmHeader, with gdcmHeader + inheriting from gdcmParser. This split is to prepare the integration + of dicom dir parsing + * bug fix under python + +2004-01-16 Jean-Pierre Roux + * REM removal of class gdcmHeaderEntrySet + * REM removal of files gdcmHeaderEntrySet.cxx, gdcmHeaderEntrySet.h + * ADD add file gdcmHeader2.cxx + * ADD add method gdcmHeader::SetPrintLevel (for PrintHeader) + +2004-01-15 Benoit Regrain + * src/gdcmDicSet.[h|cxx] : add virtual entries to have a reference of + entries created while parsing the header. Thus, they will be destroyed + when the gdcmDictSet will be destroyed + * src/gdcmHeader.cxx, gdcmHeaderEntrySet.cxx : uses virtual entries of + gdcmDictSet + +2004-01-15 Benoit Regrain + * vtk/vtkGdcmReader.cxx : bug fix : before, with python only, the program + made a fatal error because of the memory release at the end of program. + The problem was in vtkGdcmReader::ExecuteData where we were allocate + some memory and vtk seems to have some problems with that. + * src/gdcmHeaderEntrySet.cxx : bug fix for std lib and cout + +2004-01-14 Benoit Regrain + * src/gdcmHeaderEntry.[h|cxx] : gdcmElValue -> gdcmHeaderEntry + * src/gdcmHeaderEntrySet.[h|cxx] : gdcmElValSet -> gdcmHeaderEntrySet + * src/*.[h|cxx] : make changes due to class name changes + * gdcmPython/demo/*.py : bug fix due to method names + +2004-01-13 Benoit Regrain + * src/*.[h|cxx] : coding style + * vtk/*.[h|cxx] : coding style + +2004-01-13 Benoit Regrain + * gdcmPython/testSuite.py : test the readable flag of file for tests + * src/gdcmDict.cxx, gdcmElValSet.cxx : bug fix under windows for prints. + It's lied to the stl compilation by MSVC (windows, always windows...) + * src/gdcmIdo.h, gdcmHeaderIdo.cxx : remove the Ido unused files + +2004-01-12 Benoit Regrain + * src/*.h : add comments + * src/gdcmDictSet.h : set the method BuildDictPath in public + * src/gdcmTS.cxx, gdcmVR.cxx : use now a dictionary file other than to be + directly setted in the source code + * Dicts/dicomTS.dic, dicomVR.dic : 2 new dictionary files loaded by + gdcmTS and gdcmVR + +2004-01-09 Benoit Regrain + * gdcmPython/gdcmVersion.py : add a gdcmVERSION variable information + * setup.py : use a reference to gdcmVERSION + +2004-01-07 Benoit Regrain + * Modification to compile with the distutils. + * Bug fix in code + +2003-12-10 Benoit Regrain + * gdcmHeader is now aggregating gdcmFile, and not derived into. Thus, we + can use a gdcmHeaderHelper to load data + * gdcmPython/testSuite.py : make the testSuite compliant with modifications + made in the source code + +2003-12-10 Benoit Regrain + * Update Windows projects and .cvsignore files + +2003-11-12 Jean-Pierre Roux + * ENH gdcmHeader constructor has one more parameter (default value : false) + that allows the user to 'go inside' the SeQuences only + if he wants to. + gdcmElValSet:Print takes it into account + +2003-11-12 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * ENH: Update gdcmPython/CMakeLists + * FIX: (gdcmHeaderHelper) GetRescale and GetSlope + * FIX: (gdcmElValSet) char 'tag' was overiding private members (VC++) + +2003-11-10 Jean-Pierre Roux + * FIX : gdcmHeader::LoadElements is now based + on the ListTag listElem member, + not longer on the TagElValueHT tagHt member + * ENH : PrintPubElVal shows (temporarily) both results, + with the tagHt member and the listElem member. + (it's easier to 'see' the problems when using Printheader) + + * FIX : old private member LgrElem is now splitted into + ReadLength : Length actually found on disk (updated only + if bug fixing is necessary), for internal + use only + UsableLength : Updated by FixFoundLength, to fix a bug + or to allow Parser going on. + Will allow to re-write a kosher header when a SeQuence + with a length (not 0000) is found + Warning : gdcmFile::Write still uses the TagHt (not ListElem) + because gdcmElValSet::Add does not update ListElem + (to be written) + +2003-11-07 Jean-Pierre Roux + * FIX misstyping in Transfert Syntax name table + * ENH gdcmHeader::FixFoundLength now allow to 'go inside' tge SeQuences + when they have an actual length (not 0000 nor FFFFF) + (Nobody should care of it, but DICOMDIR explorers) + +2003-11-06 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * ENH: vtkgdcmViewer now works with LUT dicom (OT-PAL-face ...) + +2003-11-05 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * ENH: vtkGdcmReader now supports LUT ! + (vtkgdcmViewer for now is not able to use them though) + +2003-11-05 Jean-Pierre Roux + * in testSuite.py : new files names for checking the package + * FIX : Forgot to commit gdcmFile::GetImageDataSizeRaw(); + that returns the pixel area size to the *aware* (vtk) user + that DOESN'T want to turn the PALETTE COLOR image into an RGB image + +2003-11-05 Benoit Regrain + * in testSuite.py : Modify the rules for checking the paths + : Explicit error messages + * in __init__.py : Related modif + +2003-11-03 Jean-Pierre Roux + * add gdcmHeaderHelper::GetNumberOfScalarComponentsRaw() + to be used by aware (vtk) users that want to manage + LUT (and no to turn the PALETTE image into an RGB pixels one) + * GetPixelType now returns 8U for 24 Bits images + (vtkGdcmReader compliant) + +2003-10-31 Jean-Pierre Roux + * Removal of *all* gdcmData images and add them again + in order to loose the 'history' of un-anonymised images + +2003-10-31 Jean-Pierre Roux + * RMV : removal of useless jBitsInJsample.h + for both 8 and 12 Bits JPEG Lossy Libraries + +2003-10-31 Jean-Pierre Roux + * ENH : Add the functions gdcmFile::GetImageDataRaw + gdcmFile::GetImageDataIntoVectorRaw + that act as GetImageData and GetImageDataIntoVector + except the making of an RGB Plane from Gray Plane + LUT + Intended to aware (vtk) users who know how to manage + such an image : + After gdcmHeader : + GetLUTRGBA return a R,G,B,A LUT if any + lgrTotaleRaw gives the 'Raw' length + GetImageDataRaw returns the gray Plane + * FIX : no more dirty trick for 'Segmented xxx Palette Color Lookup' images + (They stay Grey, just like with other Dicom viewers :-( + +2003-10-30 Jean-Pierre Roux + * FIX : a VC++ intended syntax modif broke the 12/12 Bytes expanding + +2003-10-29 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * ENH: Can be used like this '$vtkgdcmViewer *.dcm' with *.dcm + being coherents dicom files. + +2003-10-29 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * FIX: DOH ! Forgot about windo$e users, they couldn't read lossless jpeg, + from medcon lib ! + * ENH: Turn it into DOS file type to match libgdcmijpeg8.dsp file type + * ENH: Two steps is necessary to please VC++ compiler... + * FIX: DOH ! libgdcmijpg8 -> libgdcmljpeg + * ENH: Add include dir to medcon lib + * FIX: only one function is being exported for now ! + You should use GLOBAL(return type) see ljpg/jpeg.h for more info + +2003-10-29 Jean-Pierre Roux + * adding gdcmHeader::GetLUTRGBA + returns a 4 * 256 Bytes Reg/Green/Blue/Alpha vtk compliant LUT + --> Mathieu, the modif u're waiting for is not yet committed + * removal of now useless GetLUTRed,GetLUTGreen,GetLUTBlue,GetLUTRGB + +2003-10-27 Jean-Pierre Roux + * adding some xmedcon breaker files (courtesy of Lo�c Boussel) + 00191113.dcm DermaColorLossLess.dcm + MxTwinLossLess.dcm RadBWLossLess.dcm + * ENH: For version prior to vtkImageViewer2 -r 1.19 + * FIX: avoid pb with xmedcon-breaker CT McTwin Elscint images + +2003-10-27 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * Removal of ido stuff in CMakeLists.txt + +2003-10-24 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * ENH: vtkGdcmReader.cxx can now read multiframe dicom + * FIX: remove a call to ->Modified ... see comments + * FIX: vtkgdcmViewer.cxx was writting ASCII file...this is so slooooow ! + +2003-10-23 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * FIX: Problem with path for libvtkgdcmPython + * ENH: Try adding a search script for python site-package + * RMV: Remove some file from medcon lib that are not necessary + * FIX: gdcm/Makefile.am fix for generating ljpg medcon + * ENH: CMakeLists.txt now generate 'pygdcm.so' instead of 'libpygdcm.so' + * FIX: More pragma disable fro VC++, + I don't think I break something as it is also disable in VTK/ITK. + But it fasten debug compilation time. + +2003-10-23 Jean-Pierre Roux + * gdcm now deals with 16 Bits Run Length Encoded images + (they are compressed as 2 planes images, + one for the high Bytes, the other for low Bytes) + +2003-10-22 Jean-Pierre Roux + * Now CheckRead takes into account : + - the bugged 'Leonardo' Siemens images + - the XA images, sent thru the burning VPRO station + * add I9000001.dcm, a GE dlx XA image, thru the VEPRO burning station + (breaks DicomWorks) + +2003-10-22 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * FIX: When copying a Makefile.am to CMakeLists.txt + one should remove the '\' + +2003-10-22 Jean-Pierre Roux + * in gdcmData adding a bugged 'Leonardo' Siemens image + (wrong lengths in header) + OK with gdcm, KO with the other viewers :-) + * add a GE dlx XA image, thru the VEPRO burning station + (breaks DicomWorks) + +2003-10-21 Jean-Pierre Roux + * in gdcmData add the checkvtkgdcmViewer.sh shell script + for a brutal checking of vtkgdcmViewer compliance + +2003-10-21 Jean-Pierre Roux + * add the files for 'xmedcon' Jpeg Lossless library + * call of 'xmedcom' Jpeg Lossles libray (instead of the old LibIDO one) + +2003-10-21 Jean-Pierre Roux + * 'Compacted Files' (12 Bits Allocate, 12 Bits Stored) are now dealt with + +2003-10-21 Jean-Pierre Roux + * garbage Siemens 'Leonardo' images dealt with + (the patch is easy to remove) + * cosmetic changes to avoid warnings + +2003-10-20 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * ENH: vtkgdcmViewer now autoscale color/window level on start-up, + no need to press 'r' now. + +2003-10-20 Jean-Pierre Roux + * upgrade of checkRead.sh checkWrite.sh according + to new Jpeg Lossless decompressor + * add US.3405.1.dcm, a genuine RGB medical file ... + * add gdcm-ACR-LibIDO.acr, unnormalized Rectangular LibIDO format image + * add CLIP0001-Sequoia-U11.dcm, US 'Clip', from SEQUOIA machine, + UNIT 11, Hop Cardio +2003-10-15 Jean-Pierre Roux + * general anonymisation in gdcmData + * adding the 'color files' from + http://www.leadtools.com/SDK/Medical/DICOM/ltdc19.htm + * adding some well knowed bugged-header images + * adding checkRead.sk, checkReadColor.sh, checkWrite.sh, + waiting for their inclusion in Python testsuite + +2003-10-15 Jean-Pierre Roux + * gdcmHeader::gdcmHeader(const char *InFilename, bool exception_on_error) + no longer seg faults when file is not found + +2003-10-14 Jean-Pierre Roux + * Emprovement of reading for Dicom encapsulated Jpeg LossLess + MultiFrame images + +2003-10-14 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * TODO: *.in file to genereate a UseGDCM later + +2003-10-14 Jean-Pierre Roux + * Some supposed-to-be Dicom Images have no preamble. + OpenFile takes it into account + * Jpeg LossLess 24 Bits images doesn't break any longer gdcm + * Missing elements added in dicomV3.dic + (just to be affraid : have a look at + ftp://medical.nema.org/medical/dicom/2003/01v03dif/01v03_06.pdf + and do it again next year ;-> + +2003-10-13 Jean-Pierre Roux + * According to PS 3.3-2003 C.11.1.1.2 p 619, when each pixel of + a PALETTE COLOR is stored on 2 Bytes, theese 2 Bytes must be equal. + But there are NOT. It's fixed ! + +2003-10-13 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * FIX: "jpeglib.h" was not found on VC++ + * FIX: vtkgdcm was not being installed + +2003-10-10 Jean-Pierre Roux + * ENH : OpenFile closes the file if it *really* doesn't look like + an ACR-NEMA / DICOM one. + * FIX : testWrite no longer writes an empty file if the source file + is not gdcm Readable + * ENH : One more JPEG LossLess type "JPEG Baseline (Process 14)" + is now decoded. + +2003-10-10 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * FIX: CMake generate now documentation + * ENH: out of source doc build ! + * ENH: Generate both user and dev documentation + * ENH: Should work on windows too + * ENH: Only one doxygen config.in file is needed + * FIX: make install should be ok now on Unix plateform + * FIX: PATH to dictionary was wrong (missing /) + * ENH: OpenFile, return true if the file looks like an ACR or DICOM file + +2003-10-09 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * vtkGdcmReader is now able to read rgb dicom file. + * src/gdcmHeaderHelper : GetNumberOfScalarComponents() + * added a gdcmViewer to vtk test, use mouse to control + window level & window width + +2003-10-09 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * CMake-ification of gdcm, we have now two build system + * FIX: on cygwin Wsock32 doesn't exist + * FIX: force jpeg dir to the local one (gdcm/src/jpeg) + +2003-10-06 Emanuel Ollart + * FIX : compilation process wad broken. + Changed gdcmViewer_sources to vtkgdcmViewer_sources + +2003-10-06 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * change gdcmViewer -> vtkgdcmViewer + * change GetXSpacing and GetYSpacing "%f\\%" is parsed backward + +2003-10-06 Jean-Pierre Roux + * FIX :A few nasty patches to allow the reading of a lot of nasty images + ( e.g : well known GE images with a wrong elem length, + : Philips MRI Images with a wrong Huffman table) + * still to be done : allow the reading of bugged LEONARDO Siemens images + +2003-10-03 Jean-Pierre Roux + * Odd length strings are padded with '\0' (not with spaces, + to remain compliant with already defined strings, + like Transfert Syntax UID and others) + +2003-10-03 Jean-Pierre Roux + * ENH :gdcmHeaderHelper::GetNumberOfScalarComponents() added, + to allow displaying RGB images (not only by affim ;-) + +2003-10-03 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * vtkGdcmReader is now able to read rgb dicom file. + * src/gdcmHeaderHelper : GetNumberOfScalarComponents() + +2003-10-03 Jean-Pierre Roux + * A few nasty patches to allow the reading of a lot of nasty images + ( e.g : well known GE images with a wrong elem length, + : Philips MRI Images with a wrong Huffman table) + * still to be done : allow the reading of bugged LEONARDO Siemens images + +2003-10-03 Jean-Pierre Roux + * One more JPEG LossLess type "JPEG Baseline (Process 14)" is now decoded. + +2003-10-03 Jean-Pierre Roux + * gdcmHeaderHelper::GetNumberOfScalarComponents() added, + to allow displaying RGB images (not only by affim ;-) + +2003-10-03 Jean-Pierre Roux + * gdcmFile::GetImageDataIntoVector now + - deals with MultiFrames MultiFragments Run Length Encoded files + - deals with YcBcR (YBR_FULL) files + - deals with YBR_YBR_FULL_422 files (they work as RBG files ?!?) + WARNING : nothing was checked for YBR_PARTIAL_422, YBR_ICT, + YBR_RCT files. + (no sample found :-( + +2003-10-02 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * src/*.cxx removed pragma thingies to src/gdcmCommon.h + Two reasons: - clear things + - third parties acces gdcm through header files, so won't + suffer anymore VC++ complains + +2003-09-30 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * add argv[1] in testvtkGdcmReader.cxx + * removed leaks + +2003-09-24 Jean-Pierre Roux + * The lines are now eigthy characters long for + gdcmHeader.cxx gdcmHeaderHelper.cxx gdcmParse.cxx + +2003-09-22 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmUtil.[cxx|h] : change the _CreateCleanString return value from + char* to std::string. Thus, the use of strdup becomes useless. (see + previous commis of Malaterre) + * src/gdcmElValSet.cxx : reuse commented call to _CreateCleanString like + before the last Malaterre's commit. + +2003-09-19 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * This commit should fix the Debug building under VC++, the problem + was mainly a mixture of debug and release lib being loaded at startup. + * I also remove a depency to a specific C function: strdup. Because I had + to force the link to msvcrtd (whereas strdup is in libc). + +2003-09-16 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * "gdcm::Unfound" string changed to a constant variable (GDCM_UNFOUND) + located in the gdcmCommon.h file. All use of reference of tha has been + changed to now use the variable GDCM_UNFOUND. + +2003-09-16 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> with JPR + * Cosmetic changes: + - gdcmPython/testSuite.py adapted to the JPR updated Dicts/dicomV3.dic + Dicom dictionary. The test suite can now be run again. Note: + I'm note very happy with the " (RET)" changes. I believe this + RETAINED comment should be dropped when parsing the dictionary. + - PACKAGER corrected + - DEVELOPPER added. + - AUTHORS updated and now in alphabetical order + * Makefile.am now exports gdcm.dsw for Windoze users. + +2003-09-11 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * cygwin complains about missing std:: in subdir Test/ + +2003-09-10 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * remove some methods that are now in gdcmHeaderHelper + +2003-09-10 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * vtkGdcmReader set spacing and origin correctly + +2003-09-09 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * Fix a few delete/delete[] mismatch + +2003-09-08 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * src/gdcmHeaderHelper.[h cxx]: added new class that provide an + interpretation to data given by gdcmHeader. For instance there are + heuristics to get informations (look at different places). + * it also include a specific class: gdcmSerieHeaderHelper devoted to + sorting DICOM images based on different strategies. + * modified Makefiles accordingly. + +2003-09-05 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * src/*.cxx : added pragma disable 4786/4251 to get rid of ~4300 warning + when building in debug mode + * vtk/win32/vtkgdcm.dsp : change /MT -> /MD and /MTd -> /MDd to match + src/win32/gdcmdll.dsp + * vtk/win32/vtkgdcm.dsp : added /nodefaultlib "mscvrt" for debug mode + +2003-08-29 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * Corrected a leak in vtkGdcmREader.cxx, the pSource was find thanks + to valgrind. + +2003-07-29 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * src/win32/libgdcmjpeg12.dsp was not dos format + * src/win32/libgdcmjpeg12.dsp : + libgdcmijpeg12_EXPORTS -> LIBGDCMIJPEG12_EXPORTS + * src/win32/gdcmdll.dsp: + /I "..\jpeg\libijg12" + +2003-07-29 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmHeader.h : add std:: prefix for stl elements... like others in + the file + * src/gdcmFile.cxx : bug fix in affectation type + * src/jpeg/libijpeg12/jmorecfg12.h : export for windows modified... like + in src/jpeg/libijpeg8/jmorecfg8.h (JPR : copy/paste exists !!!) + * Modifs of MVSC projects to compile them. Not concerning 2 identic + symbols... future problem ? + +2003-07-29 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * src/win32/libgdcmijpeg12.dsp was missing + * modified gdcm.dsw accordingly + +2003-07-28 Mathieu Malaterre <Mathieu.Malaterre@creatis.insa-lyon.fr> + * src/gdcmHeader.cxx : misplaced return 0.; for ACR/NEMA + +2003-07-24 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/jpeg/libijg12/.cvsignore, jconfig.* : ommited files while last + commit of JPR (before his hollidays to facilitate our work). + * setup.py : bug fix in code. Modifications made while the last commit + of JPR. The code hasn't been tested before the commit... it's so + useless to make that (for best programmer that is JPR) !!! + +2003-07-08 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * tagged the current version as Version0_3 (i.e. version 0.3) + +2003-07-08 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * vtk/testvtkGdcmReader.cxx : remove a symbol that is unused + * src/jpeg/libijg8/jmorecfg.h : adding export symbol for windows + * *.dsp : modifications to use new libgdcmijpeg8 library + * setup.py : bug fix on VTKPATH variable + * PACKAGER : adding all concerning windows + +2003-07-07 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * src/gdcmElValSet.cxx, gdcmFile.cxx: JPR bug fix, removal of + garbage debug code. + * TODO, vtk/vtkGdcmReader.cxx: upcoming fixes comments. + * gdcmPython/testSuite.py: JPR bug fix, brutal erasement of + test suite reported error. + * PACKAGER file added (describes what a packager must do when + packaging a new release). + * MANIFEST.in, now declares jconfig.linux and jconfig.vc + * configure.in: upgraded version number to 0.3.0 + * fixing build of rpm (through rpm -ta): + - Doc/Makefile.am exports proper doxygen files + - src/jpeg/libijg8/Makefile.am exports the include files. + +2003-07-07 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * vtk/vtkGdcmReader.cxx : bug fix when loading only 1 file. + * src/gdcmHeader.h : formatting code + +2003-07-07 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * vtk/vtkGdcmReader.[cxx|h] : bug fix when loading only one file. + We were obtaining error message from vtk. Now, creation of file list + is made in an internal list to prevent this problem. + Bug fix when output is empty. + Bug fix in update of progress value. Previous commit for this was a bad + correction. + * vtk/vtkGdcmReader.h : adding comments for InternalFileNaleList variable + +2003-07-04 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmHeader.h : added method to get the file name + * vtk/vtkGdcmReader.[cxx|h] : bug fix concerning loading of bad dicom + files. Added method to remove all files on the input + Added FIXME comment concerning the bad parsing of header made by + ExecuteInformation method (in ExecuteData method) + +2003-07-03 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * vtk/Makefile.am: vtkGdcmReader.h should now be cleany installed + when using make instal. + * src/gdcmFile.cxx : bug fix under Window after JPR commit + RQ : the JPR doesn't appear in the ChangeLog... normal for him + +2003-07-03 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * setup.py : adding include dir of jpeg lib to compile all sources + * */Win32/*.dsp : JPR fix for windows compilation + +2003-07-02 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/jpeg/libijg8/jconfig.* : JPR bug fix : now compile on both + linux and WINDOWS ! + * src/gdcmJpeg.cxx : JPR bug fix : erroneous include + * src/win32/gdcmdll.dsp : JPR fix for windows compilation + +2003-07-02 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * setup.py is again effective on un*x (takes into account the + addon of the jpeg library) + * Doc/DoxyDevelInstal.txt added (developper's raw documentation) + * Doc/Doxy* updated (includes above enhancements) + * INSTALL now points to web documentation + +2003-07-01 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * src/gdcmHeader.h doesn't make unnecessary reference to + gdcmUtil.h anymore. + * gdcmPython/Makefile.am now avoids calling the wrappers for the + clean target. + * src/gdcm*.[cxx|h] : + - to allow compilation with gcc 3.x + -- clean up of STL usage (added explicit usage of std::) + -- small fixes on exceptions. + Note: linking not tested ! + - clean of doxygen comments to avoid warnings at documentation + building stage. + * vtk/vtkGdcmReader.cxx: g++ warning message clean up (platform + dependent convertion). + +2003-06-20 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * Clean up of previous JPR garbage commit (not even commented in the + Changelog): + - Test/Makefile.am removed the reference to unexisting testTS.cxx + - moved all jpeg related files from src to src/jpeg/libijg8, with + addition/modification of Makefile.am and configure.in. + - the testSuite is still brain damage (not guilty). + +2003-06-02 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * WrapVTK.py : modifications to get correctly vtk source files to + compile + * vtk/vtkGdcmReader.cxx : modification for an already existing name + (FileName -> Filename) + +2003-06-11 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * vtk/vtkGdcmReader.[cxx/h]: + - UpdateProgress method should now be effective + - removed the limitation on having only images loaded (as opposed + to volumes), + - when building a stack of images/volume, a lesser number of + gdcmHeader and gdcmFile instances should be used (hopefully + accelerating things). + - when building a stack of images/volumes, files which are not + loadable (wrong path-filename, wrong permissions on existing file, + or file not parsable by gdcm) are replaced with a black image + in the stack (for the caller to notice the problem). + +2003-06-03 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * vtk/vtkGdcmReader.cxx: hopefully corrected Z extent. + +2003-06-02 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * vtk/vtkGdcmReader[cxx|h] : makes correct code to remove conflicts + between standard library (std) and vtk library (problems are found + under Windows... thanks Windows !) + +2003-05-30 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * vtk/vtkGdcmReader[cxx|h] should now be volume aware (read ready for + debug stage). + * gdcmPython/demo/vtkGdcmReader.py: commented lines for volume test + +2003-05-29 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * vtk/vtkGdcmReader[cxx|h] preparation addons for loading volumes. + +2003-05-28 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * When compiling with distutils (see setup.py) the C++ compiler is + called with different flags than the default ones (with automake). + In order to fix all those warning, I compiled gdcm with the command + make 'CXXFLAGS=-Wall -Wstrict-prototypes -D__STDC_LIMIT_MACROS' + and went for warning fixes: + - src/gdcmHeader.cxx, Test/dcm2acr.cxx, pourFindTaggs.cxx cleaned + up from unused variables. + - vtk/vtkGdcmReader.cxx: potential bug fix. + * src/gdcmHeader.h: Doxygen warning cleanup + +2003-05-27 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * gdcmPython/gdcm.i: + - typemaps correction to take into account the systematic replacement + of "using namespace std" with std:: prefix e.g. std::list, + std::string... (cf changes of 2003-05-21). + - gdcmGlob global variable of type gdcmGlobal (defined in + src/gdcmUtil.cxx and declared in gdcmPython/gdcm.i) is now + exported to Python a as cvar. + * gdcmPython/__init__.py now defines two functions GetPubDictTagNames() + and GetPubDictTagNamesByCategory() as a replacement for deprecated + gdcmDictSet.GetPubDictTagNames() and + gdcmDictSet.GetPubDictTagNamesByCategory() class functions (i.e. + C++ static methods). + * gdcmPython/demo/printGroupedPublicDict.py is operational again, + with the above changes. + +2003-05-22 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * setup.py, manifest.in : bug fix under linux + +2003-05-22 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * Modification of setup.py to compile vtk part too. Then, we have 2 + wrappers which must work with same distutils. For that, we have a + generic distutils in distusiltsWrapping.py ; with : + - build_extWrap class to wrap generically all extensions, + - ExtensionWrap base class for all wrapping extension that contains + a wrapper + - Wrapper interface which wrap sources + + In WrapSwig.py we have extension and wrapper for Swig + + In WrapVTK.py we have extension and wrapper for VTK + * MANIFEST.in : modifications to consider vtk directory and new python + files for compilation + +2003-05-21 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> with Benoit Regrain + * Added python wrappers of vtkGdcmReader vtk class (see the + source in vtk/vtkGdcmReader.cxx) : + - vtk/Makefile.am now builds a library + - gdcmPython/Makefile.am now builds vtkgdcmPython a second import + python library (as opposed to _gdcm.so wich are the python + wrappers of gdcm). vtkgdcmPython.so uses the vtk python wrappers + (vtkWrapPython and vtkWrapPythonInit utility) to build vtkgdcmPython + import library. + - configure.in has an additional flag --enable-vtk that needs + to be set to enable compilation of vtk related code, that is: + + vtk/vtkGdcmReader.so and + + vtk/testvtkGdcmReader C++ demo of vtk wrappers of gdcm) + + gdcmPython/vtkgdcmPython.so (see above) + - gdcmPython/demo/vtkGdcmDemo.py corrected (some images cannot + be read when compressed or when HighBit + 1 != BitsStored), + - gdcmPython/demo/vtkGdcmReader.py added. This demo illustrates + the usage of the python wrapper of vtkGdcmReader vtk class. + * vtk/vtkGdcmReader.cxx: bug fixed (thanks to Benoit Regrain). + * src/*.[h] all occurences of stl classes are now prefixed with + std::, and all occurences of "using namespace std;" where removed. + This is to avoid pollution of global namespace in included files. + Apparently vtk does not avoid this pitfall: when using both + gdcm and vtk (as in vtk/vtkGdcmReader.cxx) this ended up in a + collision of various stl members (principally cout...). + * gdcmPython/testSuite.py now cleanly removes temprory generated + file. + * gdcmPython/gdcm.i now declares a typemap for std::string (to + comply with above changes) + +2003-05-12 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> with JPR + * src/gdcmHeader>[h/cxx] added gdcmHeader::GetPixelSize() + * vtk/vtkGdcmReader.cxx now properly inports the image in the + vtk data structure (an image Flip was required). + * vtk/testvtkGdcmReader.cxx refers to gdcmData subdir instead of Data. + * cosmetic changes in documentation. + +2003-05-7 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> with JPR + * src/gdcmHeader.cxx: the constructor no longer exits when an + unexisting file is given as argument. + * The subdirectory Data (containing all the images used for the + test suite) is not part of this repository anymore. A new module + containing those images is now available at + :pserver:xxx@cvs.creatis.insa-lyon.fr:2402/cvs/public + with the name gdcmData. + All the python scripts (including the package initialisation file + gdcmPython/__init__.py) were adapated to take this change into + account (basically GDCM_DATA_PATH is now GDCM_TEST_DATA_PATH). + +2003-05-5 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> with JPR + * vtk subdir added. Contains vtkGdcmReader.[cxx|h] a vtk class + inherinting from vtkImageReader and testvtkGdcmReader.cxx a small + demo of the usage of this class. + Compilation of this vtk part is only done when using the --enable-vtk + at configure (or autogen.sh) stage. + +2003-04-16 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> with JPR + * More memory link related corrections and documentation fixes. + Notes on valgrind: + - maximum info is obtained with a command of the form: + valgrind --leak-check=yes --leak-resolution=high --num-callers=40 + --show-reachable=yes PrintHeader + - the remaining reachable blocks seem to come from the STL + allocation scheme through the usage of map and list. It looks + like this memory cannot be freed but it is not a memory leak + (in fact further invocation to the STL would recollect the + unused memory allthough it cannot explicitely be freed). + * gdcmPython/demo/vtkGdcmDemo.py added: this is a small demo + of displaying an image parsed with gdcm and displayed with VTK. + Note: some images don't seem to work e.g. + python vtkGdcmDemo.py ../../Data/US-RGB-8-esopecho.dcm + * src/gdcmHeader.x: dicom_vr and Dicts are not class members anymore. + Allthough this weakens the semantics, it is a ditch attempt to + make gdcm more thread friendly. + +2003-04-15 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> with JPR + * Memory link hunt (by using valgrind through the command + valgrind --show-reachable=yes --leak-check=yes PrintHeader). + - added src/gdcmVR.cxx gdcmVR.h that objectify the previous + gdcmHeader::_dicom_vr. + - gdcmHeader::InitVRDict transfered as gdcmVR::gdcmVR(). + - gdcmHeader::dicom_vr is now of type gdcmVR* as opposed to + VRHT*. + - gdcmGlobal global object contained class added (see src/gdcmUtil.x) + +2003-04-9 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> with JPR + * src/Makefile.am now exports all the necessary include files at + make install stage. + +2003-04-9 JPR + * UpdateGroupLength replaced by new one + +2003-04-7 JPR + * UpdateGroupLength re-written using H-Table + (named UpdateGroupLengthNew untill checks are over) + +2003-04-7 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> with JPR + * Data/im_00001 renamed to gdcm-MR-PHILIPS-16-Multi-Seq.dcm + * gdcmPython/testSuite.py now include a test of gdcmFile::Write. + * src: + - gdcmHeader::GetPubElValSet removed. + - gdcmElValSet::WriteDcm, WriteAcr, WriteExplVR, revamped to + UpdateGroupLength, WriteElements, Write. + - gdcmHeader::FileType moved to gdcmCommon.h. The enum FileType + doesn't contain TrueDicom anymore since ExplicitVR and ImplicitVR + carried the same semantics. + - src/gdcmHeaderIdo.cxx changed accordingly. + - gdcmFile::WriteBase now regroups all the codes from previous + versions of WriteDcm, WriteDcmImplVR, and WriteACR. + - enum FileType moved to gdcmCommon.h + * src/gdcmHeader.cxx AddDefault trashed + * gdcmGetXSize added + * getimageDataSize now calls gdcmGetXSize + * Test/*.cxx changed to agree with above changes + +2003-03-31 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * src/gdcmHeader.h: LoadElements() is not a public method anymore + (to avoid double call by end user). + * Test/*.cxx LoadElements() doesn't need to be called explicitely + by end user, since gdcmHeader::gdcmHeader now handles it. + +2003-03-29 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * gdcm/Doc many doxygen changes: + - Doxyfile now has two different versions, DoxyfileUsers that generates + the html.users end users oriented documentation and + DoxyfileDeveloppers that generates the html.developper developper + oriented documentation. + - README changed accordingly + - requirement.txt removed (old design info moved to TODO). + - Additional files DoxyInstallation.txt, DoxyIntroduction.txt, + DoxyMainPage.txt, DoxyPython.txt provide more information. + - Note: the website http://www.creatis.insa-lyon.fr/Public/Gdcm/ can now + be updated by simply regenerating the docs with doxygen and copying + html.developper and html.users to tux:/home/httpd/html/Public/Gdcm + * src/gdcmElValSet.cxx: stl <map>.count() can only return 0 or 1. Hence + all the tests in the form "if (<map>.count() >1)" were removed. + * src/gdcmFile.cxx: cosmetic changes to avoid messages of doxygen about + ill-formed documentation sections. + * src/gdcmHeader.cxx: ditto + +2003-03-27 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * setup.py fixed for un*x (needed macro for stdint.h) + * Test/test.cxx renamed to PrintHeader.cxx to avoid collision on + un*ces with sh-utils test utility. + * gdcmPython/demo/test.py renamed to PrintHeader.py + * gdcmPython/demo/ReorganiseFiles.py new demo script added. + * gdcmPython/win32/gdcmpycomplet.dsp renamed to gdcmpyembedded.dsp. + * gdcmPython/win32/gdcmpy.dsp trashed away (brain damaged). + * src/gdcm*.cxx JPR's bad inclusion fixed. + +2003-03-26 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * src/gdcmHeader[h, cxx] gdcmHeader now has an IsReadable predicate. + * gdcmPython/demo/test.py changed accordingly. + +2003-03-25 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * gdcmPython/Makefile.am fixed linking against libstdc++ + * gdcmPython/_gdcm.so symbolic link to gdcmPython/.libs/pygdcm.so added. + * Swig subdir (historical tests of swig version 1.3.17++) removed + * Test/testChangeEntete.cxx some lines commented out in order to make + compilation work. + * src/gdcmHeader.cxx cleaned up wild JPR's dirty kludge. + * src/gdcmElValSet.cxx cleaned up frog's forgotten debug message + +2003-03-24 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * src/gdcmHeader.cxx gdcmHeader::gdcmHeader now calls LoadElements(), + hence the user doesn't need this explicit call. + - gdcmPython/testSuite.py, gdcmPython/demo/*.py changed accordingly + i.e. LoadElements() call removed. + * src/gdcmCommon.h now defines UINT32_MAX (see stdint.h). + - src/Makefile.am declares the proper flag for g++. + * src/gdcmElValSet.h added gdcmElValSet::GenerateFreeTagKeyInGroup + for adding user defined new tags. + - src/gdcmHeader.cxx gdcmHeader::NewManualElValToPubDict added. + - src/gdcmHeader.cxx gdcmHeader::AddAndDefaultElements now + cleanly adds some gdcm added tags (like gdcmXSize, gdcmYSize...) + +2003-03-17 Fabrice Bellet <Fabrice.Bellet@creatis.insa-lyon.fr> + * Makefile.am, acinclude.m4, configure.in, python.m4, Dicts/Makefile.am, + Doc/Makefile.am, Test/Makefile.am, gdcmPython/Makefile.am, + src/Makefile.am : the project should properly compile and install + with the autotools, included the python wrappers part. + * gdcm.spec.in : added a spec file for RPM packaging. + +2003-03-14 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmUtils.cxx : redifinition of defaults parameters in code + +2003-03-12 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * gdcmPython/__init__.py fix of GDCM_DICT_PATH which was not + to exported to the environement (see gdcmPython/testSuite.py + for usage). + * src/gdcmElValSet.[cxx/h], gdcmElValue.[cxx/h], gdcmFile.[cxx/h], + gdcmHeader.[cxx/h]: ElValSet class renamed to gdcmElValSet, and + ElValue class renamed to gdcmElValue for obvious consistency reasons. + * src/gdcmElValSet.cxx, src/gdcmUtil.[cxx-h] Tokenize utility function + moved away from gdcmElValSet.cxx to gdcmUtil.cxx. + +2003-03-10 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * gdcmPython/__init__.py doesn't crash anymore when running in + in InstallMode or PreInstallMode but with an environment given + value of GDCM_DICT_PATH. + * src/gdcmDictSet.[cxx/h] coding style. + +2003-03-06 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * src/gdcmHeader.h and gdcmHeader.cxx Coding style + doxigenation. + * src/gdcm.h general comments moved to TODO, and README + * src/gdcm.h should now be seen as a user commodity (including it + should suffice to fully use gdcm). It is nowhere including within + any of the kernel files src/*.cxx and src/*.h. + +2003-03-05 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * src/gdcm.h splitted in gdcmCommon.h, gdcmDict.h, gdcmDictEntry.h, + gdcmDictSet.h, gdcmElValSet.h, gdcmElValue.h, gdcmFile.h, + gdcmHeader.h + * src/gdcm*.cxx only include their corresponding include file + (as opposed to gdcm.h) + * gdcmPython/gdcm.i changed accordingly + * Test/Makefile.am corrected and added NEWS, AUTHORS in order for + the autogen.sh generated "make snapshot" command to work. + * autogen.sh removed history related references to crea package. + +2003-03-04 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * distutilsSwigCPlusPlus.py work around some swig portability + bug. + +2003-03-03 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * Eventually, python/gdcmPython was renamed to gdcmPython. This + was done in a last ditch attempt to get setup.py _really_ + operationnal. The python/gdcmPython layaout add the advantage + of hidding away the python related distutils specific files + (MANIFEST.in, setup.py, distutils*.py...) from the main directory. + Alas, the src directory was out of scope (i.e. it's relative + position to setup.py was ../src) which made things impossible to + handle (see previous version of python/setup.py). Crossing fingers... + +2003-02-20 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * python/setup.py now works on Un*x. (harder than I thougth) + * python/distutilsSwigCPlusPlus.py can now have include files + among the list of sources. + +2003-02-20 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * src/gdcmHeader.cxx : bug fix - opening dicom file in binary !!! + * modifications in MSVC projects + +2003-02-19 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * As stated by the first lines of Test/ExceptionAndPython/README, it + looks like we can move back to original usage of exception within + src/gdcm* and hence remove the errno stuff that was introduced + as a quick and dirty fixture of this problem (added to the TODO). + * Doc/Doxyfile configuration file for Doxygen and corresponding + README file for usage added. + * Test/testWrite.cxx added. This new test comes from a split of + test.cxx that is now reverted to its original purpous i.e. + testing the proper parsing of a Dicom related file. + testWrite.cxx concentrates on testing the IO part of gdcm. + * Test/bug1.cxx (containing a bug on WIn32) added. + * src/gdcm.h, gdcmHeader.cxx, gdcmDictSet.cxx: + - gdcmHeader::GetPubTagNames and gdcmHeader::GetPubTagNamesByCategory + whose purpose is to publish the content of the TagNames of the + Dicom public dictionary were not accessible without an + instance of class gdcmHeader. + - those methods are now static methods of gdcmDictSet and hence + require no instances at all to be invocated. + - within gdcmDictSet this change required to change some method + to class methods (i.e. are now static) among which SetDictPath + (renamed to BuildDictPath) and LoadDefaultPubDict. + * python/gdcmPython/demo/printGroupedPublicDict.py changed to illustrate + the above changes by calling the new method classes of gdcmDictSet. + * python/gdcmPython/__init__.py now exposes gdcm.gdcmDictSet for + the above to be effective. + * python/gdcmPython: in order to wrap properly the above changes + for Python, swig version now needs to be > 1.3.17. + * python/gdcmPython/Makefile fixed to adapt itself to new + configure/make shema introduced by Johan Montagnat (thanks for the + contribution). Alas this Makefile cannot be turned into a proper + Makefile.am without some heavy changes in the configure.in + (for python dectection). + * python/gdcmPython/gdcm.i: the out typemap map<string, list<string>>* + now avoids publishing the empty entries. + +2003-02-13 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * python/setup.py : bug fix concerning install under windows + ExtraPath reused :-P + * gdcm.dsw : bug fix concerning path for libraries for python !!! + +2003-02-13 Benoit Regrain <Benoit.Regrain@creatis.insa-lyon.fr> + * Dicts/dicomV3.dic : remove double spaces !!! + * src/gdcmElValSet.cxx : bug fix concerning windows compiler + * python/gdcmPython/win32/gdcmpycomplet.dsp : bug fix concerning paths + and links + +2003-01-28 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * src/gdcmHeader.cxx added a post header parsing AddAndDefaultElements + method. Doxygenation. + * src/gdcm.h clean up of JPR spurious comments. + +2003-01-17 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * python/distutilsSwigCPlusPlus.py now properly collects the + shadow classes generated by "swig -c++" (gdcm.py in our case) + when using "python setup.py install". + * python/gdcmPython/__init__.py imports gdcm.py and only manually + reexports the working classes. + * src/gdcmHeader.cxx all the try/catch/throw calls were replaced + by the classical C errno scheme. This is to prevent an obscure + behavior of the python wrappers when importing wxPython.wx prior + to gdcmPython (which ended up in an abort call). An illustration + of this oddity can be found in the Test/ExceptionAndPython + subdir (see the README file). This problem probably due to + an combination of g++ and dynamic loading. + * added Test/ExceptionAndPython (see above) + +2003-01-17 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * Changed the layout of the python part to avoid bloating main + directory with setup.py, distutilsSwigCPlusPlus.py, MANIFEST.in + i.e. the distutils arsenal. All the python related stuff is + again in a python subdir, but the package itself is now in + python/gdcmPython. + * setup.py was cleaned up: + - pythonIncludePath removed + - python setup.py bdist target is now functional. + * gdcmPython/__init__.py doesn't export FileName any more (to avoid + collision with other packages). gdcmPython/demo/*.py changed + accordingly. + +2003-01-15 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * python subdir moved to gdcmPython (preparation of distutils packaging). + * gdcmPython/setup.py and distutilsSwigCPlusPlus.py added. The + distutils installer is operational. + * - gdcmPython/__init__.py now properly loads the swig generated + shadow classes (from gdcm.py). + - gdcmPython/demo/*.py changed to import the package gdcmPython + instead of gdcmPython/demo/load.py. + - gdcmPython/testSuite.py changed to import the package gdcmPython. + +2002-12-16 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * src/gdcm.h, src/gdcmHeader.cxx: added GetPubTagNames() resp. + GetPubTagNamesByCategory() to gdcmHeader that return a list of the + entries within the associated public Dicom dictionary resp. the same + information but sorted by the fourth field (PAT, IMG, DIR) of the + dictionary. + - Dicts/dicomV3.dic Entries which had an unspecified fourth field + are now in the "???" group. + - python/gdcm.i changed accordingly, + - python/demo/printGroupedPublicDict.py added, that gives an example + of the above new functionalities in Python. + +2002-12-11 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * src/gdcm.h, gdcmHeader.cxx: + - historic references to glib's g_malloc and g_free (#defined) + were definitively removed. + - gdcm.h: cosmetic changes (part of comments moved to Doc/requirements) + * src/gdcmElValSet.cxx: + - GetElement(guint32, guint32) renamed to GetElementByNumber. + - GetElValue(guint32, guint32) renamed to GetElValueByNumber. + - GetElValue(string) renamed to GetElValueByName. + - Added GetElementByName(string). + * src/gdcmHeader.cxx: added + - GetPubElValRepByNumber(guint16, guint16) + - GetPubElValRepByName(string) + - GetShaElValRepByNumber(guint16, guint16) + - GetShaElValRepByName(string) + - GetShaElValByNumber(guint16, guint16) + - GetShaElValRepByName(string) + - GetElValRepByNumber(guint16, guint16) + - GetElValRepByName(string) + - GetElValByNumber(guint16, guint16) + - GetElValRepByName(string) + * Doc/requirements.txt added. + +2002-12-9 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * Test/Makefile building now depends on the one of libgdcm.so + * src/gdcmHeader.cxx and gdcm.h are now OB (undefined length encoded + pixel data) aware which enables finding the address (offset) of + the pixel data of JPEG encoded DICOM files. This leaves only a single + file in the testSuite whose pixel data address (offset) is unknown. + * python/testSuite.py changed accordingly. + +2002-12-6 Christophe Odet + Hugues Benoit-Cattin + Eric.Boix + * VC++ has some strong limitations when working with the STL, as stated + in http://support.microsoft.com/support/kb/articles/Q168/9/58.ASP : + "Also note that some STL containers (map, set, queue, list, deque) + cannot be exported. [...] + Some STL classes contain nested classes. These classes can not + be exported. [...] + This is caused by a designed limitation that once a template + class is instantiated, it can not be re-instantiated and + exported." + Since our usage of map<> is ubiquitous in gdcm, this "designed + limitation" of VC++ is a pitfall. + Hence the Python wrappers of gdcm cannot be incrementally linked + against the c++ dynamic library. The dirty but only workaround is + to forget about incremental link of dynamic libraries and to generate + the Python wrappers library with the inclusions of the underlying C++ + library. + The following modifications concern this matter on Win32/VC++: + - wrapping python correct with standalone wrapped dll (don't use separate + dll under windows !!!!) + - python21_d debug mode enabled (ask Frog how to use it :-) + - NO problem with having an STL member of class for example string in C++ + WITH THE RESTRICTION OF FORGETING ABOUT INCREMENTAL LINK. + - Python test of dcmlib in Python is ok under windows on a large set + (one) of image(s). + * removed glib references + * typedef's inserted in gdcm.i for correct swig type management + +2002-11-27 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * python/demo/*.py load.py extracted from test.py. Added explore.py + that only displays required tags and testAll.py that parses all + the files of the testsuite without using unittest. + * python/testSuite.py other additional test on new files added. + * Data/* new test files added accordingly to the testSuite. + * src/gdcmHeader.cxx avoid overwriting of the dictionary when + the vr in the file differs from the one of the dictionary. + +2002-11-20 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * src/gdcm.h and gdcmHeader.cxx gdcm no longer loads all the elements + values, but limits itself to values which are below a user specified + size (by default 1024 bytes). + * python/gdcm.i : elements not loaded (because their size is above the + user specified treshold) are exported with their TagKey as key of the + python dictionary. This enables the testsuite to make some checks + on the unloaded elements (since we have their offset and size). + * python/testSuite.py + - now tests for the existence and proper value of the pixel data + - two new examples added. + * Data/gdcm-MR-SIEMENS-16.acr[12] added. + +2002-11-18 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * src/gdcm.h and gdcmHeader.cxx are now "Big Endian transfer syntax" + aware. See the strategy comments in gdcmHeader::FindLength(). + * Test/test.cxx now accepts a filename as first argument. + * Data/US-PAL-8-10x-echo.dcm and US-RGB-8-epicard.dcm added. + * python/testSuite.py changed to integrate test on above files. + +2002-11-15 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * Dicts/dicomV3.dic removed all the trailing (RET) when the + the vr was also RET. + * python/testSuite.py more tests added. + +2002-11-14 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * python/testSuite.py unittest test suite added (uses Data) + * Data/* dcm and acr files for the test suite. + * glib dependance removed from un*x version. We now use ISO C99 + 7.18 Integer types (see stdint.h) + - python/Makefile, src/Makefile src/gdcm.h + * src/ when an explicit vr (like dicom files) suddenly poped an + implicit element we use to mark the underlying DictEntry of the + concerned ElValue with "Implicit". This strategy was damageable + too the public or provite dictionaries, since some of their vr + would be changed. Since Header::FindLength heavily relies on the + detection by Header::FindVR of falsely explicit elements, I + added an extra ImplicitVr member to ElValue (boolean). + The rest of the changes we the necessary adaptations. + +2002-11-12 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * src/gdcmHeader::FindLength bug fix when trapping falsely explicit + VR files. + * src/gdcmHeader::FindVR: hard way fix of falsely explicit vr files. + +2002-11-8 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * Adaptation for porting to VC++: + - src/gdcm.h + o forced to use std namespace (for string to be known) + o all class use __declspec export style on WIN32 + - src/gdcmUtil.cxx new Exit method that wraps the exit call + (in stdlib.h on Win32 but in std:: for gcc) + * src/gdcmDictSet::SetDictPath adds a trailing / to environement + variable GDCM_DICT_PATH. + * src/gdcmHeader.cxx verbose comments made discrete. + +2002-11-7 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * python/gdcm.i: added a typemap that converts a C++ hashing table + to native Python dictionary. + * python/demo/test.py: + - now uses the native dictionary for exploration of gdcmHeader. + - takes an optional filename argument (the file to parse). + * src/gdcm.h and gdcmHeader.cxx: gdcmHeader now has an accessor on + PubElVals hashing table. + * Dicts/dicomV3.dic removed error prone trailing spaces. + +2002-11-6 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * Python wrapping process moved away from src/Makefile to + newly created python/Makefile (as well as gdcm.i) + * python/demo/test.py (that mirrors Test/test.cxx) is effective. + * src/gdcmHeader::FindLength only looks for current vr when necessary. + * src/gdcmDictSet.cxx: the dictionnaries directory path is now imported + from the environement variable GDCM_DICT_PATH (when existing). + * src/gdcmDict::GetTag bug fix. + +2002-10-31 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * Straightforward temporary fixes for swig to build the python wrappers. + src/Makefile now has a python working entry [by working we mean + that we can import the shadow classes without errors]. + +2002-10-29 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * hashtest.cxx removed (since already in Test) + * src/gdcmlib.h renamed to src/gdcm.h + * src/dcm.i renamed to src/gdcm.i + * src/Makefile prepared for python wrapping + +2002-10-29 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * src/gdcmHeader.cxx : + - Parsing of header is now separated from loading of element values + (see gdcmHeader::LoadElements). + - general clean up of hopefully all file access (creation of + ReadInt16 and ReadInt32) + +2002-10-22 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * src/gdcmHeader.cxx : + - RecupLgr renamed to FindLength and cut off with new IsAnInteger + method. + - SetLgrElem renamed to SetLength + - GetLgrElem renamed to GetLength + - ~gdcmHeader() made virtual to pesky warning messages at compile. + * src/gdcmElValSet.cxx fixed both GetElValue methods + * Dicts/dicomV3.dic falacious entry [7fe0 0010 OT PXL Pixel Data] + due to IdoDude was cleaned out. + +2002-10-21 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * src/gdcmHeader.cxx RecupLgr split in FindVR and RecupLgr. FindVR + concentrates on finding the value representation (when it exists). + RecupLgr now only finds the element value length, and it avoids + returning the unecessary skL (skipped length). + Also, offsetCourant was simply removed (with taille_fich) since + it was redundant with the File position internals (by using + ftell and fseek). This also made skL (see above in RecupLgr) usage + jajun. + * src/gdcmHeaderIdo.cxx src/gdcmIdo.h added. Those files concentrate + on the libido specificities which are handled through class + inheritance. + * Test/implicit_vr.dcm dicom v3 in implicit value representation + added. + +2002-10-17 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * Truckload of changes. Parsing of header is barely functional + (see Test/test) with the standard dictionary (see Dicts/dicomV3.dic). + +2002-10-10 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * src/gdcmHeader.cxx many addons of low level methods + +2002-10-07 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * src/gdcmHeader now contains_IdDcmCheckSwap, _IdDcmRecupLgr, + and _IdDcmSWAP_LONG. + +2002-09-12 Eric Boix <Eric.Boix@creatis.insa-lyon.fr> + * This corresponds to all the changes decided at the meeting of + May 23 2002. Needless to say we are running late... + diff --git a/Utilities/ITK/Utilities/gdcm/DEVELOPPER b/Utilities/ITK/Utilities/gdcm/DEVELOPPER new file mode 100644 index 0000000000000000000000000000000000000000..b0c1b158bdddf88e00128b59ce084e3b80bf2256 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/DEVELOPPER @@ -0,0 +1 @@ +The entry point is Doc/Website/Developpers.html diff --git a/Utilities/ITK/Utilities/gdcm/Dicts/.cvsignore b/Utilities/ITK/Utilities/gdcm/Dicts/.cvsignore new file mode 100644 index 0000000000000000000000000000000000000000..ed951f5ccdf6233e67a50da8a22d364e163382b8 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/Dicts/.cvsignore @@ -0,0 +1,5 @@ +Makefile +Makefile.in +DartTestfile.txt +cmake.check_depends +cmake.depends diff --git a/Utilities/ITK/Utilities/gdcm/Dicts/ACUSON.dic b/Utilities/ITK/Utilities/gdcm/Dicts/ACUSON.dic new file mode 100644 index 0000000000000000000000000000000000000000..ea805de1fa33d196c68ba094c9cd0918e1171790 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/Dicts/ACUSON.dic @@ -0,0 +1,8 @@ +7fdf 0010 LO 1 Private Creator (ACUSON:1.2.840.113680.1.0) +7fdf 1000 IS 1 Lossy Compression Ratio +7fdf 1001 US 1 Image Format +7fdf 1002 US 1 Acuson Region Type +7fdf 100b UL 1 Acuson Image Apex X +7fdf 100c UL 1 Acuson Image Apex Y +7fdf 100d IS 1 B-Color-On Flag +7fdf fe00 OB 1 Data Padding diff --git a/Utilities/ITK/Utilities/gdcm/Dicts/CMakeLists.txt b/Utilities/ITK/Utilities/gdcm/Dicts/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..d7ddb2c07803dcd0bd8aea43f9b7bc6671cab7ba --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/Dicts/CMakeLists.txt @@ -0,0 +1,118 @@ +#----------------------------------------------------------------------------- +# DICOM dictionary stuff + +#----------------------------------------------------------------------------- +# Generate our own 'DICOM' dictionary, based on the following dictionaries: +SET(ALL_DICTS + dicomV3.dic + Papyrus.dic + NIH.dic #the forbidden one... + SPI.dic + # PHILIPS-Intera.dic # uncomment me if you want + ) + +# Better solution +SET(TEST_DICT_BODY) +FOREACH(dict ${ALL_DICTS}) + # Properly set dependencies, therefore `touch Philips-Intera.dic` does not rebuild + # but adding/removing a line in Philips-Intera.dic rebuild as expected + CONFIGURE_FILE("${GDCM_SOURCE_DIR}/Dicts/${dict}" + "${GDCM_BINARY_DIR}/Dicts/${dict}" COPYONLY IMMEDIATE) + FILE(READ "${GDCM_SOURCE_DIR}/Dicts/${dict}" dict_append) + SET(TEST_DICT_BODY "${TEST_DICT_BODY}\n${dict_append}") +ENDFOREACH(dict) +CONFIGURE_FILE("${GDCM_SOURCE_DIR}/Dicts/gdcm.dic.in" + "${GDCM_BINARY_DIR}/Dicts/gdcm.dic" @ONLY IMMEDIATE) + +#----------------------------------------------------------------------------- +# Nice trick to avoid creating a .h file each time we compile gdcm +# Since CONFIGURE_FILE do a 'copy if different' +# We have to write the file here since is contains 'DICOM_DICTIONARY' +# Which is a variable afterward... + +# Following code contributing by Andy Cedilnik (Kitware) +FILE(READ "${GDCM_BINARY_DIR}/Dicts/gdcm.dic" ENT) +STRING(REGEX REPLACE "\r?\n" ";" ENT "${ENT}") +SET(DICOM_DATA_DICTIONARY "") + +FOREACH(line ${ENT}) + STRING(REGEX REPLACE + "^([0-9a-f][0-9a-f][0-9a-f][0-9a-f]) ([0-9a-f][0-9a-f][0-9a-f][0-9a-f]) ([A-Z]+) ([1-9n-]+) (.*)$" + " {0x\\1, 0x\\2, \"\\3\" , \"\\4\" , \"\\5\"}, " nline "${line}") + SET(DICOM_DATA_DICTIONARY "${DICOM_DATA_DICTIONARY}\n${nline}") +ENDFOREACH(line) + +SET(DICOM_DATA_DICTIONARY "${DICOM_DATA_DICTIONARY} \n {0,0,0,0,0}") + +#----------------------------------------------------------------------------- +# ... for DicomTS file +FILE(READ "dicomTS.dic" ENT_TS) +STRING(REGEX REPLACE "\r?\n" ";" ENT_TS "${ENT_TS}") +SET(DICOM_TS_DICTIONARY "") + +FOREACH(line ${ENT_TS}) + STRING(REGEX REPLACE + "^([0-9.]+) +(.*)$" + " ts[\"\\1\"] = \"\\2\"; " nline "${line}") + SET(DICOM_TS_DICTIONARY "${DICOM_TS_DICTIONARY}\n${nline}") +ENDFOREACH(line) + +#----------------------------------------------------------------------------- +# ... for DicomVR file +FILE(READ "dicomVR.dic" ENT_VR) +STRING(REGEX REPLACE ";" "/" ENT_VR "${ENT_VR}") # CMake doesn't like ';' +STRING(REGEX REPLACE "\r?\n" ";" ENT_VR "${ENT_VR}") +SET(DICOM_VR_DICTIONARY "") + +FOREACH(line ${ENT_VR}) + STRING(REGEX REPLACE + "^([A-Z][A-Z]) (.*)/ +//.*$" + " vr[\"\\1\"] = \"\\2\"; " nline "${line}") + SET(DICOM_VR_DICTIONARY "${DICOM_VR_DICTIONARY}\n${nline}") +ENDFOREACH(line) + +#----------------------------------------------------------------------------- +# ... for DictGroupName file +FILE(READ "DictGroupName.dic" ENT_TS) +STRING(REGEX REPLACE "\r?\n" ";" ENT_TS "${ENT_TS}") +SET(DICT_GROUP_NAME_DICTIONARY "") + +FOREACH(line ${ENT_TS}) + STRING(REGEX REPLACE + "^([0-9a-f]+) +(.*)$" + " groupName[0x\\1] = \\2; " nline "${line}") + SET(DICT_GROUP_NAME_DICTIONARY "${DICT_GROUP_NAME_DICTIONARY}\n${nline}") +ENDFOREACH(line) + +#----------------------------------------------------------------------------- +# ... for DicomDir file +FILE(READ "DicomDir.dic" ENT_DIR) +STRING(REGEX REPLACE "\\\\" "\\\\\\\\" ENT_DIR "${ENT_DIR}") +STRING(REGEX REPLACE ";" "/" ENT_DIR "${ENT_DIR}") # CMake doesn't like ';' +STRING(REGEX REPLACE "\r?\n" ";" ENT_DIR "${ENT_DIR}") +SET(DICOM_DIR_DICTIONARY "") + +FOREACH(line ${ENT_DIR}) + STRING(REGEX REPLACE + "^(metaElem|patientElem|studyElem|serieElem|imageElem) *([a-f0-9]+) ([a-f0-9]+) [\"](.*)[\"](.*)$" + " {\"\\1\" , 0x\\2 , 0x\\3 , \"\\4\"}, \\5" nline "${line}") + SET(DICOM_DIR_DICTIONARY "${DICOM_DIR_DICTIONARY}\n${nline}") +ENDFOREACH(line) + +#----------------------------------------------------------------------------- +# ... Set the dictionnary +SET(DICOM_DIR_DICTIONARY "${DICOM_DIR_DICTIONARY} \n {0,0,0,0}") + +CONFIGURE_FILE("${GDCM_SOURCE_DIR}/src/gdcmDefaultDicts.cxx.in" + "${GDCM_BINARY_DIR}/src/gdcmDefaultDicts.cxx" IMMEDIATE) + +#----------------------------------------------------------------------------- +INSTALL_FILES(/include/InsightToolkit/gdcm/Dicts .dic + dicomV3 + dicomVR + dicomTS + DicomDir + DictGroupName + gdcm +) + diff --git a/Utilities/ITK/Utilities/gdcm/Dicts/DicomDir.dic b/Utilities/ITK/Utilities/gdcm/Dicts/DicomDir.dic new file mode 100644 index 0000000000000000000000000000000000000000..58d480bc605fcfa6294e838d3982c1ac34a3d0ca --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/Dicts/DicomDir.dic @@ -0,0 +1,96 @@ +metaElem 0002 0000 "123" // Meta Group Length : to be computed later +metaElem 0002 0001 "\002\000\000\000" // File Meta Information Version +metaElem 0002 0002 "1.2.840.10008.1.3.10" // Media Stored SOP Class UID i.e. : 'Media Storage Directory Storage' +metaElem 0002 0003 "" // Media Stored SOP Instance UID : may be forged later +metaElem 0002 0010 "1.2.840.10008.1.2.1" // Transfer Syntax UID i.e. : Explicit VR - Little Endian +metaElem 0002 0012 "" // Implementation Class UID : may be forged later +metaElem 0002 0013 "gdcmLib " // Implementation Version Name don't remove trailing space ! +metaElem 0002 0016 " " // Source Application Entity Title (our ?) +metaElem 0002 0100 "" // Private Information Creator +metaElem 0004 1130 "" // File-set ID +metaElem 0004 1200 "0" // Offset of the first dir of root dir entity : to be computed later +metaElem 0004 1202 "0" // Offset of the last dir of root dir entity : to be computed later +metaElem 0004 1212 "-1" // File-set consistency flag : 0xffff Length inconsistencies will be assumed + +patientElem fffe e000 "255" // 'no length' item : length to be set to 0xffffffff later +patientElem 0004 1400 "0" // Offset of next directory record : = 0x0 : fffe e00d at end ! +patientElem 0004 1410 "65535" // Record in use flag : 65535 = 0xFFFF (see 03_10PU.PDF p 31) +patientElem 0004 1420 "0" // Offset of referenced lower-level dir entity : to be computed later +patientElem 0004 1430 "PATIENT " // Directory Record Type don't remove trailing space ! +patientElem 0008 0005 "ISO_IR 100" // Specific Character Set +patientElem 0010 0010 "" // Patient's Name +patientElem 0010 0020 "" // Patient ID +patientElem 0010 0030 "" // Patient's Birthdate +patientElem 0010 0040 "" // Patient's Sex +patientElem fffe e00d "" // Item delimitation : length to be set to ZERO later + +studyElem fffe e000 "-1" // 'no length' item : length to be set to 0xffffffff later +studyElem 0004 1400 "0" // Offset of next directory record : = 0x0 : fffe e00d at end ! +studyElem 0004 1410 "65535" // Record in use flag : 65535 = 0xFFFF (see 03_10PU.PDF p 31) +studyElem 0004 1420 "0" // Offset of referenced lower-level dir entity : to be computed later +studyElem 0004 1430 "STUDY " // Directory Record Type don't remove trailing space ! +studyElem 0008 0005 "ISO_IR 100" // Specific Character Set +studyElem 0008 0020 "" // Study Date +studyElem 0008 0030 "" // Study Time +studyElem 0008 0050 "" // Accession Number +studyElem 0008 1030 "" // Study Description +studyElem 0020 000d "" // Study Instance UID : may be forged later +studyElem 0020 0010 "" // Study ID : may be forged later +studyElem fffe e00d "" // Item delimitation : length to be set to ZERO later + +serieElem fffe e000 "-1" // 'no length' item : length to be set to 0xffffffff later +serieElem 0004 1400 "0" // Offset of next directory record : = 0x0 : fffe e00d at end ! +serieElem 0004 1410 "65535" // Record in use flag : 65535 = 0xFFFF (see 03_10PU.PDF p 31) +serieElem 0004 1420 "0" // Offset of referenced lower-level dir entity : to be computed later +serieElem 0004 1430 "SERIES" // Directory Record Type don't add trailing space ! +serieElem 0008 0005 "ISO_IR 100" // Specific Character Set +serieElem 0008 0021 "" // Series Date +serieElem 0008 0031 "" // Series Time +serieElem 0008 0060 "" // Modality +serieElem 0008 0080 "" // Institution Name : may be forged later +serieElem 0008 0081 "" // Institution Address : may be forged later +serieElem 0008 1010 "" // Station Name +serieElem 0008 1050 "" // Performing Physician's Name +serieElem 0008 103e "" // Series Description : may be forged later +serieElem 0018 1030 "" // Protocol Name +serieElem 0020 000e "" // Series Instance UID : may be forged later +serieElem 0020 0011 "0" // Series Number : may be forged later +serieElem fffe e00d "" // Item delimitation : length to be set to ZERO later + +imageElem fffe e000 "-1" // 'no length' item : length to be set to 0xffffffff later +imageElem 0004 1400 "0" // Offset of next directory record : = 0x0 : fffe e00d at end ! +imageElem 0004 1410 "65535" // Record in use flag : 65535 = 0xFFFF (see 03_10PU.PDF p 31) +imageElem 0004 1420 "0" // Offset of referenced lower-level dir entity : to be computed later +imageElem 0004 1430 "IMAGE " // Directory Record Type don't remove trailing space ! +imageElem 0004 1500 "" // Referenced File ID : will be set later = relative File Name +imageElem 0004 1510 "" // Referenced SOP Class UID in File : may be forged later +imageElem 0004 1511 "" // Referenced SOP Instance UID in File : may be forged later +imageElem 0004 1512 "" // Referenced Transfer Syntax in File +imageElem 0008 0005 "ISO_IR 100" // Specific Character Set +imageElem 0008 0008 "" // Image Type +imageElem 0008 0016 "" // SOP Class UID : to be set/forged later +imageElem 0008 0018 "" // SOP Instance UID : to be set/forged later +imageElem 0008 0023 "" // Content Date +imageElem 0008 0033 "" // Content Time +imageElem 0018 1060 "0" // Trigger Time +imageElem 0020 0013 "0" // Image Number +imageElem 0020 0032 "1.0\1.0\1.0 " // Image Position Patient +imageElem 0020 0037 "1\0\0\0\1\0 " // Image Orientation Patient +imageElem 0020 0052 "0" // Frame of Reference UID +imageElem 0020 1041 "0.0" // Slice Location +imageElem 0020 4000 "" // Image Comments +imageElem 0028 0002 "1" // Samples per Pixel +imageElem 0028 0004 " " // Photometric Interpretation +imageElem 0028 0006 "0" // Planar Configuration +imageElem 0028 0008 "1" // Number of Frames +imageElem 0028 0010 "0" // Rows +imageElem 0028 0011 "0" // Columns +imageElem 0028 0030 "1.0\1.0 " // Pixel Spacing +imageElem 0028 0100 " " // Bits Allocated +imageElem 0028 0101 " " // Bits Stored +imageElem 0028 0103 " " // Pixel Representation +imageElem 0028 1052 "0 " // Rescale Intercept +imageElem 0028 1053 "1 " // Rescale Slope +imageElem 0050 0004 "0" // Calibration Image +imageElem fffe e00d "" // Item delimitation : length to be set to ZERO later + diff --git a/Utilities/ITK/Utilities/gdcm/Dicts/DictGroupName.dic b/Utilities/ITK/Utilities/gdcm/Dicts/DictGroupName.dic new file mode 100644 index 0000000000000000000000000000000000000000..13278ef88338b3a88ca1d98c7f17c974795b8265 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/Dicts/DictGroupName.dic @@ -0,0 +1,62 @@ +0000 "Command" +0002 "Meta Elements" +0004 "Directory" +0008 "Identifing" +0010 "Patient" +0012 "Clinical Trial" +0018 "Acquisition" +0020 "Relationship" +0028 "Image Presentation" +0032 "Study" +0038 "Visit" +003a "Waveform" +0040 "Procedure" +0050 "Device" +0054 "Nuclear Medicine" +2000 "BFS" +2010 "BFB" +2020 "BAB" +2040 "IOB" +2100 "Print Job" +2110 "Printer" +3002 "Radio Therapy" +3004 "DVH" +3006 "SSET" +300a "RT" +300b "RT" +300e "Review" +4000 "Text" +4008 "Results" +5000 "Curves" +5002 "Curves" +5004 "Curves" +5006 "Curves" +5008 "Curves" +500a "Curves" +500c "Curves" +500e "Curves" +5010 "Curves" +5012 "Curves" +5014 "Curves" +5016 "Curves" +5018 "Curves" +501a "Curves" +501c "Curves" +501e "Curves" +6000 "Overlays" +6002 "Overlays" +6004 "Overlays" +6006 "Overlays" +6008 "Overlays" +600a "Overlays" +600c "Overlays" +600e "Overlays" +6010 "Overlays" +6012 "Overlays" +6014 "Overlays" +6016 "Overlays" +6018 "Overlays" +601a "Overlays" +601c "Overlays" +601e "Overlays" +7fe0 "Pixels" diff --git a/Utilities/ITK/Utilities/gdcm/Dicts/ELSCINT.dic b/Utilities/ITK/Utilities/gdcm/Dicts/ELSCINT.dic new file mode 100644 index 0000000000000000000000000000000000000000..da46b3f650ddc9fff6897f508a45adedea7fa1b9 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/Dicts/ELSCINT.dic @@ -0,0 +1,14 @@ +00e1 0010 LO 1 Implementor ID +00e1 1022 DS 2 Presentation Relative Center +00e1 1023 DS 2 Presentation Relative Part +00e1 1024 CS 1 Presentation Horizontal Invert +00e1 1025 CS 1 Presentation Vertical Invert +00e1 1040 SH 1 Image Label +01f3 0010 LO 1 Implementor ID +01f3 1011 SQ 1 PS Sequence +07a1 0010 LO 1 Implementor ID +07a1 1010 LO 1 Tamar Software Version +6001 0010 LO 1 Implementor ID +6001 1010 CS 1 Text Overlay Flag +00e1 0010 LO 1 Implementor ID +00e1 1022 DS 2 Presentation Relative Center diff --git a/Utilities/ITK/Utilities/gdcm/Dicts/GE-EchoPAC.dic b/Utilities/ITK/Utilities/gdcm/Dicts/GE-EchoPAC.dic new file mode 100644 index 0000000000000000000000000000000000000000..08af46f9ce4885860592228db72b7adebeb2eeb5 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/Dicts/GE-EchoPAC.dic @@ -0,0 +1,2 @@ +6003 00xx LO 1 Private Creator (GEMS_Ultrasound_ImageGroup_001) +7FE1 00xx LO 1 Private Creator (GEMS_Ultrasound_MovieGroup_001) diff --git a/Utilities/ITK/Utilities/gdcm/Dicts/GEMS-Advance.dic b/Utilities/ITK/Utilities/gdcm/Dicts/GEMS-Advance.dic new file mode 100644 index 0000000000000000000000000000000000000000..95e188d0ad19510cfb29e0eeefa8f796c662d83d --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/Dicts/GEMS-Advance.dic @@ -0,0 +1,306 @@ +0009 0010 SH 1 Private Creator Data Element +0009 1001 LO 2 GE Advance Implementation Version Name +0009 1002 LO 1 GE Advance Patient.patient_id +0009 1003 SH 1 GE Advance Patient.compatible_version +0009 1004 SH 1 GE Advance Patient.software_version +0009 1005 DT 1 GE Advance Patient.patient_datetime +0009 1006 SL 1 GE Advance Patient.type +0009 1007 UI 1 GE Advance Exam.exam_id +0009 1008 SH 1 GE Advance Exam.compatible_version +0009 1009 SH 1 GE Advance Exam.software_version +0009 100a UI 1 GE Advance Scan.scan_id +0009 100b SH 1 GE Advance Scan.compatible_version +0009 100c SH 1 GE Advance Scan.software_version +0009 100d DT 1 GE Advance Scan.scan_datetime +0009 100e DT 1 GE Advance Scan.scan_ready +0009 100f UI 1 GE Advance Scan.scan_description +0009 1010 LO 1 GE Advance Scan.hospital_name +0009 1011 LO 1 GE Advance Scan.scanner_desc +0009 1012 LO 1 GE Advance Scan.manufacturer +0009 1013 UI 1 GE Advance Scan.for_identifier +0009 1014 LO 1 GE Advance Scan.landmark_name +0009 1015 SH 1 GE Advance Scan.landmark_abbrev +0009 1016 SL 1 GE Advance Scan.patient_position +0009 1017 SL 1 GE Advance Scan.scan_perspective +0009 1018 SL 1 GE Advance Scan.scan_type +0009 1019 SL 1 GE Advance Scan.scan_mode +0009 101a SL 1 GE Advance Scan.start_condition +0009 101b SL 1 GE Advance Scan.start_cond_data +0009 101c SL 1 GE Advance Scan.sel_stop_cond +0009 101d SL 1 GE Advance Scan.sel_stop_cond_data +0009 101e SL 1 GE Advance Scan.collect_deadtime +0009 101f SL 1 GE Advance Scan.collect_singles +0009 1020 SL 1 GE Advance Scan.collect_countrate +0009 1021 SL 1 GE Advance Scan.countrate_period +0009 1022 SL 1 GE Advance Scan.delayed_events +0009 1023 SL 1 GE Advance Scan.delayed_bias +0009 1024 SL 1 GE Advance Scan.word_size +0009 1025 SL 1 GE Advance Scan.axial_acceptance +0009 1026 SL 1 GE Advance Scan.axial_angle_3d +0009 1027 SL 1 GE Advance Scan.theta_compression +0009 1028 SL 1 GE Advance Scan.axial_compression +0009 1029 FL 1 GE Advance Scan.gantry_tilt_angle +0009 102a SL 1 GE Advance Scan.collimation +0009 102b SL 1 GE Advance Scan.scan_fov +0009 102c SL 1 GE Advance Scan.axial_fov +0009 102d SL 1 GE Advance Scan.event_separation +0009 102e SL 1 GE Advance Scan.mask_width +0009 102f SL 1 GE Advance Scan.binning_mode +0009 1030 SL 1 GE Advance Scan.trig_rej_method +0009 1031 SL 1 GE Advance Scan.number_for_reject +0009 1032 SL 1 GE Advance Scan.lower_reject_limit +0009 1033 SL 1 GE Advance Scan.upper_reject_limit +0009 1034 SL 1 GE Advance Scan.triggers_acquired +0009 1035 SL 1 GE Advance Scan.triggers_rejected +0009 1036 LO 1 GE Advance Scan.tracer_name +0009 1037 LO 1 GE Advance Scan.batch_description +0009 1038 FL 1 GE Advance Scan.tracer_activity +0009 1039 DT 1 GE Advance Scan.meas_datetime +0009 103a FL 1 GE Advance Scan.pre_inj_volume +0009 103b DT 1 GE Advance Scan.admin_datetime +0009 103c FL 1 GE Advance Scan.post_inj_activity +0009 103d DT 1 GE Advance Scan.post_inj_datetime +0009 103e SH 1 GE Advance Scan.radionuclide_name +0009 103f FL 1 GE Advance Scan.half_life +0009 1040 FL 1 GE Advance Scan.positron_fraction +0009 1041 SL 1 GE Advance Scan.source1_holder +0009 1042 FL 1 GE Advance Scan.source1_activity +0009 1043 DT 1 GE Advance Scan.source1_meas_dt +0009 1044 SH 1 GE Advance Scan.source1_radnuclide +0009 1045 FL 1 GE Advance Scan.source1_half_life +0009 1046 SL 1 GE Advance Scan.source2_holder +0009 1047 FL 1 GE Advance Scan.source2_activity +0009 1048 DT 1 GE Advance Scan.source2_meas_dt +0009 1049 SH 1 GE Advance Scan.source2_radnuclide +0009 104a FL 1 GE Advance Scan.source2_half_life +0009 104b SL 1 GE Advance Scan.source_speed +0009 104c FL 1 GE Advance Scan.source_location +0009 104d SL 1 GE Advance Scan.emission_present +0009 104e SL 1 GE Advance Scan.lower_axial_acc +0009 104f SL 1 GE Advance Scan.upper_axial_acc +0009 1050 SL 1 GE Advance Scan.lower_coinc_limit +0009 1051 SL 1 GE Advance Scan.upper_coinc_limit +0009 1052 SL 1 GE Advance Scan.coinc_delay_offset +0009 1053 SL 1 GE Advance Scan.coinc_output_mode +0009 1054 SL 1 GE Advance Scan.upper_energy_limit +0009 1055 SL 1 GE Advance Scan.lower_energy_limit +0009 1056 UI 1 GE Advance Scan.normal_cal_id +0009 1057 UI 1 GE Advance Scan.normal_2d_cal_id +0009 1058 UI 1 GE Advance Scan.blank_cal_id +0009 1059 UI 1 GE Advance Scan.wc_cal_id +0009 105a SL 1 GE Advance Scan.derived +0009 105b LO 1 GE Advance Scan.contrast_agent +0009 105c UI 1 GE Advance Frame.frame_id +0009 105d UI 1 GE Advance Frame.scan_id +0009 105e UI 1 GE Advance Frame.exam_id +0009 105f LO 1 GE Advance Frame.patient_id +0009 1060 SH 1 GE Advance Frame.compatible_version +0009 1061 SH 1 GE Advance Frame.software_version +0009 1062 ST 1 GE Advance Frame.where_is_frame +0009 1063 SL 1 GE Advance Frame.frame_size +0009 1064 SL 1 GE Advance Frame.file_exists +0009 1065 SL 1 GE Advance Frame.patient_entry +0009 1066 FL 1 GE Advance Frame.table_height +0009 1067 FL 1 GE Advance Frame.table_z_position +0009 1068 DT 1 GE Advance Frame.landmark_datetime +0009 1069 SL 1 GE Advance Frame.slice_count +0009 106a FL 1 GE Advance Frame.start_location +0009 106b SL 1 GE Advance Frame.acq_delay +0009 106c DT 1 GE Advance Frame.acq_start +0009 106d SL 1 GE Advance Frame.acq_duration +0009 106e SL 1 GE Advance Frame.acq_bin_dur +0009 106f SL 1 GE Advance Frame.acq_bin_start +0009 1070 SL 1 GE Advance Frame.actual_stop_cond +0009 1071 FD 1 GE Advance Frame.total_prompts +0009 1072 FD 1 GE Advance Frame.total_delays +0009 1073 SL 1 GE Advance Frame.frame_valid +0009 1074 SL 1 GE Advance Frame.validity_info +0009 1075 SL 1 GE Advance Frame.archived +0009 1076 SL 1 GE Advance Frame.compression +0009 1077 SL 1 GE Advance Frame.uncompressed_size +0009 1078 SL 1 GE Advance Frame.accum_bin_dur +0009 1079 SH 1 GE Advance ImageSet.compatible_version +0009 107a SH 1 GE Advance ImageSet.software_version +0009 107b DT 1 GE Advance ImageSet.is_datetime +0009 107c SL 1 GE Advance ImageSet.is_source +0009 107d SL 1 GE Advance ImageSet.is_contents +0009 107e SL 1 GE Advance ImageSet.is_type +0009 107f FL 3 GE Advance ImageSet.is_reference +0009 1080 SL 1 GE Advance ImageSet.multi_patient +0009 1081 SL 1 GE Advance ImageSet.number_of_normals +0009 1082 UI 1 GE Advance ImageSet.color_map_id +0009 1083 SL 1 GE Advance ImageSet.window_level_type +0009 1084 FL 1 GE Advance ImageSet.rotate +0009 1085 SL 1 GE Advance ImageSet.flip +0009 1086 FL 1 GE Advance ImageSet.zoom +0009 1087 SL 1 GE Advance ImageSet.pan_x +0009 1088 SL 1 GE Advance ImageSet.pan_y +0009 1089 FL 1 GE Advance ImageSet.window_level_min +0009 108a FL 1 GE Advance ImageSet.window_level_max +0009 108b SL 1 GE Advance ImageSet.recon_method +0009 108c SL 1 GE Advance ImageSet.attenuation +0009 108d FL 1 GE Advance ImageSet.atten_coefficient +0009 108e SL 1 GE Advance ImageSet.bp_filter +0009 108f FL 1 GE Advance ImageSet.bp_filter_cutoff +0009 1090 SL 1 GE Advance ImageSet.bp_filter_order +0009 1091 FL 1 GE Advance ImageSet.bp_center_l +0009 1092 FL 1 GE Advance ImageSet.bp_center_p +0009 1093 SL 1 GE Advance ImageSet.atten_smooth +0009 1094 SL 1 GE Advance ImageSet.atten_smooth_param +0009 1095 SL 1 GE Advance ImageSet.angle_smooth_param +0009 1096 UI 1 GE Advance ImageSet.wellcountercal_id +0009 1097 UI 1 GE Advance ImageSet.trans_scan_id +0009 1098 UI 1 GE Advance ImageSet.norm_cal_id +0009 1099 UI 1 GE Advance ImageSet.blnk_cal_id +0009 109a FL 1 GE Advance ImageSet.cac_edge_threshold +0009 109b FL 1 GE Advance ImageSet.cac_skull_offset +0009 109c UI 1 GE Advance ImageSet.emiss_sub_id +0009 109d SL 1 GE Advance ImageSet.radial_filter_3d +0009 109e FL 1 GE Advance ImageSet.radial_cutoff_3d +0009 109f SL 1 GE Advance ImageSet.axial_filter_3d +0009 10a0 FL 1 GE Advance ImageSet.axial_cutoff_3d +0009 10a1 FL 1 GE Advance ImageSet.axial_start +0009 10a2 FL 1 GE Advance ImageSet.axial_spacing +0009 10a3 SL 1 GE Advance ImageSet.axial_angles_used +0009 10b2 SL 1 GE Advance ImageSet.ir_num_iterations +0009 10b3 SL 1 GE Advance ImageSet.ir_num_subsets +0009 10b4 FL 1 GE Advance ImageSet.ir_recon_fov +0009 10b5 SL 1 GE Advance ImageSet.ir_corr_model +0009 10b6 SL 1 GE Advance ImageSet.ir_loop_filter +0009 10b7 FL 1 GE Advance ImageSet.ir_pre_filt_parm +0009 10b8 SL 1 GE Advance ImageSet.ir_loop_filt_parm +0009 10b9 FL 1 GE Advance ImageSet.response_filt_parm +0009 10ba SL 1 GE Advance ImageSet.post_filter +0009 10bb FL 1 GE Advance ImageSet.post_filt_parm +0009 10bc SL 1 GE Advance ImageSet.ir_regularize +0009 10bd FL 1 GE Advance ImageSet.regularize_parm +0009 10be SL 1 GE Advance ImageSet.ac_bp_filter +0009 10bf FL 1 GE Advance ImageSet.ac_bp_filt_cut_off +0009 10c0 SL 1 GE Advance ImageSet.ac_bp_filt_order +0009 10c1 SL 1 GE Advance ImageSet.ac_img_smooth +0009 10c2 FL 1 GE Advance ImageSet.ac_img_smooth_parm +0009 10c3 SL 1 GE Advance ImageSet.scatter_method +0009 10c4 SL 1 GE Advance ImageSet.scatter_num_iter +0009 10c5 FL 1 GE Advance ImageSet.scatter_parm +0009 10a4 SH 1 GE Advance Image.compatible_version +0009 10a5 SH 1 GE Advance Image.software_version +0009 10a6 SL 1 GE Advance Image.slice_number +0009 10a7 FL 1 GE Advance Image.total_counts +0009 10a8 OB 1 GE Advance Image.other_atts +0009 10a9 SL 1 GE Advance Image.other_atts_size +0009 10aa SL 1 GE Advance Image.archived +0009 10ab FL 1 GE Advance Image.bp_center_x +0009 10ac FL 1 GE Advance Image.bp_center_y +0009 10ad UI 1 GE Advance Image.trans_frame_id +0009 10ae UI 1 GE Advance Image.tpluse_frame_id +0009 10c6 FL 1 GE Advance Image.seg_qc_parm +0009 10c7 SL 1 GE Advance Image.overlap +0009 10c8 UI 1 GE Advance Image.ovlp_frm_id +0009 10c9 UI 1 GE Advance Image.ovlp_trans_frm_id +0009 10ca UI 1 GE Advance Image.ovlp_tpulse_frm_id +0011 0010 SH 1 Private Creator Data Element +0011 1001 SQ 1 GE Advance ROI Sequence +0011 1002 UI 1 > GE Advance ROI.roi_id +0011 1003 UI 1 > GE Advance ROI.image_id +0011 1004 SH 1 > GE Advance ROI.compatible_version +0011 1005 SH 1 > GE Advance ROI.software_version +0011 1006 LO 1 > GE Advance ROI.roi_name +0011 1007 DT 1 > GE Advance ROI.roi_datetime +0011 1008 SL 1 > GE Advance ROI.roi_type +0011 1009 FL 1 > GE Advance ROI.center_x +0011 100a FL 1 > GE Advance ROI.center_y +0011 100b FL 1 > GE Advance ROI.width +0011 100c FL 1 > GE Advance ROI.height +0011 100d FL 1 > GE Advance ROI.angle +0011 100e SL 1 > GE Advance ROI.number_of_points +0011 100f OB 1 > GE Advance ROI.roi_data +0011 1010 SL 1 > GE Advance ROI.roi_size +0011 1011 LO 1 > GE Advance ROI.color +0011 1012 SL 1 > GE Advance ROI.line_type +0011 1013 SL 1 > GE Advance ROI.line_width +0011 1014 SL 1 > GE Advance ROI.roi_number +0011 1015 SL 1 > GE Advance ROI.convex +0011 1016 SL 1 > GE Advance ROI.atten_corr_flag +0013 0010 SH 1 Private Creator Data Element +0013 1001 SQ 1 GE Advance Annotation Sequence +0013 1002 UI 1 > GE Advance Annotation.annotation_id +0013 1003 UI 1 > GE Advance Annotation.image_id +0013 1004 SH 1 > GE Advance Annotation.compatible_version +0013 1005 SH 1 > GE Advance Annotation.software_version +0013 1006 SL 1 > GE Advance Annotation.type +0013 1007 LO 1 > GE Advance Annotation.font_name +0013 1008 SH 1 > GE Advance Annotation.font_size +0013 1009 LO 1 > GE Advance Annotation.foreground_color +0013 100a LO 1 > GE Advance Annotation.background_color +0013 100b SL 1 > GE Advance Annotation.coordinate_system +0013 100c FL 1 > GE Advance Annotation.start_x +0013 100d FL 1 > GE Advance Annotation.start_y +0013 100e FL 1 > GE Advance Annotation.end_x +0013 100f FL 1 > GE Advance Annotation.end_y +0013 1010 SL 1 > GE Advance Annotation.start_symbol +0013 1011 SL 1 > GE Advance Annotation.end_symbol +0013 1012 OB 1 > GE Advance Annotation.annotation_data +0013 1013 SL 1 > GE Advance Annotation.annotation_size +0013 1014 LO 1 > GE Advance Annotation.label_id +5001 0010 SH 1 Private Creator Data Element +5001 1001 UI 1 GE Advance Curve.curve_id +5001 1002 SH 1 GE Advance Curve.compatible_version +5001 1003 SH 1 GE Advance Curve.software_version +5001 1004 SL 1 GE Advance Curve.statistics_type +5001 1005 LT 1 GE Advance Curve.how_derived +5001 1006 SL 1 GE Advance Curve.how_derived_size +5001 1007 SL 1 GE Advance Curve.multi_patient +5001 1008 SL 1 GE Advance Curve.deadtime +5003 0010 SH 1 Private Creator Data Element +5003 1001 SQ 1 GE Advance Graph Sequence +5003 1002 UI 1 > GE Advance Graph.graph_id +5003 1003 SH 1 > GE Advance Graph.compatible_version +5003 1004 SH 1 > GE Advance Graph.software_version +5003 1005 LO 1 > GE Advance Graph.title +5003 1006 DT 1 > GE Advance Graph.graph_datetime +5003 1007 ST 1 > GE Advance Graph.graph_description +5003 1008 LO 1 > GE Advance Graph.title_font_name +5003 1009 SH 1 > GE Advance Graph.title_font_size +5003 100a LO 1 > GE Advance Graph.footer +5003 100b SH 1 > GE Advance Graph.footer_font_size +5003 100c LO 1 > GE Advance Graph.foreground_color +5003 100d LO 1 > GE Advance Graph.background_color +5003 100e SL 1 > GE Advance Graph.graph_border +5003 100f SL 1 > GE Advance Graph.graph_width +5003 1010 SL 1 > GE Advance Graph.graph_height +5003 1011 SL 1 > GE Advance Graph.grid +5003 1012 LO 1 > GE Advance Graph.label_font_name +5003 1013 SH 1 > GE Advance Graph.label_font_size +5003 1014 LO 1 > GE Advance Graph.axes_color +5003 1015 LO 1 > GE Advance Graph.x_axis_label +5003 1016 SL 1 > GE Advance Graph.x_axis_units +5003 1017 FL 1 > GE Advance Graph.x_major_tics +5003 1018 FL 1 > GE Advance Graph.x_axis_min +5003 1019 FL 1 > GE Advance Graph.x_axis_max +5003 101a LO 1 > GE Advance Graph.y_axis_label +5003 101b SL 1 > GE Advance Graph.y_axis_units +5003 101c FL 1 > GE Advance Graph.y_major_tics +5003 101d FL 1 > GE Advance Graph.y_axis_min +5003 101e FL 1 > GE Advance Graph.y_axis_max +5003 101f LO 1 > GE Advance Graph.legend_font_name +5003 1020 SH 1 > GE Advance Graph.legend_font_size +5003 1021 SL 1 > GE Advance Graph.legend_location_x +5003 1022 SL 1 > GE Advance Graph.legend_location_y +5003 1023 SL 1 > GE Advance Graph.legend_width +5003 1024 SL 1 > GE Advance Graph.legend_height +5003 1025 SL 1 > GE Advance Graph.legend_border +5003 1026 SL 1 > GE Advance Graph.multi_patient +5005 0010 SH 1 Private Creator Data Element +5005 1001 SQ 1 GE Advance CurvePresentation Sequence +5005 1002 UI 1 > GE Advance CurvePresentation.curvepresent_id +5005 1003 UI 1 > GE Advance CurvePresentation.graph_id +5005 1004 UI 1 > GE Advance CurvePresentation.curve_id +5005 1005 SH 1 > GE Advance CurvePresentation.compatible_version +5005 1006 SH 1 > GE Advance CurvePresentation.software_version +5005 1007 LO 1 > GE Advance CurvePresentation.curve_label +5005 1008 LO 1 > GE Advance CurvePresentation.color +5005 1009 SL 1 > GE Advance CurvePresentation.line_type +5005 100a SL 1 > GE Advance CurvePresentation.line_width +5005 100b SL 1 > GE Advance CurvePresentation.point_symbol +5005 100c SL 1 > GE Advance CurvePresentation.point_symbol_dim +5005 100d LO 1 > GE Advance CurvePresentation.point_color diff --git a/Utilities/ITK/Utilities/gdcm/Dicts/GEMS-Advantx.dic b/Utilities/ITK/Utilities/gdcm/Dicts/GEMS-Advantx.dic new file mode 100644 index 0000000000000000000000000000000000000000..ac7dc921d43ce50915d6577e8148127b93fac529 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/Dicts/GEMS-Advantx.dic @@ -0,0 +1,35 @@ +0011 00xx LO 1 Private Creator PATIENT_01 +0011 xx01 LT 1 Patient DOB +0015 00xx LO 1 Private Creator EXAM_01 +0015 xx01 DS 1 Stenos_calibr_ratio +0015 xx02 DS 1 Stenos_magnification +0015 xx03 DS 1 Cardiac_calibr_ratio +0019 00xx LO 1 Private Creator SERIE_01 +0019 xx01 DS 1 Angle_value_1 +0019 xx02 DS 1 Angle_value_2 +0019 xx03 DS 1 Angle_value_3 +0019 xx04 CS 1 Angle_label_1 +0019 xx05 CS 1 Angle_label_2 +0019 xx06 CS 1 Angle_label_3 +0019 xx07 ST 1 Adx_procedure_name +0019 xx08 ST 1 Adx_exam_name +0019 xx09 SH 1 Adx_patient_size +0019 000A IS 1 Acq_record view +0019 xx10 DS 1 Adx_injector_delay +0019 xx11 CS 1 Adx_auto_inject +0019 xx14 IS 1 Adx_acq_mod +0019 xx15 CS 1 Adx_camera_rotation_enable +0019 xx16 CS 1 Adx_reverse_sweep +0019 xx17 IS 1 Cur_spatial_filter_strength +0019 xx18 IS 1 Zoom_factor +0019 xx19 IS 1 X_zoom +0019 xx1A IS 1 Y_zoom +0019 xx1B DS 1 Adx_focus +0019 xx1C CS 1 Adx_dose +0019 xx1D IS 1 Side_mark +0019 xx1E IS 1 Percentage_landscape +0019 xx1F DS 1 Adx_exposure_duration +70nn 00xx LO 1 Private Creator ANNOT_01 +70nn xx04 ST 1 Text_annotation +70nn xx05 IS 2 Box +70nn xx07 IS 2 Arrow end diff --git a/Utilities/ITK/Utilities/gdcm/Dicts/GEMS-CR.dic b/Utilities/ITK/Utilities/gdcm/Dicts/GEMS-CR.dic new file mode 100644 index 0000000000000000000000000000000000000000..f4b91a6027b2af3eaa16de417e2be4c7e38425ec --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/Dicts/GEMS-CR.dic @@ -0,0 +1,33 @@ +0023 0010 LO 1 Private Creator +0023 1000 LO 1 CR Exposure Menu Code +0023 1010 LO 1 CR Exposure Menu String +0023 1020 LO 1 CR EDR Mode +0023 1030 LO 1 CR Latitude +0023 1040 LO 1 CR Group Number +0023 1050 LO 1 CR Image Serial Number +0023 1060 LO 1 CR Bar Code Number +0023 1070 LO 1 CR Film Output Exposure +0023 1080 LO 1 CR Film Format +0023 1090 LO 1 CR S-Shift String +0023 2000 SS 1 CR S-Shift +0023 2010 LO 1 CR C-Shift +0023 2020 LO 1 CR GT +0023 2030 LO 1 CR GA +0023 2040 LO 1 CR GC +0023 2050 LO 1 CR GS +0023 2060 LO 1 CR RT +0023 2070 LO 1 CR RE +0023 2080 US 1 CR RN +0023 2090 LO 1 CR DRT +0023 3000 LO 1 CR DRE +0023 3010 US 1 CR DRN +0023 3020 LO 1 CR ORE +0023 3030 SS 1 CR ORN +0023 3040 SS 1 CR ORD +0023 3050 LO 1 CR Cassette Size +0023 3060 LO 1 CR Machine ID +0023 3070 LO 1 CR Machine Type +0023 3080 LO 1 CR Technician Code +0023 3090 LO 1 CR Energy Subtraction value +0023 30f0 LO 1 CR Distribution Code +0023 30ff US 1 CR Shutters Applied diff --git a/Utilities/ITK/Utilities/gdcm/Dicts/GEMS-DLX.dic b/Utilities/ITK/Utilities/gdcm/Dicts/GEMS-DLX.dic new file mode 100644 index 0000000000000000000000000000000000000000..64e832596a77a3d09d93e6429096def564c951c8 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/Dicts/GEMS-DLX.dic @@ -0,0 +1,29 @@ +0011 1001 LT 1 Patient DOB +0015 1001 DS 1 Stenosis Calibration Ratio +0015 1002 DS 1 Stenosis Magnification +0015 1003 DS 1 Cardiac Calibration Ratio + +0019 1001 DS 1 Angle Value L Arm +0019 1002 DS 1 Angle Value P Arm +0019 1003 DS 1 Angle Value C Arm +0019 1004 CS 1 Angle Label L Arm +0019 1005 CS 1 Angle Label P Arm +0019 1006 CS 1 Angle Label C Arm +0019 1007 ST 1 Adx Procedure Name +0019 1008 ST 1 Adx Exam Name +0019 1009 SH 1 Adx Patient Size +0019 100a IS 1 Acquisition Record View +0019 1010 DS 1 Adx Injector Delay +0019 1011 CS 1 Adx Auto Inject +0019 1014 IS 1 Adx Acquisition Mode +0019 1015 CS 1 Adx Camera Rotation Enabled +0019 1016 CS 1 Adx Reverse Sweep +0019 1017 IS 1 Cur Spatial Filter Strength +0019 1018 IS 1 Zoom Factor +0019 1019 IS 1 X Zoom +0019 101a IS 1 Y Zoom +0019 101b DS 1 Adx Focus +0019 101c CS 1 Adx Dose +0019 101d IS 1 Side Mark +0019 101e IS 1 Percentage Landscape +0019 101f DS 1 Adx Exposure Duration diff --git a/Utilities/ITK/Utilities/gdcm/Dicts/GEMS-Genie.dic b/Utilities/ITK/Utilities/gdcm/Dicts/GEMS-Genie.dic new file mode 100644 index 0000000000000000000000000000000000000000..303948d6de2b92dbe324c25761df59642812afaa --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/Dicts/GEMS-Genie.dic @@ -0,0 +1,87 @@ +0009 0010 LO 1 Private Creator Identification +0009 xx11 SL 1 Study Flags +0009 xx12 SL 1 Study Type +0009 xx21 SL 1 Series Flags +0009 xx22 SH 1 User Orientation +0009 xx23 SL 1 Initiation Type +0009 xx24 SL 1 Initiation Delay +0009 xx25 SL 1 Initiation Count Rate +0009 xx26 SL 1 Number Energy Sets +0009 xx27 SL 1 Number Detectors +0009 xx2c LO 1 Series Comments +0009 xx2d SL 1 Track Beat Average +0009 xx2e FD 1 Distance Prescribed +0009 xx35 SL 1 Gantry Locus Type +0009 xx37 SL 1 Starting Heart Rate +0009 xx38 SL 1 RR Window Width +0009 xx39 SL 1 RR Window Offset +0009 xx3a SL 1 Percent Cycle Imaged +0009 xx40 PN 1 Patient Object Name +0009 xx41 SL 1 Patient Flags +0009 xx42 DA 1 Patient Creation Date +0009 xx43 TM 1 Patient Creation Time +0011 0010 LO 1 Private Creator Identification +0011 xx0a SL 1 Series Type +0011 xx0b SL 1 Effective Series Duration +0011 xx0c SL 1 Num Beats +0011 xx0d LO 1 Radio Nuclide Name +0011 xx12 LO 1 Dataset Name +0011 xx13 SL 1 Dataset Type +0011 xx15 SL 1 Detector Number +0011 xx16 SL 1 Energy Number +0011 xx17 SL 1 RR Interval Window Number +0011 xx18 SL 1 MG Bin Number +0011 xx19 FD 1 Radius Of Rotation +0011 xx1a SL 1 Detector Count Zone +0011 xx1b SL 1 Num Energy Windows +0011 xx1c SL 4 Energy Offset +0011 xx1d SL 1 Energy Range +0011 xx1f SL 1 Image Orientation +0011 xx23 SL 1 Use FOV Mask +0011 xx24 SL 1 FOV Mask Y Cutoff Angle +0011 xx25 SL 1 FOV Mask Cutoff Angle +0011 xx26 SL 1 Table Orientation +0011 xx27 SL 2 ROI Top Left +0011 xx28 SL 2 ROI Bottom Right +0011 xx33 LO 1 Energy Correct Name +0011 xx34 LO 1 Spatial Correct Name +0011 xx35 LO 1 Tuning Calib Name +0011 xx36 LO 1 Uniformity Correct Name +0011 xx37 LT 1 Acquisition Specific Correction Name +0011 xx38 SL 1 Byte Order +0011 xx3a SL 1 Picture Format +0011 xx3b FD 1 Pixel Scale +0011 xx3c FD 1 Pixel Offset +0011 xx3e SL 1 FOV Shape +0011 xx3f SL 1 Dataset Flags +0011 xx44 FD 1 Threshold Center +0011 xx45 FD 1 Threshold Width +0011 xx46 SL 1 Interpolation Type +0011 xx55 FD 1 Period +0011 xx56 FD 1 Elapsed Time +0013 0010 LO 1 Private Creator Identification +0013 xx10 FD 2 Digital FOV +0013 xx11 SL 1 Source Translator +0013 xx16 SL 1 AutoTrack Peak +0013 xx17 SL 1 AutoTrack Width +0013 xx18 FD 1 Transmission Scan Time +0013 xx19 FD 1 Transmission Mask Width +0013 xx1a FD 1 Copper Attenuator Thickness +0013 xx1e FD 1-n Tomo View Offset +0013 xx26 LT 1 Study Comments +0033 xx08 CS 1 GENIE Data Object Type +0033 xx10 SL 1 Modified +0033 xx11 LO 1 Name +0033 xx16 LO 1 ProtocolDataUID +0033 xx17 SH 1 Date +0033 xx18 SH 1 Time +0033 xx19 UL 1 ProtocoldataFlags +0033 xx1A UL 1 ProtocolName +0033 xx1B LO 1 RelevantDataUID +0033 xx1C LO 1 BulkData +0033 xx1D SL 1-n IntData +0033 xx1E FD 1-n DoubleData +0033 xx1F LT 1-n StringData +0033 xx20 LT 1-n BulkDataFormat +0033 xx23 LT 1-n StringDataFormat +0033 xx24 LT 1 Description diff --git a/Utilities/ITK/Utilities/gdcm/Dicts/GEMS-HiSpeed.dic b/Utilities/ITK/Utilities/gdcm/Dicts/GEMS-HiSpeed.dic new file mode 100644 index 0000000000000000000000000000000000000000..68999f670562a6469b75100abb7d28a2c2375cce --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/Dicts/GEMS-HiSpeed.dic @@ -0,0 +1,34 @@ +0009 1031 SH 1 Mobile Location Code +0019 1002 SL 1 Detector Channel +0019 1023 DS 1 Table Speed +0019 1024 DS 1 mid scan time +0019 1026 SL 1 Tube Azimuth +0019 1027 DS 1 Gantry Velocity +0019 1039 SS 1 SFOV Type +0019 1042 SS 1 Segment number +0019 1043 SS 1 Total segments required +0043 1012 SS 3 X-Ray Chain +0043 101e DS 1 Delta start time +0043 1035 US 1 Infant indicator +0043 1036 CS 1 language +0043 1037 CS 1 Gantry type +0043 1038 SH 1 Raw data ID +0043 1039 IS 1 Reconstruction Matrix +0043 1040 CS 1-n Image Filter +0043 1041 US 1 Prospective Addition Indicator +0043 1043 US 1 Motion Correction Indicator +0043 1044 US 1 Helical Correction Indicator +0043 1045 US 1 Cine Correction Indicator +0043 1046 US 1 IBO Correction Indicator +0043 1047 US 1 BBH Correction Indicator +0043 1048 US 1 Advanced Noise Reduction Indicator +0043 1049 US 1 Scatter Correction Indicator +0043 104a DS 3 Recon Center Coordinates +0043 1050 US 1 Cross-Talk Correction Indicator +0043 1051 US 1 Q-Cal Correction Indicator +0043 1052 US 1 Afterglow Correction Indicator +0043 1053 US 1 Local Decon Correction Indicator +0043 1054 DS 1 Scan Start Location +0043 1055 DS 1 Scan End Location +0043 1056 IS 1 Detector Row +0043 1057 CS 1 Tube Focus diff --git a/Utilities/ITK/Utilities/gdcm/Dicts/GEMS-Infinia.dic b/Utilities/ITK/Utilities/gdcm/Dicts/GEMS-Infinia.dic new file mode 100644 index 0000000000000000000000000000000000000000..654357775edf8666d4d352e78283434d06b8c831 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/Dicts/GEMS-Infinia.dic @@ -0,0 +1,87 @@ +0009 xx10 LO 1 Study Name +0009 xx11 SL 1 Study Flags +0009 xx12 SL 1 Study Type + + + + + + + + + + + + + + + +0009 xx40 PN 1 Patient Object Name +0009 xx41 SL 1 Patient Flags +0009 xx42 DA 1 Patient Creation Date +0009 xx43 TM 1 Patient Creation Time + + + + +0011 xx0d LO 1 Radio Nuclide Name +0011 xx12 LO 1 Dataset Name + +0011 xx15 SL 1 Detector Number + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +0013 xx11 SL 1 Source Translator + + + + + + +0013 xx26 LT 1 Study Comments +0033 xx08 CS 1 GENIE Data Object Type +0033 xx10 SL 1 Modified +0033 xx11 LO 1 Name +0033 xx16 LO 1 ProtocolDataUID +0033 xx17 SH 1 Date +0033 xx18 SH 1 Time +0033 xx19 UL 1 ProtocoldataFlags +0033 xx1A UL 1 ProtocolName +0033 xx1B LO 1 RelevantDataUID +0033 xx1C LO 1 BulkData +0033 xx1D SL 1-n IntData +0033 xx1E FD 1-n DoubleData +0033 xx1F LT 1-n StringData +0033 xx20 LT 1-n BulkDataFormat +0033 xx23 LT 1-n StringDataFormat +0033 xx24 LT 1 Description diff --git a/Utilities/ITK/Utilities/gdcm/Dicts/GEMS.dic b/Utilities/ITK/Utilities/gdcm/Dicts/GEMS.dic new file mode 100644 index 0000000000000000000000000000000000000000..bdcc7b6c20cd584725505116fe58edf2e72d0743 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/Dicts/GEMS.dic @@ -0,0 +1,394 @@ +0009 0000 UL 1 Group Length +0009 0010 LO 1 Private Creator Identification (GEMS_IDEN_01) +0009 1001 LO 1 Full fidelity +0009 1002 SH 1 Suite id +0009 1004 SH 1 Product id +0009 1027 SL 1 Image actual date +0009 1030 SH 1 Service id +0009 1031 SH 1 Mobile location number +0009 10e3 UI 1 Equipment UID +0009 10e6 SH 1 Genesis Version - now +0009 10e7 UL 1 Exam Record checksum +0009 10e9 SL 1 Actual series data time stamp + +0011 0000 UL 1 Group Length +0011 0010 LO 1 Private Creator Identification (GEMS_PATI_01) +0011 1010 SS 1 Patient Status + +0019 0000 UL 1 Group Length +0019 0010 LO 1 Private Creator Identification (GEMS_ACQU_01) +0019 1002 SL 1 Number of cells I in Detector +0019 1003 DS 1 Cell number at Theta +0019 1004 DS 1 Cell spacing +0019 100f DS 1 Horiz. Frame of ref. +0019 1011 SS 1 Series contrast +0019 1012 SS 1 Last pseq +0019 1013 SS 1 Start number for baseline +0019 1014 SS 1 End number for baseline +0019 1015 SS 1 Start number for enhanced scans +0019 1016 SS 1 End number for enhanced scans +0019 1017 SS 1 Series plane +0019 1018 LO 1 First scan ras +0019 1019 DS 1 First scan location +0019 101a LO 1 Last scan ras +0019 101b DS 1 Last scan loc +0019 101e DS 1 Display field of view +0019 1023 DS 1 Table speed +0019 1024 DS 1 Mid scan time +0019 1025 SS 1 Mid scan flag +0019 1026 SL 1 Degrees of azimuth +0019 1027 DS 1 Gantry period +0019 102a DS 1 x-ray On position +0019 102b DS 1 x-ray Off position +0019 102c SL 1 Number of triggers +0019 102e DS 1 Angle of first view +0019 102f DS 1 Trigger frequency +0019 1039 SS 1 Scan FOV type +0019 1040 SS 1 Stat recon flag +0019 1041 SS 1 Compute type +0019 1042 SS 1 Segment number +0019 1043 SS 1 Total segments requested +0019 1044 DS 1 Interscan delay +0019 1047 SS 1 View compression factor +0019 104a SS 1 Total no. of ref channels +0019 104b SL 1 Data size for scan data +0019 1052 SS 1 Recon post proc. Flag +0019 1057 SS 1 CT water number +0019 1058 SS 1 CT bone number +0019 105a FL 1 Acquisition Duration +0019 105e SL 1 Number of channels (1...512) +0019 105f SL 1 Increment between channels +0019 1060 SL 1 Starting view +0019 1061 SL 1 Number of views +0019 1062 SL 1 Increment between views +0019 106a SS 1 Dependent on #views processed +0019 106b SS 1 Field of view in detector cells +0019 1070 SS 1 Value of back projection button +0019 1071 SS 1 Set if fatq estimates were used +0019 1072 DS 1 Z chan avg over views +0019 1073 DS 1 Avg of left ref chans over views +0019 1074 DS 1 Max left chan over views +0019 1075 DS 1 Avg of right ref chans over views +0019 1076 DS 1 Max right chan over views +0019 107d DS 1 Second echo +0019 107e SS 1 Number of echoes +0019 107f DS 1 Table delta +0019 1081 SS 1 Contiguous +0019 1084 DS 1 Peak SAR +0019 1085 SS 1 Monitor SAR +0019 1087 DS 1 Cardiac repetition time +0019 1088 SS 1 Images per cardiac cycle +0019 108a SS 1 Actual receive gain analog +0019 108b SS 1 Actual receive gain digital +0019 108d DS 1 Delay after trigger +0019 108f SS 1 Swappf +0019 1090 SS 1 Pause Interval +0019 1091 DS 1 Pulse Time +0019 1092 SL 1 Slice offset on freq axis +0019 1093 DS 1 Center Frequency +0019 1094 SS 1 Transmit Gain +0019 1095 SS 1 Analog receiver gain +0019 1096 SS 1 Digital receiver gain +0019 1097 SL 1 Bitmap defining CVs +0019 1098 SS 1 Center freq. Method +0019 109b SS 1 Pulse seq. Mode +0019 109c LO 1 Pulse seq. Name +0019 109d DT 1 Pulse seq. Date +0019 109e LO 1 Internal pulse seq. Name +0019 109f SS 1 Transmitting coil +0019 10a0 SS 1 Surface Coil Type +0019 10a1 SS 1 Extremity Coil flag +0019 10a2 SL 1 Raw data run number +0019 10a3 UL 1 Calibrated Field strength +0019 10a4 SS 1 SAT fat/water/bone +0019 10a5 DS 1 Receive bandwidth +0019 10a7 DS 1 User data +0019 10a8 DS 1 User data +0019 10a9 DS 1 User data +0019 10aa DS 1 User data +0019 10ab DS 1 User data +0019 10ac DS 1 User data +0019 10ad DS 1 User data +0019 10ae DS 1 User data +0019 10af DS 1 User data +0019 10b0 DS 1 User data +0019 10b1 DS 1 User data +0019 10b2 DS 1 User data +0019 10b3 DS 1 User data +0019 10b4 DS 1 User data +0019 10b5 DS 1 User data +0019 10b6 DS 1 User data +0019 10b7 DS 1 User data +0019 10b8 DS 1 User data +0019 10b9 DS 1 User data +0019 10ba DS 1 User data +0019 10bb DS 1 User data +0019 10bc DS 1 User data +0019 10bd DS 1 User data +0019 10be DS 1 Projection angle +0019 10c0 SS 1 Saturation planes +0019 10c1 SS 1 Surface coil intensity +0019 10c2 SS 1 SAT location R +0019 10c3 SS 1 SAT location L +0019 10c4 SS 1 SAT location A +0019 10c5 SS 1 SAT location P +0019 10c6 SS 1 SAT location H +0019 10c7 SS 1 SAT location F +0019 10c8 SS 1 SAT thickness R/L +0019 10c9 SS 1 SAT thickness A/P +0019 10ca SS 1 SAT thickness H/F +0019 10cb SS 1 Prescribed flow axis +0019 10cc SS 1 Velocity encoding +0019 10cd SS 1 Thickness disclaimer +0019 10ce SS 1 Prescan type +0019 10cf SS 1 Prescan status +0019 10d0 SH 1 Raw data type +0019 10d2 SS 1 Projection Algorithm +0019 10d3 SH 1 Projection algorithm +0019 10d5 SS 1 Fractional echo +0019 10d6 SS 1 Prep pulse +0019 10d7 SS 1 Cardiac phases +0019 10d8 SS 1 Variable echoflag +0019 10d9 DS 1 Concatenated SAT +0019 10da SS 1 Reference channel used +0019 10db DS 1 Back projector coefficient +0019 10dc SS 1 Primary speed correction used +0019 10dd SS 1 Overrange correction used +0019 10de DS 1 Dynamic Z alpha value +0019 10df DS 1 User data +0019 10e0 DS 1 User data +0019 10e2 DS 1 Velocity Encode Scale +0019 10f2 SS 1 Fast phases +0019 10f9 DS 1 Transmission gain + +0021 0000 UL 1 Group Length +0021 0010 LO 1 Private Creator Identification (GEMS_RELA_01) +0021 1003 SS 1 Series from which Prescribed +0021 1005 SH 1 Genesis Version - now +0021 1007 UL 1 Series Record checksum +0021 1018 SH 1 Genesis version - Now +0021 1019 UL 1 Acq recon record checksum +0021 1019 UL 1 Acqrecon record checksum +0021 1020 DS 1 Table start location +0021 1035 SS 1 Series from which prescribed +0021 1036 SS 1 Image from which prescribed +0021 1037 SS 1 Screen Format +0021 104a LO 1 Anatomical reference for scout +0021 104f SS 1 Locations in acquisition +0021 1050 SS 1 Graphically prescribed +0021 1051 DS 1 Rotation from source x rot +0021 1052 DS 1 Rotation from source y rot +0021 1053 DS 1 Rotation from source z rot +0021 1054 SH 3 Image position +0021 1055 SH 6 Image orientation +0021 1056 SL 1 Integer slop +0021 1057 SL 1 Integer slop +0021 1058 SL 1 Integer slop +0021 1059 SL 1 Integer slop +0021 105a SL 1 Integer slop +0021 105b DS 1 Float slop +0021 105c DS 1 Float slop +0021 105d DS 1 Float slop +0021 105e DS 1 Float slop +0021 105f DS 1 Float slop +0021 1081 DS 1 Auto window/level alpha +0021 1082 DS 1 Auto window/level beta +0021 1083 DS 1 Auto window/level window +0021 1084 DS 1 To window/level level +0021 1090 SS 1 Tube focal spot position +0021 1091 SS 1 Biopsy position +0021 1092 FL 1 Biopsy T location +0021 1093 FL 1 Biopsy ref location + +0023 0000 UL 1 Group Length +0023 0010 LO 1 Private Creator Identification (GEMS_STDY_01) +0023 1001 SL 1 Number of series in Study +0023 1002 SL 1 Number of unarchived Series +0023 1010 SS 1 Reference image field +0023 1050 SS 1 Summary image +0023 1070 FD 1 Start time(secs) in first axial +0023 1074 SL 1 No. of updates to header +0023 107d SS 1 Indicates if the study has complete info (DICOM/genesis) + +0025 0000 UL 1 Group Length +0025 0010 LO 1 Private Creator Identification (GEMS_SERS_01) +0025 1006 SS 1 Last pulse sequence used +0025 1007 SL 1 Images in Series +0025 1010 SL 1 Landmark Counter +0025 1011 SS 1 Number of Acquisitions +0025 1014 SL 1 Indicates no. of updates to header +0025 1017 SL 1 Series Complete Flag +0025 1018 SL 1 Number of images archived +0025 1019 SL 1 Last image number used +0025 101a SH 1 Primary Receiver Suite and Host + +0027 0000 UL 1 Group Length +0027 0010 LO 1 Private Creator Identification (GEMS_IMAG_01) +0027 1006 SL 1 Image archive flag +0027 1010 SS 1 Scout Type +0027 101c SL 1 Vma mamp +0027 101d SS 1 Vma phase +0027 101e SL 1 Vma mod +0027 101f SL 1 Vma clip +0027 1020 SS 1 Smart scan ON/OFF flag +0027 1030 SH 1 Foreign Image Revision +0027 1031 SS 1 Imaging Mode +0027 1032 SS 1 Pulse Sequence +0027 1033 SL 1 Imaging Options +0027 1035 SS 1 Plane Type +0027 1036 SL 1 Oblique Plane +0027 1040 SH 1 RAS letter of image location +0027 1041 FL 1 Image location +0027 1042 FL 1 Center R coord of plane image +0027 1043 FL 1 Center A coord of plane image +0027 1044 FL 1 Center S coord of plane image +0027 1045 FL 1 Normal R coord +0027 1046 FL 1 Normal A coord +0027 1047 FL 1 Normal S coord +0027 1048 FL 1 R Coord of Top Right Corner +0027 1049 FL 1 A Coord of Top Right Corner +0027 104a FL 1 S Coord of Top Right Corner +0027 104b FL 1 R Coord of Bottom Right Corner +0027 104c FL 1 A Coord of Bottom Right Corner +0027 104d FL 1 S Coord of Bottom Right Corner +0027 1050 FL 1 Table start location +0027 1051 FL 1 Table end location +0027 1052 SH 1 RAS letter for side of image +0027 1053 SH 1 RAS letter for anterior/posterior +0027 1054 SH 1 RAS letter for scout start loc +0027 1055 SH 1 RAS letter for scout end loc +0027 1060 FL 1 Image dimension - X +0027 1061 FL 1 Image dimension - Y +0027 1062 FL 1 Number of Excitations + +0029 0000 UL 1 Group Length +0029 0010 LO 1 Private Creator Identification (GEMS_IMPS_01) +0029 1004 SL 1 Lower range of Pixels1 +0029 1005 DS 1 Lower range of Pixels1 +0029 1006 DS 1 Lower range of Pixels1 +0029 1007 SL 1 Lower range of Pixels1 +0029 1008 SH 1 Lower range of Pixels1 +0029 1009 SH 1 Lower range of Pixels1 +0029 100a SS 1 Lower range of Pixels1 +0029 1015 SL 1 Lower range of Pixels1 +0029 1016 SL 1 Lower range of Pixels1 +0029 1017 SL 1 Lower range of Pixels2 +0029 1018 SL 1 Upper range of Pixels2 +0029 101a SL 1 Len of tot hdr in bytes +0029 1026 SS 1 Version of the hdr struct +0029 1034 SL 1 Advantage comp. Overflow +0029 1035 SL 1 Advantage comp. Underflow + +0043 0000 UL 1 Group Length +0043 0010 LO 1 Private Creator Identification (GEMS_PARM_01) +0043 1001 SS 1 Bitmap of prescan options +0043 1002 SS 1 Gradient offset in X +0043 1003 SS 1 Gradient offset in Y +0043 1004 SS 1 Gradient offset in Z +0043 1005 SS 1 Img is original or unoriginal +0043 1006 SS 1 Number of EPI shots +0043 1007 SS 1 Views per segment +0043 1008 SS 1 Respiratory rate, bpm +0043 1009 SS 1 Respiratory trigger point +0043 100a SS 1 Type of receiver used +0043 100b DS 1 Peak rate of change of gradient field +0043 100c DS 1 Limits in units of percent +0043 100d DS 1 PSD estimated limit +0043 100e DS 1 PSD estimated limit in tesla per second +0043 100f DS 1 Saravghead +0043 1010 US 1 Window value +0043 1011 US 1 Total input views +0043 1012 SS 3 X-ray chain +0043 1013 SS 5 Decon kernel parameters +0043 1014 SS 3 Calibration parameters +0043 1015 SS 3 Total output views +0043 1016 SS 5 Number of overranges +0043 1017 DS 1 IBH image scale factors +0043 1018 DS 3 BBH coefficients +0043 1019 SS 1 Number of BBH chains to blend +0043 101a SL 1 Starting channel number +0043 101b SS 1 Ppscan parameters +0043 101c SS 1 GE image integrity +0043 101d SS 1 Level value +0043 101e DS 1 Delta start time +0043 101f SL 1 Max overranges in a view +0043 1020 DS 1 Avg overranges all views +0043 1021 SS 1 Corrected after glow terms +0043 1025 SS 6 Reference channels +0043 1026 US 6 No views ref chans blocked +0043 1027 SH 1 Scan pitch ratio +0043 1028 OB 1 Unique image iden +0043 1029 OB 1 Histogram tables +0043 102a OB 1 User defined data +0043 102b SS 4 Private Scan Options +0043 102c SS 1 Effective echo spacing +0043 102d SH 1 String slop field 1 +0043 102e SH 1 String slop field 2 +0043 102f SS 1 Raw data type +0043 1030 SS 1 Raw data type +0043 1031 DS 2 RA cord of target recon center +0043 1032 SS 1 Vas flags +0043 1033 FL 1 Neg_scanspacing +0043 1034 IS 1 Offset Frequency +0043 1035 UL 1 User_usage_tag +0043 1036 UL 1 User_fill_map_MSW +0043 1037 UL 1 User_fill_map_LSW +0043 1038 FL 24 User25...User48 +0043 1039 IS 4 Slop_int_6... slop_int_9 +0043 1040 FL 4 Trigger on position +0043 1041 FL 4 Degree of rotation +0043 1042 SL 4 DAS trigger source +0043 1043 SL 4 DAS fpa gain +0043 1044 SL 4 DAS output source +0043 1045 SL 4 DAS ad input +0043 1046 SL 4 DAS cal mode +0043 1047 SL 4 DAS cal frequency +0043 1048 SL 4 DAS reg xm +0043 1049 SL 4 DAS auto zero +0043 104a SS 4 Starting channel of view +0043 104b SL 4 DAS xm pattern +0043 104c SS 4 TGGC trigger mode +0043 104d FL 4 Start scan to X-ray on delay +0043 104e FL 4 Duration of X-ray on +0043 1060 IS 8 slop_int_10...slop_int_17 +0043 1061 UI 1 Scanner Study Entity UID +0043 1062 SH 1 Scanner Study ID +0043 106f DS 3 Scanner Table Entry (single gradient coil systems only) +0043 106f DS 4 Scanner Table Entry + Gradient Coil Selected + +0045 0000 UL 1 Group Length +0045 0010 LO 1 Private Creator Identification (GEMS_HELIOS_01) +0045 1001 SS 1 Number of Macro Rows in Detector +0045 1002 FL 1 Macro width at ISO Center +0045 1003 SS 1 DAS type +0045 1004 SS 1 DAS gain +0045 1005 SS 1 DAS Temprature +0045 1006 CS 1 Table Direction +0045 1007 FL 1 Z smoothing Factor +0045 1008 SS 1 View Weighting Mode +0045 1009 SS 1 Sigma Row number +0045 100a FL 1 Minimum DAS value +0045 100b FL 1 Maximum Offset Value +0045 100c SS 1 Number of Views shifted +0045 100d SS 1 Z tracking Flag +0045 100e FL 1 Mean Z error +0045 100f FL 1 Z tracking Error +0045 1010 SS 1 Start View 2A +0045 1011 SS 1 Number of Views 2A +0045 1012 SS 1 Start View 1A +0045 1013 SS 1 Sigma Mode +0045 1014 SS 1 Number of Views 1A +0045 1015 SS 1 Start View 2B +0045 1016 SS 1 Number Views 2B +0045 1017 SS 1 Start View 1B +0045 1018 SS 1 Number of Views 1B +0045 1019 SS 1 Air Calibration Date +0045 101a SS 1 Air Calibration Time +0045 101b SS 1 Phantom Calibration Date +0045 101c SS 1 Phantom Calibration Time +0045 101d SS 1 Z Slope Calibration Date +0045 101e SS 1 Z Slope Calibration Time +0045 101f SS 1 Cross Talk Calibration Date +0045 1020 SS 1 Cross Talk Calibration Time +0045 1021 SS 1 Iterbone Flag +0045 1022 SS 1 Perisstaltic Flag diff --git a/Utilities/ITK/Utilities/gdcm/Dicts/HITACHI-MR-pronto.dic b/Utilities/ITK/Utilities/gdcm/Dicts/HITACHI-MR-pronto.dic new file mode 100644 index 0000000000000000000000000000000000000000..1881b4ff9b0e75fa75cac0956663db519075f5a5 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/Dicts/HITACHI-MR-pronto.dic @@ -0,0 +1,4 @@ +0009 0000 UL 1 Group Length +0009 0010 LO 1 Private Creator +0009 0011 LO 1 Private Creator +0009 1100 OB 1 Image ID Information diff --git a/Utilities/ITK/Utilities/gdcm/Dicts/NIH.dic b/Utilities/ITK/Utilities/gdcm/Dicts/NIH.dic new file mode 100644 index 0000000000000000000000000000000000000000..038703b9996cbfd89cec05f763c2b23682c0d4b5 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/Dicts/NIH.dic @@ -0,0 +1,15 @@ +0018 106b UI 1 Synchronization Frame of Reference (RET) +0028 0013 US 1 Instants (RET) +0028 0015 US 1 UsedNbX ACR Special (RET) +0028 0016 US 1 UsedNbY ACR Special (RET) +0028 0017 US 1 UsedNbZ ACR Special (RET) +0028 0018 US 1 UsedNbT ACR Special (RET) +0028 0122 US 1 Waveform Padding Value (RET) +0028 0199 US 1 Special Code (RET) +003a 0002 SQ 1 Waveform Sequence (RET) +003a 0103 CS 1 Data Value Representation (RET) +0040 0552 SQ 1 Specimen Description Sequence (RET) +0040 0553 ST 1 Specimen Description (RET) +0040 09f8 SQ 1 Vital Stain Code Sequence (RET) +0040 a16a ST 1 Bibliographics Citation (RET) +0040 a992 ST 1 Uniform Resource Locator (RET) diff --git a/Utilities/ITK/Utilities/gdcm/Dicts/PHILIPS-EasyVision.dic b/Utilities/ITK/Utilities/gdcm/Dicts/PHILIPS-EasyVision.dic new file mode 100644 index 0000000000000000000000000000000000000000..a41c6af108b45cde7459b43019722bc8266282a1 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/Dicts/PHILIPS-EasyVision.dic @@ -0,0 +1,3 @@ +0009 YY04 LO 1-n Image Data Consistence +0019 YY25 LO 1-n Original Pixel Data Quality +0029 YY25 LO 1-n Processed Pixel Data Quality diff --git a/Utilities/ITK/Utilities/gdcm/Dicts/PHILIPS-Intera.dic b/Utilities/ITK/Utilities/gdcm/Dicts/PHILIPS-Intera.dic new file mode 100644 index 0000000000000000000000000000000000000000..35d58bf4480eb9a5d57918a74449da60dacff400 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/Dicts/PHILIPS-Intera.dic @@ -0,0 +1,90 @@ +2001 0000 UL 1 Group Length +2001 0010 LO 1 Private Creator Group 2001 +2001 1001 FL 1 Chemical Shift +2001 1002 IS 1 Chemical Shift Number MR +2001 1003 FL 1 Diffusion B-Factor +2001 1004 CS 1 Diffusion Direction +2001 1006 CS 1 Image Enhanced +2001 1007 CS 1 Image Type ED ES +2001 1008 IS 1 Phase Number +2001 100a IS 1 Slice Number MR +2001 100b CS 1 Slice Orientation +2001 1011 FL 1 Diffusion Echo Time +2001 1012 CS 1 Dynamic Series +2001 1013 SL 1 EPI Factor +2001 1014 SL 1 Number of Echoes +2001 1015 SS 1 Number of Locations +2001 1016 SS 1 Number of PC Directions +2001 1017 SL 1 Number of Phases MR +2001 1018 SL 1 Number of Slices MR +2001 1019 CS 1 Partial Matrix Scanned +2001 101a FL 1-n PC Velocity +2001 101b FL 1 Prepulse Delay +2001 101c CS 1 Prepulse Type +2001 101d IS 1 Reconstruction Number MR +2001 101f CS 1 Respiration Sync +2001 1021 CS 1 SPIR +2001 1022 FL 1 Water Fat Shift +2001 1023 DS 1 Flip Angle Philips +2001 1025 SH 1 Echo Time Display MR +2001 102d SS 1 Stack Number of Slices +2001 1032 FL 1 Stack Radial Angle +2001 1033 CS 1 Stack Radial Axis +2001 1035 SS 1 Stack Slice Number +2001 1036 CS 1 Stack Type +2001 103f CS 1 Zoom Mode +2001 105f SQ 1 Stack Sequence +2001 1060 SL 1 Number of Stacks +2001 1063 CS 1 Examination Source +2001 107b IS 1 Acquisition Number +2001 1081 IS 1 Number of Dynamic Scans + +2001 00e0 LO 1 Private Creator Group 2001 +2001 e001 FL 1 Chemical Shift +2001 e002 IS 1 Chemical Shift Number MR +2001 e003 FL 1 Diffusion B-Factor +2001 e004 CS 1 Diffusion Direction +2001 e006 CS 1 Image Enhanced +2001 e007 CS 1 Image Type ED ES +2001 e008 IS 1 Phase Number +2001 e00a IS 1 Slice Number MR +2001 e00b CS 1 Slice Orientation +2001 e011 FL 1 Diffusion Echo Time +2001 e012 CS 1 Dynamic Series +2001 e013 SL 1 EPI Factor +2001 e014 SL 1 Number of Echoes +2001 e015 SS 1 Number of Locations +2001 e016 SS 1 Number of PC Directions +2001 e017 SL 1 Number of Phases MR +2001 e018 SL 1 Number of Slices MR +2001 e019 CS 1 Partial Matrix Scanned +2001 e01a FL 1-n PC Velocity +2001 e01b FL 1 Prepulse Delay +2001 e01c CS 1 Prepulse Type +2001 e01d IS 1 Reconstruction Number MR +2001 e01f CS 1 Respiration Sync +2001 e021 CS 1 SPIR +2001 e022 FL 1 Water Fat Shift +2001 e023 DS 1 Flip Angle Philips +2001 e025 SH 1 Echo Time Display MR +2001 e02d SS 1 Stack Number of Slices +2001 e032 FL 1 Stack Radial Angle +2001 e033 CS 1 Stack Radial Axis +2001 e035 SS 1 Stack Slice Number +2001 e036 CS 1 Stack Type +2001 e03f CS 1 Zoom Mode +2001 e05f SQ 1 Stack Sequence +2001 e060 SL 1 Number of Stacks +2001 e063 CS 1 Examination Source +2001 e07b IS 1 Acquisition Number +2001 e081 IS 1 Number of Dynamic Scans + +2005 0000 UL 1 Group Length +2005 0010 LO 1 Private Creator Group 2005 +2005 1005 CS 1 Synergy Reconstruction Type +2005 1020 SL 1 Number of Chemical Shifts +2005 10a1 CS 1 Syncra Scan Type + +2005 1083 SQ 1 Temporary SQ 1 +2005 1402 SQ 1 Temporary SQ 2 + diff --git a/Utilities/ITK/Utilities/gdcm/Dicts/Papyrus.dic b/Utilities/ITK/Utilities/gdcm/Dicts/Papyrus.dic new file mode 100644 index 0000000000000000000000000000000000000000..ee8ffad255070a407184e113ece02de5b4d3cd06 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/Dicts/Papyrus.dic @@ -0,0 +1,16 @@ +0041 0000 UL 1 Group Length +0041 0010 LO 1 Owner ID (PAPYRUS 3.0) +0041 1000 LT 1 Comments +0041 1010 SQ 1 Pointer Sequence +0041 1011 UL 1 Image Pointer +0041 1012 UL 1 Pixel Offset +0041 1013 SQ 1 Image Identifier Sequence +0041 1014 SQ 1 External PAPYRUS-File Reference Sequence +0041 1015 US 1 Number of images +0041 1021 UI 1 Referenced SOP Class UID +0041 1022 UI 1 Referenced SOP Instance UID +0041 1031 LO 1 Referenced File Name +0041 1032 LO 1-n Referenced File Path +0041 1041 UI 1 Referenced Image SOP Class UID +0041 1042 UI 1 Referenced Image SOP Instance UID +0041 1050 SQ 1 Image Sequence diff --git a/Utilities/ITK/Utilities/gdcm/Dicts/ParseDict.py b/Utilities/ITK/Utilities/gdcm/Dicts/ParseDict.py new file mode 100644 index 0000000000000000000000000000000000000000..2b3924245ab53897026a32b625fb2b949786f117 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/Dicts/ParseDict.py @@ -0,0 +1,735 @@ +#! /usr/bin/env python +""" +Let's write our own python parser to clean up the pdf (after +pdftotext of course). +Instructions: run pdftotext like this: + +$ pdftotext -f 9 -l 81 -raw -nopgbrk 04_06PU.PDF 04_06PU-3.txt + +then run the python parser like this: + +$ python ParseDict.py 04_06PU.txt dicomV3.dic +""" +import re,os + +""" +PdfTextParser takes as input a text file (produced by pdftotext) +and create as output a clean file (ready to be processed) by +DicomV3Expander +Warning: PdfTextParser does not expand: +- (xxxx,xxxx to xxxx) xxxxxxxxxxxx +or +- (12xx, 3456) comment... + +""" +class PdfTextParser: + # Cstor + def __init__(self): + self._InputFilename = '' + self._OutputFilename = '' + self._Infile = 0 + self._OutLines = [] + self._PreviousBuffers = [] + + def SetInputFileName(self,s): + self._InputFilename = s + + def SetOutputFileName(self,s): + self._OutputFilename = s + + # Function returning if s is a comment for sure + def IsAComment(self,s): + #print s, len(s) + if s == "Tag Name VR VM": + return True + elif s == "PS 3.6-2003": + return True + elif s == "PS 3.6-2004": + return True + patt = re.compile('^Page [0-9]+$') + if( patt.match(s) ): + return True + return False + + def IsAStartingLine(self,s): + patt = re.compile('^\\([0-9a-fA-Fx]+,[0-9a-fA-F]+\\) (.*)$') + if( patt.match(s) ): + return True + return False + + def IsAFullLine(self,s): + patt = re.compile('^\\([0-9a-fA-Fx]+,[0-9a-fA-F]+\\) (.*) [A-Z][A-Z] [0-9]$') + if( patt.match(s) ): + return True + return False + + # FIXME this function could be avoided... + def IsSuspicious(self,s): + l = len(s) + if l > 80: + return True + return False + + def AddOutputLine(self,s): + assert not self.IsAComment(s) + self._OutLines.append(s + '\n') + + def Open(self): + self._Infile = file(self._InputFilename, 'r') + for line in self._Infile.readlines(): + line = line[:-1] # remove '\n' + if not self.IsAComment( line ): + if self.IsAStartingLine(line): + #print "Previous buffer:",self._PreviousBuffers + previousbuffer = ' '.join(self._PreviousBuffers) + if self.IsAStartingLine(previousbuffer): + if not self.IsSuspicious(previousbuffer): + self.AddOutputLine(previousbuffer) + else: + # this case should not happen if I were to rewrite the + # thing I should be able to clean that + #print "Suspicious:", previousbuffer + #print "List is:", self._PreviousBuffers + s = self._PreviousBuffers[0] + if self.IsAFullLine(s): + # That means we have a weird line that does not start + # as usual (xxxx,xxxx) therefore we tried constructing + # a buffer using a the complete previous line... + #print "Full line:", s + self.AddOutputLine(s) + s2 = ' '.join(self._PreviousBuffers[1:]) + #print "Other Full line:", s2 + self.AddOutputLine(s2) + else: + # we have a suspicioulsy long line, so what that could + # happen, let's check: + if self.IsAFullLine(previousbuffer): + self.AddOutputLine(previousbuffer) + else: + # This is the only case where we do not add + # previousbuffer to the _OutLines + print "Suspicious and Not a full line:", s + else: + if previousbuffer: + print "Not a buffer:", previousbuffer + # We can clean buffer, since only the case 'suspicious' + + # 'Not a full line' has not added buffer to the list + self._PreviousBuffers = [] + # In all cases save the line for potentially growing this line + assert not self.IsAComment(line) + self._PreviousBuffers.append(line) + else: + #print "Not a line",line + assert not self.IsAComment(line) + self._PreviousBuffers.append(line) + else: + #print "Comment:",line + previousbuffer = ' '.join(self._PreviousBuffers) + if previousbuffer and self.IsAStartingLine(previousbuffer): + #print "This line is added:", previousbuffer + self.AddOutputLine( previousbuffer ) + else: + #print "Line is comment:", line + print "Buffer is:", previousbuffer + # Ok this is a comment we can safely clean the buffer: + self._PreviousBuffers = [] + self.Write() + + def Write(self): + outfile = file(self._OutputFilename, 'w') + outfile.writelines( self._OutLines ) + outfile.close() + self._Infile.close() + + # Main function to call for parsing + def Parse(self): + self.Open() + +""" +subclass +""" +class UIDParser(PdfTextParser): + def IsAStartingLine(self,s): + patt = re.compile('^1.2.840.10008.[0-9.]+ (.*)$') + if( patt.match(s) ): + return True + #print "Is Not:", s + return False + + def IsAFullLine(self,s): + patt = re.compile('^1.2.840.10008.[0-9.]+ (.*) PS ?[0-9].1?[0-9]$') + if( patt.match(s) ): + return True + patt = re.compile('^1.2.840.10008.[0-9.]+ (.*) Well-known frame of reference$') + if( patt.match(s) ): + return True + patt = re.compile('^1.2.840.10008.[0-9.]+ (.*) \\(Retired\\)$') + if( patt.match(s) ): + return True + return False + + def IsAComment(self,s): + if PdfTextParser.IsAComment(self,s): + return True + # else let's enhance the super class + patt = re.compile('^SPM2 (.*) http(.*)$') + if( patt.match(s) ): + return True + return False + + def AddOutputLine(self,s): + if self.IsAFullLine(s): + return PdfTextParser.AddOutputLine(self,s) + print "Discarding:", s + + +""" +TransferSyntaxParser +""" +class TransferSyntaxParser(UIDParser): + def IsAFullLine(self,s): + patt = re.compile('^(.*) Transfer Syntax PS ?[0-9].1?[0-9]$') + if patt.match(s): + return UIDParser.IsAStartingLine(self,s) + print "Not a TS:", s + return False + +""" +Papyrus parser +pdftotext -f 19 -l 41 -raw -nopgbrk /tmp/Papyrus31Specif.pdf /tmp/Papyrus31Specif.txt + +I need to do a second pass for pages: +#29 since I need to find [0-9.]+ +#40,41 since it start with number in two columns !! +""" +class PapyrusParser(PdfTextParser): + def __init__(self): + self._PreviousPage = 0 + self._PreviousNumber = 0 + PdfTextParser.__init__(self) + + def IsAStartingLine(self,s): + patt = re.compile('^[A-Za-z \'\(\)]+ +\\([0-9A-F]+,[0-9A-F]+\\) +(.*)$') + if( patt.match(s) ): + return True + # After page 39, lines are like: + patt = re.compile('^[0-9x]+ [0-9xA-F]+ .*$') + if( patt.match(s) ): + #print "PAge 39", s + return True + return False + + def IsAFullLine(self,s): + patt = re.compile('^[A-Za-z \'\(\)]+ +\\([0-9A-F]+,[0-9A-F]+\\) +(.*)$') + if( patt.match(s) ): + return True + # After page 39, lines are like: + patt = re.compile('^[0-9x]+ [0-9xA-F]+ .* [A-Z][A-Z] [0-9].*$') + if( patt.match(s) ): + #print "PAge 39", s + return True + return False + + def IsAComment(self,s): + # dummy case: + if s == 'Attribute Name Tag Type Attribute Description': + #print "Dummy", s + return True + patt = re.compile('^.*ANNEXE.*$') + if patt.match(s): + return True + # Indicate page #, spaces ending with only one number + # Sometime there is a line with only one number, we need to + # make sure that page # is strictly increasing + patt = re.compile('^[1-9][0-9]+$') + if( patt.match(s) ): + p = eval(s) + if( p > self._PreviousPage): + #print "Page #", p + self._PreviousNumber = 0 + self._PreviousPage = p + return True +# else: +# print "PAGE ERROR:", s + # Now within each page there is a comment that start with a # + # let's do the page approach wich reset at each page + patt = re.compile('^[0-9]+$') + if( patt.match(s) ): + if( eval(s) > self._PreviousNumber): + #print "Number #", eval(s) + self._PreviousNumber = eval(s) + return True + #else: + # print "ERROR:", s + return False + + def AddOutputLine(self,s): + assert not self.IsAComment(s) + s = s.replace('\n','') + #print "REMOVE return:", s + patt = re.compile('^([A-Za-z \'\(\)]+) (\\([0-9A-F]+,[0-9A-F]+\\)) ([0-9C]+) (.*)$') + m = patt.match(s) + ss = 'dummy (0000,0000) 0' + if m: + ss = m.group(2) + ' ' + m.group(3) + ' ' + m.group(1) + else: + patt = re.compile('^([A-Za-z \'\(\)]+) (\\([0-9A-F]+,[0-9A-F]+\\)) (.*)$') + m = patt.match(s) + if m: + ss = m.group(2) + ' 0 ' + m.group(1) + else: + ss = s + # There is two case one that end with all capital letter + # explaining the 'DEFINED TERMS' + patt = re.compile('^[0-9x]+ [0-9xA-F]+ .* [A-Z][A-Z] [0-9] [A-Z, ]$') + #patt = re.compile('^[0-9x]+ [0-9xA-F]+ .* [A-Z][A-Z] [0-9]|1\\-n [A-Z, |3.0]+$') + #patt = re.compile('^[0-9x]+ [0-9xA-F]+ .* [A-Z][A-Z] [01n-] [A-Z, |3.0]+$') + if patt.match(s): + print "Match", s + ss = '' + self._OutLines.append(ss + '\n') + + def Open(self): + self._Infile = file(self._InputFilename, 'r') + for line in self._Infile.readlines(): + line = line[:-1] # remove '\n' + if not self.IsAComment( line ): + if self.IsAStartingLine(line): + #print "Previous buffer:",self._PreviousBuffers + previousbuffer = ' '.join(self._PreviousBuffers) + if self.IsAFullLine(previousbuffer): + self.AddOutputLine(previousbuffer) + else: + if previousbuffer: + print "Not a buffer:", previousbuffer + # We can clean buffer, since only the case 'suspicious' + + # 'Not a full line' has not added buffer to the list + self._PreviousBuffers = [] + # In all cases save the line for potentially growing this line + # just to be safe remove any white space at begining of string + assert not self.IsAComment(line) + self._PreviousBuffers.append(line.strip()) + else: + #print "Not a line",line + assert not self.IsAComment(line) + # just to be safe remove any white space at begining of string + self._PreviousBuffers.append(line.strip()) + else: + #print "Previous buffer:",self._PreviousBuffers + previousbuffer = ' '.join(self._PreviousBuffers) + if previousbuffer and self.IsAStartingLine(previousbuffer): + #print "This line is added:", previousbuffer + self.AddOutputLine( previousbuffer ) +# else: +# #print "Line is comment:", line +# print "Buffer is:", previousbuffer + # Ok this is a comment we can safely clean the buffer: + self._PreviousBuffers = [] + self.Write() + +""" +Parser for: +GE Medical Systems HISPEED ADVANTAGE CT/i CONFORMANCE STATEMENT +pdftotext -f 81 -l 90 -raw -nopgbrk 2162114_100r5.pdf 2162114_100r5.txt +""" +class GEMSParser(PdfTextParser): +# def __init__(self): +# PdfTextParser.__init__(self) + + def IsAStartingLine(self,s): + #patt = re.compile('^[A-Za-z \'\(\)]+ +\\([0-9A-F]+,[0-9A-F]+\\) +(.*)$') + patt = re.compile('^[A-Za-z0-9 .#(),_/-]+ +\\([0-9A-F]+, ?[0-9A-F]+\\) +(.*)$') + if( patt.match(s) ): + return True + return False + + def IsAFullLine(self,s): + #patt = re.compile('^[A-Za-z \'\(\)]+ +\\([0-9A-F]+,[0-9A-F]+\\) +(.*)$') + patt = re.compile('^[A-Za-z0-9 .#(),_/-]+ +\\([0-9A-F]+, ?[0-9A-F]+\\) [A-Z][A-Z] [0-9]+$') + if( patt.match(s) ): + return True + print "Not full:", s + return False + + def IsAComment(self,s): + if PdfTextParser.IsAComment(self,s): + return True + #patt = re.compile('^.*GE Medical Systems LightSpeed QX/i CONFORMANCE STATEMENT REV 2.2 sm 2288567-100.*$') + #if patt.match(s): + # return True + patt = re.compile('^.*GE Medical Systems HISPEED ADVANTAGE CT/i CONFORMANCE STATEMENT.*$') + if patt.match(s): + return True + patt = re.compile('^GE Medical Systems LightSpeed QX/i CONFORMANCE STATEMENT.*$') + if patt.match(s): + return True + patt = re.compile('^Attribute Name Tag VR VM$') + if patt.match(s): + return True + patt = re.compile('^B.[1-9].*Private .*$') + if patt.match(s): + return True + patt = re.compile('^Table B.1.? .* Private .*$') + if patt.match(s): + return True + patt = re.compile('^Note :.*$') + if patt.match(s): + return True + patt = re.compile('^7.11.1$') + if patt.match(s): + return True + return False + + def AddOutputLine(self,s): + #print s + assert not self.IsAComment(s) + patt = re.compile('^([A-Za-z0-9 .#(),_/-]+) +\\(([0-9A-F]+), ?([0-9A-F]+)\\) ([A-Z][A-Z]) ([0-9]+)$') + m = patt.match(s) + if m: + ss = m.group(2).lower() + ' ' + m.group(3).lower() + ' ' + m.group(4) + ' ' + m.group(5) + ' ' + m.group(1) + self._OutLines.append(ss + '\n') + else: + print 'OOOPs', s + + +""" +This class is meant to expand line like: +- (xxxx,xxxx to xxxx) xxxxxxxxxxxx +or +- (12xx, 3456) comment... + +""" +class DicomV3Expander: + def __init__(self): + self._InputFilename = '' + self._OutputFilename = '' + self._OutLines = [] + + def SetInputFileName(self,s): + self._InputFilename = s + + def SetOutputFileName(self,s): + self._OutputFilename = s + + # Function to turn into lower case a tag: + # ex: (ABCD, EF01) -> (abcd, ef01) + def LowerCaseTag(self,s): + #print "Before:", s[:-1] + patt = re.compile('^(\\([0-9a-fA-F]+,[0-9a-fA-F]+\\))(.*)$') + m = patt.match(s) + if m: + s1 = m.group(1) + s2 = m.group(2) + return s1.lower() + s2 + else: + patt = re.compile('^[0-9a-fA-F]+ [0-9a-fA-F]+ [A-Z][A-Z] [0-9n-] .*$') + if patt.match(s): + return s + else: + print "Impossible case:", s + os.sys.exit(1) + + def AddOutputLine(self,s): + if s.__class__ == list: + for i in s: + self._OutLines.append(i + '\n') + else: + self._OutLines.append(s + '\n') + + # Expand the line approriaetkly and also add it to the + # _OutLines list + def ExpandLine(self, s): + assert s[-1] == '\n' + s = s[:-1] # remove \n + list = [] + if self.NeedToExpansion(s, list): + self.AddOutputLine(list) # list != [] + elif self.NeedGroupXXExpansion(s, list): + self.AddOutputLine(list) # list != [] + elif self.NeedElemXXExpansion(s, list): + self.AddOutputLine(list) # list != [] + else: + self.AddOutputLine(self.LowerCaseTag(s)) + + # If line is like: + # (0020,3100 to 31FF) Source Image Ids RET + def NeedToExpansion(self,s, list): + patt = re.compile('^\\(([0-9a-fA-F]+),([0-9a-fA-F]+) to ([0-9a-fA-F]+)\\)(.*)$') + m = patt.match(s) + if m: + #print m.groups() + gr = m.group(1) + el_start = '0x'+m.group(2) + el_end = '0x'+m.group(3) + for i in range(eval(el_start), eval(el_end)): + el = hex(i)[2:] + l = '('+gr+','+el+')'+m.group(4) + list.append(l) + return True + return False + + # If line is like: + # (50xx,1200) Number of Patient Related Studies IS 1 + def NeedGroupXXExpansion(self,s,list): + patt = re.compile('^\\(([0-9a-fA-F]+)xx,([0-9a-fA-F]+)\\)(.*)$') + m = patt.match(s) + if m: + #print m.groups() + gr_start = m.group(1) + el = m.group(2) + #el_start = '0x'+m.group(2) + #el_end = '0x'+m.group(3) + start = '0x'+gr_start+'00' + end = '0x'+gr_start+'FF' + for i in range(eval(start), eval(end)): + gr = hex(i)[2:] + l = '('+gr+','+el+')'+m.group(3) + #print l + list.append(l) + return True + return False + + # If line is like: + # (2001,xx00) Number of Patient Related Studies IS 1 + def NeedElemXXExpansion(self,s,list): + patt = re.compile('^([0-9a-fA-F]+) ([0-9a-fA-F]+)xx(.*)$') + m = patt.match(s) + if m: + #print m.groups() + gr = m.group(1) + el_start = m.group(2) + start = '0x00' + end = '0xFF' + for i in range(eval(start), eval(end)): + el = '%02x'% i + l = '('+gr+','+el_start+el+')'+m.group(3) + print l + list.append(l) + return True + else: + patt = re.compile('^([0-9a-fA-F]+) xx([0-9a-fA-F]+)(.*)$') + m = patt.match(s) + if m: + #print m.groups() + gr = m.group(1) + el_start = m.group(2) + start = '0x00' + end = '0xFF' + for i in range(eval(start), eval(end)): + el = '%02x'% i + l = '('+gr+','+el+el_start+')'+m.group(3) + print l + list.append(l) + return True + return False + + def Write(self): + outfile = file(self._OutputFilename, 'w') + outfile.writelines( self._OutLines ) + outfile.close() + + def Expand(self): + infile = file(self._InputFilename,'r') + for line in infile.readlines(): + # ExpandLine also LowerCase the line + self.ExpandLine(line) # l is [1,n] lines + self.Write() + infile.close() + +""" +Parse line from a philips document, line are like this: + +Syncra Scan Type 2005,10A1 VR = CS, VM = 1 +""" +class InteraParser: + def __init__(self): + self._InputFilename = '' + self._OutputFilename = '' + + def Reformat(self,s): + assert self.IsGood(s) + patt = re.compile("^([A-Za-z0-9 -]+) ([0-9A-Z]+),([0-9A-Z]+) VR = ([A-Z][A-Z]), VM = (.*)$") + m = patt.match(s) + if m: + dicom = m.group(2) + ' ' + m.group(3) + ' ' + m.group(4) + ' ' + m.group(5) + ' ' + m.group(1) + return dicom + else: + print "oops" + + def IsGood(self,s): + patt = re.compile("^[A-Za-z0-9 -]+ [0-9A-Z]+,[0-9A-Z]+ VR = [A-Z][A-Z], VM = .*$") + if patt.match(s): + return True + print "Not good:", s + return False + + def SetInputFileName(self,s): + self._InputFilename = s + + def SetOutputFileName(self,s): + self._OutputFilename = s + + def Parse(self): + infile = file(self._InputFilename, 'r') + outLines = [] + for line in infile.readlines(): + print self.Reformat(line) + outLines.append( self.Reformat(line) + '\n' ) + outfile = file(self._OutputFilename, 'w') + outfile.writelines( outLines ) + outfile.close() + +""" +Parse line from a dicom3tools document, line are like this: + +(0003,0008) VERS="SSPI" VR="US" VM="1" Owner="SIEMENS ISI" Keyword="ISICommandField" Name="ISI Command Field" +""" +class Dicom3ToolsParser: + def __init__(self): + self._InputFilename = '' + self._OutputFilename = '' + + def Reformat(self,s): + assert self.IsGood(s) + patt = re.compile("^\(([0-9a-f]+),([0-9a-f]+)\)\s+VERS=\".*\"\s+VR=\"([A-Z][A-Z])\"\s+VM=\"(.*)\"\s+Owner=\".*\"\s+Keyword=\".*\"\s+Name=\"(.*)\"$") + m = patt.match(s) + dicom = '' + if m: + # Apparently some have Name == '?', skip those + name = m.group(5) + if name != '?' and name != '? ': + dicom = m.group(1) + ' ' + m.group(2) + ' ' + m.group(3) + ' ' + m.group(4) + ' ' + m.group(5) + else: + print "oops" + else: + print "oops" + return dicom + + def IsGood(self,s): + #patt = re.compile("^\([0-9a-f]+,[0-9a-f]+\) VERS=\".*\" VR=\"[A-Z][A-Z]\" VM=\".*\" Owner=\".*\" Keyword=\".*\" Name=\".*\"$") + patt = re.compile("^\([0-9a-f]+,[0-9a-f]+\)\s+VERS=\".*\"\s+VR=\"[A-Z][A-Z]\"\s+VM=\".*\"\s+Owner=\".*\"\s+Keyword=\".*\"\s+Name=\".*\".*$") + if patt.match(s): + return True + print "Not good:", s + return False + + def SetInputFileName(self,s): + self._InputFilename = s + + def SetOutputFileName(self,s): + self._OutputFilename = s + + def Parse(self): + infile = file(self._InputFilename, 'r') + outLines = [] + for line in infile.readlines(): + newline = self.Reformat(line) + print newline + if newline: + outLines.append( newline + '\n' ) + outfile = file(self._OutputFilename, 'w') + outfile.writelines( outLines ) + outfile.close() + +""" +Parse line from a PhilipsAdvance document, line are like this: + +GE Advance Implementation Version Name (0009,1001) 3 LO 2 n/a +""" +class GEAdvanceParser: + def __init__(self): + self._InputFilename = '' + self._OutputFilename = '' + + def Reformat(self,s): + assert self.IsGood(s) + #patt = re.compile("^\(([0-9a-f]+),([0-9a-f]+)\)\s+VERS=\".*\"\s+VR=\"([A-Z][A-Z])\"\s+VM=\"(.*)\"\s+Owner=\".*\"\s+Keyword=\".*\"\s+Name=\"(.*)\"$") + patt = re.compile("^([A-Za-z0-9 ._>]+) \\(([0-9A-F]+),([0-9A-F]+)\\) [0-9] ([A-Z][A-Z]) ([0-9]) .*$") + m = patt.match(s) + dicom = '' + if m: + dicom = m.group(2) + ' ' + m.group(3).lower() + ' ' + m.group(4) + ' ' + m.group(5) + ' ' + m.group(1) + else: + print "oops" + return dicom + + def IsGood(self,s): + #patt = re.compile("^\([0-9a-f]+,[0-9a-f]+\)\s+VERS=\".*\"\s+VR=\"[A-Z][A-Z]\"\s+VM=\".*\"\s+Owner=\".*\"\s+Keyword=\".*\"\s+Name=\".*\".*$") + patt = re.compile("^[A-Za-z0-9 ._>]+ \\([0-9A-F]+,[0-9A-F]+\\) [0-9] [A-Z][A-Z] [0-9] .*$") + if patt.match(s): + return True + print "Not good:", s + return False + + def SetInputFileName(self,s): + self._InputFilename = s + + def SetOutputFileName(self,s): + self._OutputFilename = s + + def Parse(self): + infile = file(self._InputFilename, 'r') + outLines = [] + for line in infile.readlines(): + newline = self.Reformat(line) + #print newline + if newline: + outLines.append( newline + '\n' ) + outfile = file(self._OutputFilename, 'w') + outfile.writelines( outLines ) + outfile.close() + +if __name__ == "__main__": + argc = len(os.sys.argv ) + if ( argc < 3 ): + print "Sorry, wrong list of args" + os.sys.exit(1) #error + + inputfilename = os.sys.argv[1] + outputfilename = os.sys.argv[2] + tempfile = "/tmp/mytemp" + """ + dp = PdfTextParser() + dp.SetInputFileName( inputfilename ) + #dp.SetOutputFileName( outputfilename ) + dp.SetOutputFileName( tempfile ) + dp.Parse() + exp = DicomV3Expander() + #exp.SetInputFileName( tempfile ) + exp.SetInputFileName( inputfilename ) + exp.SetOutputFileName( outputfilename ) + exp.Expand() + + dp = TransferSyntaxParser() + dp.SetInputFileName( inputfilename ) + dp.SetOutputFileName( outputfilename ) + dp.Parse() + + dp = PapyrusParser() + dp.SetInputFileName( inputfilename ) + dp.SetOutputFileName( outputfilename ) + dp.Parse() + + dp = InteraParser() + dp.SetInputFileName( inputfilename ) + dp.SetOutputFileName( outputfilename ) + dp.Parse() + dp = GEMSParser() + dp.SetInputFileName( inputfilename ) + dp.SetOutputFileName( outputfilename ) + dp.Parse() + + """ + dp = Dicom3ToolsParser() + dp.SetInputFileName( inputfilename ) + dp.SetOutputFileName( outputfilename ) + dp.Parse() + + """ + dp = GEAdvanceParser() + dp.SetInputFileName( inputfilename ) + dp.SetOutputFileName( outputfilename ) + dp.Parse() + """ + + #print dp.IsAStartingLine( "(0004,1212) File-set Consistency Flag US 1\n" ) diff --git a/Utilities/ITK/Utilities/gdcm/Dicts/README b/Utilities/ITK/Utilities/gdcm/Dicts/README new file mode 100644 index 0000000000000000000000000000000000000000..6f94c6ec9985c35738f491459d24021208dc7df1 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/Dicts/README @@ -0,0 +1,321 @@ +Sources for dicom public dictionaries: + * the official source is the part 6 of the dicom standard (see + http://www.dclunie.com/dicom-status/status.html#BaseStandard2001). + * http://www.fpimage.com/Manuals/Imp/dicomdic.html + an html group based presentation. + * ftp://rsbweb.nih.gov/pub/nih-image/documents/dicom-dict.txt + a C syntax oriented version provided by NIH (Jim Nash) + * http://afni.nimh.nih.gov/afni/AFNI_Dist/afni_src.tgz + extract mri_dicom_hdr.c (tar zxvf afni_src.tgz afni_src/mri_dicom_hdr.c) + and look for the definitions of CMD_dictionary, META_dictionary, + ID_dictionary, PAT_dictionary... + * Actually, the *official* Dicom Data Dictionary + is on http://medical.nema.org/dicom/2003/03_06PU.pdf + (check it every year, some tags are added, some names change) + All C syntax oriented stuff, or anything else -but gdcm one- + you can find on the net is very partial. + WARNING : The Dicom Tag is an identifier inside the Dicom Dictionary, + The Tag Name *is not* + + +Comment on the file NIH.dic, you can find the following discussion +on comp.protocol.dicom(*). As clearly specify by David Clunie all +thoses tags are extremely dangerous to use since they override some +other, we are only adding them to gdcm to be able to read /apparently/ +some NIH images. SHOULD NOT EVER BE USED FOR WRITTING IMAGES ! + +(*) +[Re: Retired element VR and VM, was Re: 0028,3006 LUT Data (nightmare)] +... +> 'gdcm' Dicom dictionary uses a few tags, such as : +> 0018 106b UI 1 Synchronization Frame of Reference +This should be: +(0020,0200) Synchronization Frame of Reference UID +> 0028 0122 US 1 Waveform Padding Value +(5400,100A) Waveform Padding Value +> 003a 0002 SQ 1 Waveform Sequence +(5400,0100) Waveform Sequence +> 003a 0103 CS 1 Data Value Representation +(50xx,0103) Data Value Representation +> 0040 0552 SQ 1 Specimen Description Sequence +No such attribute +> 0040 0553 ST 1 Specimen Description +No such attribute +> 0040 09f8 SQ 1 Vital Stain Code Sequence +No such attribute +> 0040 a16a ST 1 Bibliographics Citation +No such attribute +> 0040 a992 ST 1 Uniform Resource Locator +No such attribute + +I suspect these were taken for the draft for trial implementation +of Sup 23 SR, which was problematic in many ways, not the least +of which was that some of its attributes with the same number +were re-used with different purpose and VR, etc. + +Some may have been from early drafts of other supplements (e.g., +waveform from the looks of things). + +None of these should ever be used. +... + + + + + + +Remarks about dicomV3Intera.dic: + +This document is produced /somehow/ using document at: +[Intera 10.1] +http://www.medical.philips.com/main/company/connectivity/assets/docs/dicomcs/Conformance_Statement_MR_101_v04.pdf + +[DICOM Conformance Statement] +http://www.medical.philips.com/main/company/connectivity/assets/docs/dicomcs/MR_InteraR104dcs.pdf + + +Remarks about GEMS.dic + +This document is produced using: +GE Medical Systems HISPEED ADVANTAGE CT/i CONFORMANCE STATEMENT: +http://www.gehealthcare.com/euen/interoperability/docs/2162114_100r5.pdf + +the 0023 tags were also extracted from: +[Technical Publications] +http://www.gehealthcare.com/usen/interoperability/dicom/docs/22046092.pdf + +Ok I finally understood the Private Creator thing: +V 0025|0010 lg : x(c) 12 Off.: x(e4e) 3662 [LO] [gdcm::Unknown] [GEMS_SERS_01] +V 0027|0010 lg : x(c) 12 Off.: x(eda) 3802 [LO] [gdcm::Unknown] [GEMS_IMAG_01] +V 0029|0010 lg : x(c) 12 Off.: x(10b8) 4280 [LO] [gdcm::Unknown] [GEMS_IMPS_01] +V 0043|0010 lg : x(c) 12 Off.: x(112a) 4394 [LO] [gdcm::Unknown] [GEMS_PARM_01] + +And if you take document: +http://www.gehealthcare.com/euen/interoperability/docs/2288567_100r3_0.pdf +they are all described: + +B.2.5 Private Creator Identification (GEMS_STDY_01) +B.2.6 Private Creator Identification (GEMS_SERS_01) +B.2.7 Private Creator Identification (GEMS_IMAG_01) +... + +In fact the best document is: +LightSpeed QX/i 1.2 Conformance Statement for DICOM v3.0 (ID/Net v3.0) +http://www.gehealthcare.com/euen/interoperability/docs/2288567_100r3_0.pdf + + +I was searching for 0043 1039, I could only find: +http://www.gehealthcare.com/it_solutions/connectivity/pdf/hispeed_np.pdf +ok -> http://www.gehealthcare.com/usen/interoperability/dicom/docs/hispeed_np.pdf +but the link points nowhere, the document describes: +HiSpeed LX/i, FX/i, DX/i, DX/iB 2.00/2.01/2.02 CONFORMANCE STATEMENT for DICOM v3.0 + +..let's use google cache... not fun ! + + +0043 1060 was found at: http://www.gehealthcare.com/it_solutions/connectivity/pdf/2246181r25.pdf +ok -> http://www.gehealthcare.com/usen/interoperability/dicom/docs/2246181r25.pdf +0043 1060 IS 8 slop_int_10...slop_int_17 + +I would also need: +Signa Horizon Lx DICOM CONFORMANCE STATEMENT for DICOM v3.0 +grrrr: Vas flags 0043 1032 SS 1 in http://www.vitalcom.com/it_solutions/connectivity/pdf/2317752r3.pdf +ok: -> www.gehealthcare.com/usen/interoperability/dicom/docs/2317752r3.pdf +but 0043 1032 SS 1 Raw data type http://www.vitalcom.com/it_solutions/connectivity/pdf/2171143r25.pdf +ok -> www.gehealthcare.com/usen/interoperability/dicom/docs/2171143r25.pdf + +Adding a page from : http://www.vitalcom.com/it_solutions/connectivity/pdf/2317752r3.pdf + +A Coord of Top Right Corner (0027,1049) FL 1 +S Coord of Top Right Corner (0027,104A) FL 1 +R Coord of Bottom Right Corner (0027,104B) FL 1 +A Coord of Bottom Right Corner (0027,104C) FL 1 +S Coord of Bottom Right Corner (0027,104D) FL 1 +Image dimension - X (0027,1060) FL 1 +Image dimension - Y (0027,1061) FL 1 +Number of Excitations (0027,1062) FL 1 +B.1. 8 Private Creator Identification (GEMS_IMPS_01) +Lower range of Pixels1 (0029,1015) SL 1 +Lower range of Pixels1 (0029,1016) SL 1 +Lower range of Pixels2 (0029,1017) SL 1 +Upper range of Pixels2 (0029,1018) SL 1 +Len of tot hdr in bytes (0029,101A) SL 1 +Version of the hdr struct (0029,1026) SS 1 +Advantage comp. Overflow (0029,1034) SL 1 +Advantage comp. Underflow (0029,1035) SL 1 +B.1. 9 Private Creator Identification (GEMS_PARM_01) +Bitmap of prescan options (0043,1001) SS 1 +Gradient offset in X (0043,1002) SS 1 +Gradient offset in Y (0043,1003) SS 1 +Gradient offset in Z (0043,1004) SS 1 +Img is original or unoriginal (0043,1005) SS 1 +Number of EPI shots (0043,1006) SS 1 +Views per segment (0043,1007) SS 1 +Respiratory rate, bpm (0043,1008) SS 1 +Respiratory trigger point (0043,1009) SS 1 +Type of receiver used (0043,100A) SS 1 +Peak rate of change of gradient field (0043,100B) DS 1 +Limits in units of percent (0043,100C) DS 1 +PSD estimated limit (0043,100D) DS 1 +PSD estimated limit in tesla per second (0043,100E) DS 1 +Saravghead (0043,100F) DS 1 +Window value (0043,1010) US 1 +GE image integrity (0043,101C) SS 1 +Level value (0043,101D) SS 1 +Unique image iden (0043,1028) OB 1 +Histogram tables (0043,1029) OB 1 +User defined data (0043,102A) OB 1 +Private Scan Options (0043,102B) SS 4 +Effective echo spacing (0043,102C) SS 1 +String slop field 1 (0043,102D) SH 1 +String slop field 2 (0043,102E) SH 1 +Image Type (real, imaginary, phase, magnitude) (0043,102F) SS 1 +Vas collapse flag (0043,1030) SS 1 + +RA cord of target recon center (0043,1031) DS 2 +Vas flags (0043,1032) SS 1 +Neg_scanspacing (0043,1033) FL 1 +Offset Frequency (0043,1034) IS 1 +User_usage_tag (0043,1035) UL 1 +User_fill_map_MSW (0043,1036) UL 1 +User_fill_map_LSW (0043,1037) UL 1 +User data 25...User data 48 (0043,1038) FL 24 +Slop_int_6... slop_int_9 (0043,1039) IS 4 + 6: b_value + 7: private imaging options 2 + 8: ihtagging + 9: ihtagspc +Slop_int_10...slop_int_17 (0043,1060) IS 8 + 10: ihfcineim + 11: ihfcinent + 12: Reserved + 13: oprtarr + 14: averages + 15: Current Station # + 16: Total # of Stations + 17: Reserved + +Scanner Study Entity UID (0043,1061) UI 1 +Scanner Study ID (0043,1062) SH 1 +Scanner Table Entry (single gradient coil systems only) +Scanner Table Entry + Gradient Coil Selected (0043,106f) DS 3 or 4 + + +------------------------------------------------- +Notes from: +PathSpeedtm PACS Version 8.0 CONFORMANCE STATEMENT for DICOM V3.0 +http://www.gehealthcare.com/it_solutions/connectivity/pdf/iis_fp_10282r1.pdf +ok -> www.gehealthcare.com/usen/interoperability/dicom/docs/iis_fp_10282r1.pdf + +See GE_ImageThumbnails +-------------------------------------------------- + + +About ACUSON.dic, generated from aspen3.pdf: +[Acusion Aspen(tm) Ultrasound System Dicom Conformance Statement for aspen 3.0 3.5] +http://mais.baikal.ru/library/pdf/aspen3.pdf + + +-------------------------------------------------- +According to : +http://www.gehealthcare.com/usen/interoperability/dicom/docs/ep250409r4.pdf + +2.5 EXTENSIONS / SPECIALIZATIONS / PRIVATIZATIONS +If so configured, the product will send ultrasound raw data information in private data elements designated by the Private +Creator element: + +Element Name Tag VR VM Description +Private Creator 7FE1,00xx LO 1 GEMS_Ultrasound_MovieGroup_001 + +This means that all private tags starting with 7FE1,xx will belong to the GEMS_Ultrasound_MovieGroup_001. +If so configured, the product will send preview image in private data elements designated by the Private Creator element: + +Element Name Tag VR VM Description +Private Creator 6003,00xx LO 1 GEMS_Ultrasound_ImageGroup_001 + +This means that all private tags starting with 6003,00xx will belong to the GEMS_Ultrasound_ImageGroup_001 + +-------------------------------------------------- +In preparation for the new Philips dictionaray with values taken from: +http://www.medical.philips.com/main/company/connectivity/assets/docs/dicomcs/mr91.pdf +rename the old dictionary to avoid confusion + +Basically all the dictionary should have been: + +2001 xx22 FL 1 Water Fat Shift +instead of +2001 1022 FL 1 Water Fat Shift + + +About GEMS Genie: +Doc was taken from: +http://www.gehealthcare.com/usen/fun_img/nmedicine/nmdicom/docs/confstmt.pdf + +433 echo "http://www.gehealthcare.com/usen/fun_img/nmedicine/nmdicom/docs/confstmt.pdf" > GEMS-Genie.dic +To build GEMS-Genie I also used: http://www.gehealthcare.com/usen/fun_img/nmedicine/nmdicom/docs/2383442_100r1.pdf + +434 echo "http://www.gehealthcare.com/usen/interoperability/dicom/docs/2270669_100r0_3.pdf" > GEMS-Advance.dic + +According to 2270669_100r0_3.pdf, there is different interpretation for: + +0009 10b3 SL 1 GE Advance ImageSet.ir_num_subsets +0009 10b4 FL 1 GE Advance ImageSet.ir_recon_fov + +or: + +0009 10b4 FL 1 GE Advance ImageSet.ir_num_subsets +... grrrr +ok nevermind I found also this document: +http://www.gehealthcare.com/usen/fun_img/pet/docs/5101600GDOr0.pdf +that defines: +0009 10b3 SL 1 GE Advance ImageSet.ir_num_subsets + + +-------------------------------------------------- +About 6002,1000 I only found one ref: +[Advantage Workstation 4.0 CONFORMANCE STATEMENT for DICOM V3.0] +http://www.gehealthcare.com/usen/interoperability/dicom/docs/2261302_100r1.pdf + + +-------------------------------------------------- +For GEMS-Advantx.dic +[EchoPAC PC version 4 CONFORMANCE STATEMENT for DICOM] +http://www.gehealthcare.com/it_solutions/connectivity/pdf/EP250409r06.pdf +ok -> www.gehealthcare.com/usen/interoperability/dicom/docs/EP250409r06.pdf +http://www.gehealthcare.com/usen/xr/dicom/docs/2142506_100r01_ps.pdf + + +-------------------------------------------------- +ELSCINT Dictionary was done by ripping stuff from: +Value Multiplicity was deducted by looking at the values for this particular image... +http://www.merge-efilm.com/phpbb2/viewtopic.php?t=171&sid=11cde708c1f4feac179467c117373732 + + +About PHILIPS-EasyVision.dic, BE VERY AFRAID: +http://www.medical.philips.com/main/company/connectivity/assets/docs/dicomcs/ev44_final.pdf +... pure pleasure... + + +-------------------------------------------------- +SPI.dic and SIEMENS.dic were generated based on D. Clunie work at: +[3.3.2.2.2 Siemens Magnetom SP SPI Format] +http://www.dclunie.com/medical-image-faq/html/part4.html + +and spi.tpl siemens.tpl from dicom3tools (20050611 snapshot) + + +--------------------------------------------------- + +Alright SIEMENS is totally screwed up... +Let's have a look at: +[Aristos VB10] +http://www.medical.siemens.com/siemens/en_INT/rg_marcom_FBAs/files/brochures/DICOM/ax/Aristos_DicomConformanceStatement.pdf + +SOMATOM syngo VA50A DICOM Conformance Statement +http://61.62.116.208/webhd/adams/LinkedDocuments/SENSATION_16.pdf + +SOMATOM syngo VA45A DICOM Conformance Statement +http://61.62.116.208/webhd/adams/LinkedDocuments/EMOTION%206%20DICOM.pdf + +Somaris/5 VA70A CT DICOM Conformance Statement +http://www.petscaninfo.com/zportal/portals/ctimi/prodandserv/dicom_statements/xvi.pdf diff --git a/Utilities/ITK/Utilities/gdcm/Dicts/SIEMENS-syngo.dic b/Utilities/ITK/Utilities/gdcm/Dicts/SIEMENS-syngo.dic new file mode 100644 index 0000000000000000000000000000000000000000..16a6de38e4de6eea5fc9cbda4e998174bbf9a60a --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/Dicts/SIEMENS-syngo.dic @@ -0,0 +1,96 @@ +See : + +www.tamsinfo.toshiba.com/docrequest/pdf/esoft3.5.pdf +for more fields (page 106 ?!?) +or +www.medical.siemens.com/siemens/en_INT/rg_marcom_FBAs/files/brochures/DICOM/mr/MEDWS_DCS_ESK.pdf + +CSA Non Image +------------- +0029 xx08 CS 1 CSA Data Type +0029 xx09 LO 1 CSA Data Version +0029 xx10 OB 1 CSA Data Info +7fe1 xx10 OB 1 CSA Data + +CSA Image Header Module +----------------------- + +0029 xx08 CS 1 CSA Image Header Type +0029 xx09 LO 1 CSA Image Header Version +0029 xx10 OB 1 CSA Image Header Info + +CSA Series Header Module +----------------------- + +0029 xx08 CS 1 CSA Series Header Type +0029 xx09 LO 1 CSA Series Header Version +0029 xx10 OB 1 CSA Series Header Info + +0029 xx08 CS 1 syngo Report Type +0029 xx09 LO 1 syngo Report +0029 xx15 US 1 SR Variant +0029 xx17 US 1 SC SOP Instance UID + +0029 xx10 OB 1 syngo Report Data +0029 xx11 OB 1 syngo Report Presentation + +MEDCOM Header Module +-------------------- + +0029 xx08 CS 1 Medcom Header Type +0029 xx09 LO 1 Medcom Header Version +0029 xx10 OB 1 Medcom Header Info +0029 xx20 OB 1 Medcom History Information +0029 xx31 LO 1 PMTF Information 1 +0029 xx32 UL 1 PMTF Information 2 +0029 xx33 UL 1 PMTF Information 3 +0029 xx34 CS 1 PMTF Information 4 +0029 xx35 UL 1 PMTF Information 5 +0029 xx40 SQ 1 Application Header Sequence +0029 xx41 CS 1 Application Header Type +0029 xx42 LO 1 Application Header ID +0029 xx43 LO 1 Application Header Version +0029 xx44 OB 1 Application Header Info +0029 xx40 SQ 1 Application Header Sequence +0029 xx50 LO 8 Workflow Control Flags +0029 xx51 CS 1 Archive Management Flag Keep Online +0029 xx52 CS 1 Archive Management Flag Do Not Archive +0029 xx53 CS 1 Image Location Status +0029 xx54 DS 1 Estimated Retrieve Time +0029 xx55 CS 1 Data Size of Retrieved Images + +MEDCOM History Information +-------------------------- + + +MEDCOM OOG Module +----------------- +0029 xx08 CS 1 MedCom OOG Type +0029 xx09 LO 1 MedCom OOG Version +0029 xx10 OB 1 MedCom OOG Info + +syngo Report Data +----------------- + +Standard Extensions of NM SOP Class +----------------------------------- +0019 00a5 SS 1-n Number of repeats per phase +0019 00a6 SS 1-n Cycles per repeat +0019 00a7 SL 1-n Repeat start time +0019 00a8 SL 1-n Repeat stop time +0019 00a9 SL 1-n Effective repeat time +0019 00aa SS 1-n Adquiered cycles per repeat +0021 0000 OB 1 ECAT File Menu Header +--> +--> 0021 0000 is NOT a group length ?!? +--> +0021 0001 OB 1 ECAT File SubHeader +0033 0000 FL n Flood correction Matrix Det 1 upto SR 2.0 +0033 0001 FL n Flood correction Matrix Det 2 upto SR 2.0 + + +etc ... +See : +tamsinfo.toshiba.com/docrequest/pdf/esoft3.5.pdf +for more fields (page 106 ?!?) + diff --git a/Utilities/ITK/Utilities/gdcm/Dicts/SIEMENS.dic b/Utilities/ITK/Utilities/gdcm/Dicts/SIEMENS.dic new file mode 100644 index 0000000000000000000000000000000000000000..73575226f091f6eedd166649fe42da756ab7b09f --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/Dicts/SIEMENS.dic @@ -0,0 +1,217 @@ +0009 1010 CS 1 Storage Mode +0009 1015 LO 1 UID +0009 1040 SH 1 Data Object Subtype +0009 1041 SH 1 Data Object Subtype + +0009 1110 LO 1 Recognition Code +0009 1130 UL 1 Byte Offset of Original Header +0009 1131 UL 1 Length of Original Header +0009 1140 UL 1 Byte Offset of Pixelmatrix +0009 1141 UL 1 Length of Pixelmatrix In Bytes + +0009 1310 LO 1 Generator Identification Label +0009 1311 LO 1 Gantry Identification Label +0009 1312 LO 1 X-Ray Tube Identification Label +0009 1313 LO 1 Detector Identification Label +0009 1314 LO 1 DAS Identification Label +0009 1315 LO 1 SMI Identification Label +0009 1316 LO 1 CPU Identification Label +0009 1320 SH 1 Header Version + +0011 0000 UL 1 Group Length +0011 0003 LO 1 Patient UID +0011 0004 LO 1 Patient ID +0011 000a LO 1 Case ID +0011 0010 DA 1 Registration Date +0011 0010 LO 1 Patient UID +0011 0011 TM 1 Registration Time +0011 0011 LO 1 Patient ID +0011 0020 DA 1 Patient Registration Date +0011 0021 TM 1 Patient Registration Time +0011 0022 LO 1 Request ID +0011 0023 DS 1 Used Patient Weight +0011 0023 LO 1 Examination UID +0011 0030 LO 1 Patientname RIS +0011 0031 LO 1 Patientprename RIS +0011 0040 IS 1 Organ Code +0011 0040 LO 1 Patient Hospital Status +0011 0041 LO 1 Medical Alerts +0011 0042 LO 1 Contrast Allergies +0011 00a1 DA 1 Patient Registration Date +0011 00a2 TM 1 Patient Registration Time +0011 00b0 LO 1 Patient Last Name +0011 00b2 LO 1 Patient First Name +0011 00b4 LO 1 Patient Hospital Status +0011 00bc TM 1 Current Location Time +0011 00c0 LO 1 Patient Insurance Status +0011 00d0 LO 1 Patient Billing Type +0011 00d2 LO 1 Patient Billing Address + +0013 0000 PN 1 Modifying Physician +0013 0010 DA 1 Modification Date +0013 0012 TM 1 Modification Time +0013 0020 PN 1 Patient Name +0013 0022 LO 1 Patient Id +0013 0030 DA 1 Patient Birthdate +0013 0031 DS 1 Patient Weight +0013 0032 LO 1 Patients Maiden Name +0013 0033 LO 1 Referring Physician +0013 0034 LO 1 Admitting Diagnosis +0013 0035 LO 1 Patient Sex +0013 0040 LO 1 Procedure Description +0013 0042 LO 1 Patient Rest Direction +0013 0044 LO 1 Patient Position +0013 0046 LO 1 View Direction + +0019 1010 IS 1 Net Frequency +0019 1020 CS 1 Measurement Mode +0019 1030 CS 1 Calculation Mode +0019 1050 IS 1 Noise Level +0019 1060 IS 1 Number of Data Bytes +0019 1210 DS 1 Total Measurement Time Nominal +0019 1211 DS 1 Total Measurement Time Current +0019 1212 DS 1 Start Delay Time +0019 1213 DS 1 Dwell Time +0019 1214 IS 1 Number of Phases +0019 1216 UL 2 Sequence Control Mask +0019 1218 UL 1 Measurement Status Mask +0019 1220 IS 1 Number of Fourier Lines Nominal +0019 1221 IS 1 Number of Fourier Lines Current +0019 1226 IS 1 Number of Fourier Lines after Zero +0019 1228 IS 1 First Measured Fourier Line +0019 1230 IS 1 Acquisition Columns +0019 1231 IS 1 Reconstruction Columns +0019 1240 IS 1 Array Coil Element Number +0019 1241 UL 1 Array Coil Element Select Mask +0019 1242 UL 1 Array Coil Element Data Mask +0019 1243 IS 1-n Array Coil Element To ADC Connect +0019 1244 DS 1-n Array Coil Element Noise Level +0019 1245 IS 1 Array Coil ADC Pair Number +0019 1246 UL 1 Array Coil Combination Mask +0019 1250 IS 1 Number of Averages Current +0019 1260 DS 1 Flip Angle +0019 1270 IS 1 Number of Prescans +0019 1281 CS 1 Filter Type for Raw Data +0019 1282 DS 1-n Filter Parameter for Raw Data +0019 1283 CS 1 Filter Type for Image Data +0019 1284 DS 1-n Filter Parameter for Image Data +0019 1285 CS 1 Filter Type for Phase Correction +0019 1286 DS 1-n Filter Parameter for Phase Correction +0019 1287 CS 1 Normalization Filter Type for Image Data +0019 1288 DS 1-n Normalization Filter Parameter for Image Data +0019 1290 IS 1 Number of Saturation Regions +0019 1291 DS 6 Saturation Phase Encoding Vector Sagittal Component +0019 1292 DS 6 Saturation Readout Vector Sagittal Component +0019 1293 IS 1 EPI Stimulation Monitor Mode +0019 1294 DS 1 Image Rotation Angle +0019 1296 UL 3 Coil ID Mask +0019 1297 UL 2 Coil Class Mask +0019 1298 DS 3 Coil Position +0019 12a0 DS 1 EPI Reconstruction Phase +0019 12a1 DS 1 EPI Reconstruction Slope + +0019 1410 IS 1 Distance Source To Source Side Collimator +0019 1411 IS 1 Distance Source To Detector Side Collimator +0019 1412 DS 1 Magnetic Field Strength +0019 1414 DS 1 ADC Voltage +0019 1416 DS 2 ADC Offset +0019 1420 DS 1 Transmitter Amplitude +0019 1420 IS 1 Number of Possible Channels +0019 1421 IS 1 Mean Channel Number +0019 1421 IS 1 Number of Transmitter Amplitudes +0019 1422 DS 1 Detector Spacing +0019 1422 DS 1 Transmitter Attenuator +0019 1423 DS 1 Detector Center +0019 1424 DS 1 Reading Integration Time +0019 1424 DS 1 Transmitter Calibration +0019 1426 DS 1 Transmitter Reference +0019 1450 DS 1 Detector Alignment +0019 1450 DS 1 Receiver Total Gain +0019 1451 DS 1 Receiver Amplifier Gain +0019 1452 DS 1 Receiver Preamplifier Gain +0019 1454 DS 1 Receiver Cable Attenuation +0019 1455 DS 1 Receiver Reference Gain +0019 1456 DS 1 Receiver Filter Frequency +0019 1460 DS 1 Focus Alignment +0019 1460 DS 1 Reconstruction Scale Factor +0019 1462 DS 1 Reference Scale Factor +0019 1465 UL 1 Focal Spot Deflection Amplitude +0019 1466 UL 1 Focal Spot Deflection Phase +0019 1467 UL 1 Focal Spot Deflection Offset +0019 1470 DS 1 Water Scaling Factor +0019 1470 DS 1 Phase Gradient Amplitude +0019 1471 DS 1 Interpolation Factor +0019 1471 DS 1 Readout Gradient Amplitude +0019 1472 DS 1 Selection Gradient Amplitude +0019 1480 DS 3 Gradient Delay Time +0019 1480 CS 1 Patient Region +0019 1482 DS 1 Total Gradient Delay Time +0019 1482 CS 1 Patient Phase of Life +0019 1490 DS 1 Osteo Offset +0019 1490 LO 1 Sensitivity Correction Label +0019 1491 DS 6 Saturation Phase Encoding Vector Coronal Component +0019 1492 DS 6 Saturation Readout Vector Coronal Component +0019 1492 DS 1 Osteo Regression Line Slope +0019 1493 DS 1 Osteo Regression Line Intercept +0019 1494 IS 1 Osteo Standardization Code +0019 1496 IS 1 Osteo Phantom Number +0019 14a0 IS 1 RF Watchdog Mask +0019 14a1 DS 1 EPI Reconstruction Slope +0019 14a2 DS 1 RF Power Error Indicator +0019 14a5 DS 3 Specific Absorption Rate Whole Body +0019 14a6 DS 3 Specific Energy Dose +0019 14b0 DS 1 Feed per Rotation +0019 14b0 UL 1 Adjustment Status Mask +0019 14bd IS 1 Pulmo Trigger Level +0019 14be DS 1 Expiratoric Reserve Volume +0019 14bf DS 1 Vital Capacity +0019 14c0 DS 1 Pulmo Water +0019 14c1 DS 1 Pulmo Air +0019 14c1 DS 6 EPI Capacity +0019 14c2 DS 3 EPI Inductance +0019 14c2 DA 1 PulmoDate +0019 14c3 IS 1-n EPI Switch Configuration Code +0019 14c3 TM 1 PulmoTime +0019 14c4 IS 1-n EPI Switch Hardware Code +0019 14c5 DS 1-n EPI Switch Delay Time +0019 14d1 DS 1 Flow Sensitivity +0019 14d2 CS 1 Calculation Submode +0019 14d3 DS 1 Field of View Ratio +0019 14d4 IS 1 Base Raw Matrix Size +0019 14d5 IS 1 2D Oversampling Lines +0019 14d6 IS 1 3D Phase Oversampling Partitions +0019 14d7 IS 1 Echo Line Position +0019 14d8 IS 1 Echo Column Position +0019 14d9 IS 1 Lines Per Segment +0019 14da CS 1 Phase Coding Direction +0019 1456 DS 1 Receiver Filter Frequency + +0029 1110 CS 1 Window Style +0029 1120 CS 3 Pixel Quality Code +0029 1122 IS 3 Pixel Quality Value +0029 1150 CS 1 Archive Code +0029 1151 CS 1 Exposure Code +0029 1152 IS 1 Sort Code +0029 1160 LO 1 Splash + +0029 1108 CS 1 MedCom Header Type +0029 1109 LO 1 MedCom Header Version +0029 1110 OB 1 MedCom Header Info +0029 1120 OB 1 MedCom History Information +0029 1131 LO 1 PMTF Information 1 +0029 1132 UL 1 PMTF Information 2 +0029 1133 UL 1 PMTF Information 3 +0029 1134 CS 1 PMTF Information 4 +0029 1135 UL 1 PMTF Information 5 +0029 1140 SQ 1 Application Header Sequence +0029 1141 CS 1 Application Header Type +0029 1142 LO 1 Application Header ID +0029 1143 LO 1 Application Header Version +0029 1144 OB 1 Application Header Info +0029 1150 LO 8 Workflow Control Flags +0029 1151 CS 1 Archive Management Flag Keep Online +0029 1152 CS 1 Archive Management Flag Do Not Archive +0029 1153 CS 1 Image Location Status +0029 1154 DS 1 Estimated Retrieve Time +0029 1155 DS 1 Data Size of Retrieved Images + diff --git a/Utilities/ITK/Utilities/gdcm/Dicts/SPI.dic b/Utilities/ITK/Utilities/gdcm/Dicts/SPI.dic new file mode 100644 index 0000000000000000000000000000000000000000..0cd8be9735ee289f7c08af73614dc070bdb1dccf --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/Dicts/SPI.dic @@ -0,0 +1,8 @@ +0009 0010 LO 1 Comments +0009 0015 LO 1 UID +0009 0040 US 1 Data Object Type +0009 0041 SH 1 Data Object Subtype +0011 0010 LO 1 Organ +0011 0015 LO 1 Allergy Indication +0011 0020 LO 1 Pregnancy +0029 0060 LO 1 Compression Algorithm diff --git a/Utilities/ITK/Utilities/gdcm/Dicts/dicomAttributeTypes.dic b/Utilities/ITK/Utilities/gdcm/Dicts/dicomAttributeTypes.dic new file mode 100644 index 0000000000000000000000000000000000000000..fe5cd5bcbfc939bc1914dd31a0a94aa6914aaf48 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/Dicts/dicomAttributeTypes.dic @@ -0,0 +1,46 @@ +Found in : + http://medical.nema.org/dicom/2004/04_15PU.PDF + +Unused till now :-( + + +1.2.840.10008.15.0.3.1 dicomDeviceName +1.2.840.10008.15.0.3.2 dicomDescription +1.2.840.10008.15.0.3.3 dicomManufacturer +1.2.840.10008.15.0.3.4 dicomManufacturerModelName +1.2.840.10008.15.0.3.5 dicomSoftwareVersion +1.2.840.10008.15.0.3.6 dicomVendorData +1.2.840.10008.15.0.3.7 dicomAETitle +1.2.840.10008.15.0.3.8 dicomNetworkConnectionReference +1.2.840.10008.15.0.3.9 dicomApplicationCluster +1.2.840.10008.15.0.3.10 dicomAssociationInitiator +1.2.840.10008.15.0.3.11 dicomAssociationAcceptor +1.2.840.10008.15.0.3.12 dicomHostname +1.2.840.10008.15.0.3.13 dicomPort +1.2.840.10008.15.0.3.14 dicomSOPClass +1.2.840.10008.15.0.3.15 dicomTransferRole +1.2.840.10008.15.0.3.16 dicomTransferSyntax +1.2.840.10008.15.0.3.17 dicomPrimaryDeviceType +1.2.840.10008.15.0.3.18 dicomRelatedDeviceReference +1.2.840.10008.15.0.3.19 dicomPreferredCalledAETitle +1.2.840.10008.15.0.3.20 dicomTLSCyphersuite +1.2.840.10008.15.0.3.21 dicomAuthorizedNodeCertificateReference +1.2.840.10008.15.0.3.22 dicomThisNodeCertificateReference +1.2.840.10008.15.0.3.23 dicomInstalled +1.2.840.10008.15.0.3.24 dicomStationName +1.2.840.10008.15.0.3.25 dicomDeviceSerialNumber +1.2.840.10008.15.0.3.26 dicomInstitutionName +1.2.840.10008.15.0.3.27 dicomInstitutionAddress +1.2.840.10008.15.0.3.28 dicomInstitutionDepartmentName +1.2.840.10008.15.0.3.29 dicomIssuerOfPatientID +1.2.840.10008.15.0.3.30 dicomPreferredCallingAETitle +1.2.840.10008.15.0.3.31 dicomSupportedCharacterSet +1.2.840.10008.15.0.4.1 dicomConfigurationRoot +1.2.840.10008.15.0.4.2 dicomDevicesRoot +1.2.840.10008.15.0.4.3 dicomUniqueAETitlesRegistryRoot +1.2.840.10008.15.0.4.4 dicomDevice +1.2.840.10008.15.0.4.5 dicomNetworkAE +1.2.840.10008.15.0.4.6 dicomNetworkConnection +1.2.840.10008.15.0.4.7 dicomUniqueAETitle +1.2.840.10008.15.0.4.8 dicomTransferCapability + diff --git a/Utilities/ITK/Utilities/gdcm/Dicts/dicomGroupNameAbbreviations.dic b/Utilities/ITK/Utilities/gdcm/Dicts/dicomGroupNameAbbreviations.dic new file mode 100644 index 0000000000000000000000000000000000000000..a56d3203f827e63a661c6a0261946ef41d525582 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/Dicts/dicomGroupNameAbbreviations.dic @@ -0,0 +1,63 @@ +// Group Number +// NHI Abbreviation (when known) - not part of DICOM standard - +// Meaning (when known) - not part of DICOM standard - + +0000 CMD Command +0002 META Meta Elements +0004 DIR Directory +0008 ID Identification Informations +0010 PAT Patient Informations +0012 CLI Clinical Trial Informations +0018 ACQ Acquisition Informations +0020 REL Relationship Informations +0022 ??? ??? +0028 IMG Image Informations +0032 SDY Study Informations +0038 VIS Visit Information +003a WAV Waveform Information +0040 PRC Procedure Informations +0050 DEV Device Informations +0054 NMI Nuclear Medicine +0060 HIS Histogram +0070 ??? ??? +0088 MED Medicine +0100 ??? ??? +0400 ??? ??? +2000 BFS ??? +2010 BFB ??? +2020 BIB ??? +2030 BAB ??? +2040 IOB ??? +2050 ??? ??? +2100 PJ ??? +2110 PRINTER Printer +2130 ??? ??? +2200 ??? ??? +3002 RT Radiotherapy +3004 DVH ??? +3006 SSET ??? +3008 ??? ??? +300a RT Radiotherapy +300c RT Radiotherapy +300e RT Radiotherapy +4008 RES Results +4ffe ??? ??? +5000 CRV Curve +5002 CRV Curve +5004 CRV Curve +5006 CRV Curve +5008 CRV Curve +500a CRV Curve +500c CRV Curve +500e CRV Curve +5200 ??? ??? +5400 ??? ??? +5600 ??? ??? +6000 OLY Overlays +6002 OLY Overlays +6004 OLY Overlays +6008 OLY Overlays +600a OLY Overlays +600c OLY Overlays +600e OLY Overlays +7fe0 PXL Pixels diff --git a/Utilities/ITK/Utilities/gdcm/Dicts/dicomTS.dic b/Utilities/ITK/Utilities/gdcm/Dicts/dicomTS.dic new file mode 100644 index 0000000000000000000000000000000000000000..bff4b6331b5b83e32e8905643fc9e71df5a8db13 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/Dicts/dicomTS.dic @@ -0,0 +1,205 @@ +1.2.840.10008.1.2 Implicit VR - Little Endian +1.2.840.10008.1.2.1 Explicit VR - Little Endian +1.2.840.10008.1.2.1.99 Deflated Explicit VR - Little Endian +1.2.840.10008.1.2.2 Explicit VR - Big Endian +1.2.840.10008.1.2.4.50 JPEG Baseline (Process 1) +1.2.840.10008.1.2.4.51 JPEG Extended (Process 2 & 4) +1.2.840.10008.1.2.4.52 JPEG Extended (Process 3 & 5) (Retired) +1.2.840.10008.1.2.4.53 JPEG Spectral Selection, Non-Hierarchical (Process 6 & 8) (Retired) +1.2.840.10008.1.2.4.54 JPEG Spectral Selection, Non-Hierarchical (Process 7 & 9) (Retired) +1.2.840.10008.1.2.4.55 JPEG Full Progression, Non-Hierarchical (Process 10 & 12) (Retired) +1.2.840.10008.1.2.4.56 JPEG Full Progression, Non-Hierarchical (Process 11 & 13) (Retired) +1.2.840.10008.1.2.4.57 JPEG Lossless Non-Hierarchical (Process 14) +1.2.840.10008.1.2.4.58 JPEG Lossless Non-Hierarchical (Process 15) (Retired) +1.2.840.10008.1.2.4.59 JPEG Extended Hierarchical (Process 16 & 18) (Retired) +1.2.840.10008.1.2.4.60 JPEG Spectral Selection, Non-Hierarchical (Process 17 & 19) (Retired) +1.2.840.10008.1.2.4.61 JPEG Spectral Selection, Hierarchical (Process 20 & 22) (Retired) +1.2.840.10008.1.2.4.62 JPEG Spectral Selection, Hierarchical (Process 21 & 23) (Retired) +1.2.840.10008.1.2.4.63 JPEG Full Progression, Hierarchical (Process 24 & 26) (Retired) +1.2.840.10008.1.2.4.64 JPEG Full Progression, Hierarchical (Process 25 & 27) (Retired) +1.2.840.10008.1.2.4.65 JPEG Lossless, Hierarchical (Process 28) (Retired) +1.2.840.10008.1.2.4.66 JPEG Lossless, Hierarchical (Process 29) (Retired)) +1.2.840.10008.1.2.4.70 JPEG Lossless, Non-Hierarchical, First-Order Prediction (Process 14 [Selection Value 1]) +1.2.840.10008.1.2.4.80 JPEG-LS Lossless Image Compression +1.2.840.10008.1.2.4.81 JPEG-LS Lossy (Near-Lossless) Image Compression +1.2.840.10008.1.2.4.90 JPEG 2000 Image Compression (Lossless Only) +1.2.840.10008.1.2.4.91 JPEG 2000 Image Compression +1.2.840.10008.1.2.4.100 MPEG2 Main Profile @ Main Level +1.2.840.10008.1.2.5 RLE Lossless +1.2.840.113619.5.2 Implicit VR - Big Endian (G.E Private) + +1.2.840.10008.1.3.10 Media Storage Directory Storage +1.2.840.10008.1.4.1.1 Talairach Brain Atlas Frame of Reference +1.2.840.10008.1.4.1.2 SPM2 T1 Frame of Reference +1.2.840.10008.1.4.1.3 SPM2 T2 Frame of Reference +1.2.840.10008.1.4.1.4 SPM2 PD Frame of Reference +1.2.840.10008.1.4.1.5 SPM2 EPI Frame of Reference +1.2.840.10008.1.4.1.6 SPM2 FIL T1 Frame of Reference +1.2.840.10008.1.4.1.7 SPM2 PET Frame of Reference +1.2.840.10008.1.4.1.8 SPM2 TRANSM Frame of Reference +1.2.840.10008.1.4.1.9 SPM2 SPECT Frame of Reference +1.2.840.10008.1.4.1.10 SPM2 GRAY Frame of Reference +1.2.840.10008.1.4.1.11 SPM2 WHITE Frame of Reference +1.2.840.10008.1.4.1.12 SPM2 CSF Frame of Reference +1.2.840.10008.1.4.1.13 SPM2 BRAINMASK Frame of Reference +1.2.840.10008.1.4.1.14 SPM2 AVG305T1 Frame of Reference +1.2.840.10008.1.4.1.15 SPM2 AVG152T1 Frame of Reference +1.2.840.10008.1.4.1.16 SPM2 AVG152T2 Frame of Reference +1.2.840.10008.1.4.1.17 SPM2 AVG152PD Frame of Reference +1.2.840.10008.1.4.1.18 SPM2 SINGLESUBJT1 Frame of Reference +1.2.840.10008.1.4.2.1 ICBM 452 T1 Frame of Reference +1.2.840.10008.1.4.2.2 ICBM Single Subject MRI Frame of Reference + +1.2.840.10008.1.1 Verification SOP Class +1.2.840.10008.1.9 Basic Study Content Notification SOP Class +1.2.840.10008.1.20.1 Image Commitment Push Model SOP Class +1.2.840.10008.1.20.1.1 Image Commitment Push Model SOP Instance +1.2.840.10008.1.20.2 Image Commitment Push Model SOP Class (Retired) +1.2.840.10008.1.20.2.1 Image Commitment Push Model SOP Instance (Retired) + +1.2.840.10008.1.40 Procedural Event Logging SOP Class +1.2.840.10008.1.40.1 Procedural Event Logging SOP Instance +1.2.840.10008.2.16.4 DICOM Controlled Terminology +1.2.840.10008.3.1.1.1 DICOM Application Context Name +1.2.840.10008.3.1.2.1.1 Detached Patient Management SOP Class +1.2.840.10008.3.1.2.1.4 Detached Patient Management Meta SOP Class +1.2.840.10008.3.1.2.2.1 Detached Visit Management SOP Class +1.2.840.10008.3.1.2.3.1 Detached Study Management SOP Class +1.2.840.10008.3.1.2.3.2 Study Component Management SOP Class +1.2.840.10008.3.1.2.3.3 Modality Performed Procedure Step SOP Class +1.2.840.10008.3.1.2.3.4 Modality Performed Procedure Step Retrieve SOP Class +1.2.840.10008.3.1.2.3.5 Modality Performed Procedure Step Notification SOP Class +1.2.840.10008.3.1.2.5.1 Detached Results Management SOP Class +1.2.840.10008.3.1.2.5.4 Detached Results Management Meta SOP Class +1.2.840.10008.3.1.2.5.5 Detached Study Management Meta SOP Class +1.2.840.10008.3.1.2.6.1 Detached Interpretation Management SOP Class + +1.2.840.10008.4.2 Storage Device Class + +1.2.840.10008.5.1.1.1 Basic Film Session SOP Class +1.2.840.10008.5.1.1.2 Basic Film Box SOP Class +1.2.840.10008.5.1.1.4 Basic Gray Scale Image Box SOP Class +1.2.840.10008.5.1.1.4.1 Basic Color Image Box SOP Class +1.2.840.10008.5.1.1.4.2 Referenced Image Box SOP Class (Retired) +1.2.840.10008.5.1.1.9 Basic Gray Scale Print Management Meta SOP Class +1.2.840.10008.5.1.1.9.1 Referenced Gray Scale Print Management Meta SOP Class(Retired) +1.2.840.10008.5.1.1.14 Print Job SOP Class +1.2.840.10008.5.1.1.15 Basic Annotation Box SOP Class +1.2.840.10008.5.1.1.16 Printer SOP Class +1.2.840.10008.5.1.1.16.376 Printer Configuration Retrieval SOP Class +1.2.840.10008.5.1.1.17 Printer SOP Instance +1.2.840.10008.5.1.1.17.376 Printer Configuration Retrieval SOP Instance +1.2.840.10008.5.1.1.18 Basic Color Print Management Meta SOP Class +1.2.840.10008.5.1.1.18.1 Referenced Color Print Management Meta SOP Class (Retired) +1.2.840.10008.5.1.1.22 VOI LUT Box SOP Class +1.2.840.10008.5.1.1.23 Presentation LUT Box SOP Class +1.2.840.10008.5.1.1.24 Image Overlay Box SOP Class (Retired) +1.2.840.10008.5.1.1.24.1 Basic Print Image Overlay Box SOP Class +1.2.840.10008.5.1.1.25 Print Queue SOP Instance +1.2.840.10008.5.1.1.26 Print Queue Management SOP Class +1.2.840.10008.5.1.1.27 Stored Print Storage SOP Class +1.2.840.10008.5.1.1.29 Hardcopy Grayscale Image Storage SOP Class +1.2.840.10008.5.1.1.30 Hardcopy Color Image Storage SOP Class +1.2.840.10008.5.1.1.31 Pull Print Request SOP Class +1.2.840.10008.5.1.1.32 Pull Stored Print Management Meta SOP Class +1.2.840.10008.5.1.1.33 Media Creation Management SOP Class UID + +1.2.840.10008.5.1.4.1.1.1 Computed Radiography Image Storage +1.2.840.10008.5.1.4.1.1.1.1 Digital X-Ray Image Storage - For Presentation +1.2.840.10008.5.1.4.1.1.1.1.1 Digital X-Ray Image Storage - For Processing +1.2.840.10008.5.1.4.1.1.1.2 Digital Mammography Image Storage - For Presentation +1.2.840.10008.5.1.4.1.1.1.2.1 Digital Mammography Image Storage - For Processing +1.2.840.10008.5.1.4.1.1.1.3 Digital Intra-oral X-ray Image Storage - For Presentation +1.2.840.10008.5.1.4.1.1.1.3.1 Digital Intra-oral X-Ray Image Storage - For Processing +1.2.840.10008.5.1.4.1.1.2 CT Image Storage +1.2.840.10008.5.1.4.1.1.2.1 Enhanced CT Image Storage + +1.2.840.10008.5.1.4.1.1.3 Ultrasound Multi-Frame Image Storage (Retired) +1.2.840.10008.5.1.4.1.1.3.1 Ultrasound Multi-Frame Image Storage +1.2.840.10008.5.1.4.1.1.4 MR Image Storage +1.2.840.10008.5.1.4.1.1.4.1 Enhanced MR Image Storage +1.2.840.10008.5.1.4.1.1.4.2 MR Spectroscopy Storage +1.2.840.10008.5.1.4.1.1.5 Nuclear Medicine Image Storage (Retired) +1.2.840.10008.5.1.4.1.1.6 Ultrasound Image Storage (Retired) +1.2.840.10008.5.1.4.1.1.6.1 Ultrasound Image Storage +1.2.840.10008.5.1.4.1.1.7 Secondary Capture Image Storage +1.2.840.10008.5.1.4.1.1.7.1 Multi-frame Single Bit Secondary Capture Image Storage +1.2.840.10008.5.1.4.1.1.7.2 Multi-frame Grayscale Byte Secondary Capture Image Storage +1.2.840.10008.5.1.4.1.1.7.3 Multi-frame Grayscale Word Secondary Capture Image Storage +1.2.840.10008.5.1.4.1.1.7.4 Multi-frame True Color Secondary Capture Image Storage +1.2.840.10008.5.1.4.1.1.8 Standalone Overlay Storage +1.2.840.10008.5.1.4.1.1.9 Standalone Curve Storage +1.2.840.10008.5.1.4.1.1.9.1.1 12-Lead ECG Waveform Storage +1.2.840.10008.5.1.4.1.1.9.1.2 General ECG Waveform Storage +1.2.840.10008.5.1.4.1.1.9.1.3 Ambulatory ECG Waveform Storage +1.2.840.10008.5.1.4.1.1.9.2.1 Hemodynamic Waveform Storage +1.2.840.10008.5.1.4.1.1.9.3.1 Cardiac Electrophysiology Waveform Storage +1.2.840.10008.5.1.4.1.1.9.4.1 Basic Voice Audio Waveform Storage +1.2.840.10008.5.1.4.1.1.10 Standalone Modality LUT Storage +1.2.840.10008.5.1.4.1.1.11 Standalone VOI LUT Storage +1.2.840.10008.5.1.4.1.1.11.1 Grayscale Softcopy Presentation State Storage SOP Class +1.2.840.10008.5.1.4.1.1.12.1 X-Ray Angiographic Image Storage +1.2.840.10008.5.1.4.1.1.12.2 X-Ray Radiofluoroscoping Image Storage +1.2.840.10008.5.1.4.1.1.12.3 X-Ray Angiographic Bi-Plane Image Storage (Retired) +1.2.840.10008.5.1.4.1.1.20 Nuclear Medicine Image Storage +1.2.840.10008.5.1.4.1.1.66 Raw Data Storage +1.2.840.10008.5.1.4.1.1.66.1 Spacial Registration Storage +1.2.840.10008.5.1.4.1.1.66.2 Spacial Fiducials Storage + +1.2.840.10008.5.1.4.1.1.77.1 VL Image Storage (Retired) +1.2.840.10008.5.1.4.1.1.77.2 VL MultiFrame Image Storage (Retired) +1.2.840.10008.5.1.4.1.1.77.1.1 VL Endoscoping Image Storage +1.2.840.10008.5.1.4.1.1.77.1.1.1 Video Endoscoping Image Storage +1.2.840.10008.5.1.4.1.1.77.1.2 VL Microscoping Image Storage +1.2.840.10008.5.1.4.1.1.77.1.2.1 Video Microscoping Image Storage +1.2.840.10008.5.1.4.1.1.77.1.3 VL Slide-Coordinates Microscoping Image Storage +1.2.840.10008.5.1.4.1.1.77.1.4 VL Photographic Image Storage +1.2.840.10008.5.1.4.1.1.77.1.4.1 Video Photographic Image Storage +1.2.840.10008.5.1.4.1.1.77.1.5.1 Ophthalmic Photography 8 Bit Image Storage +1.2.840.10008.5.1.4.1.1.77.1.5.2 Ophthalmic Photography 16 Bit Image Storage +1.2.840.10008.5.1.4.1.1.77.1.5.3 Stereometric Relationship Storage + +1.2.840.10008.5.1.4.1.1.88.1 SR Text Storage +1.2.840.10008.5.1.4.1.1.88.2 SR Audio Storage +1.2.840.10008.5.1.4.1.1.88.3 SR Detail Storage +1.2.840.10008.5.1.4.1.1.88.4 SR Comprehensive Storage +1.2.840.10008.5.1.4.1.1.88.11 Basic Text SR +1.2.840.10008.5.1.4.1.1.88.22 Enhanced SR +1.2.840.10008.5.1.4.1.1.88.33 Comprehensive SR +1.2.840.10008.5.1.4.1.1.88.40 Procedure Log Storage +1.2.840.10008.5.1.4.1.1.88.50 Mammography CAD SR +1.2.840.10008.5.1.4.1.1.88.59 Key Object Selection Document +1.2.840.10008.5.1.4.1.1.88.65 Chest CAD SR +1.2.840.10008.5.1.4.1.1.104.1 Encapsulated PDF Storage +1.2.840.10008.5.1.4.1.1.128 Positron Emission Tomography Image Storage +1.2.840.10008.5.1.4.1.1.129 Standalone PET Curve Storage +1.2.840.10008.5.1.4.1.1.481.1 RT Image Storage +1.2.840.10008.5.1.4.1.1.481.2 RT Dose Storage +1.2.840.10008.5.1.4.1.1.481.3 RT Structure Set Storage +1.2.840.10008.5.1.4.1.1.481.4 RT Beams Treatment Record Storage +1.2.840.10008.5.1.4.1.1.481.5 RT Plan Storage +1.2.840.10008.5.1.4.1.1.481.6 RT Brachy Treatment Record Storage +1.2.840.10008.5.1.4.1.1.481.7 RT Treatment Summary Record Storage + +1.2.840.10008.5.1.4.1.2.1.1 Patient Root Query/Retrieve Information Model - FIND +1.2.840.10008.5.1.4.1.2.1.2 Patient Root Query/Retrieve Information Model - MOVE +1.2.840.10008.5.1.4.1.2.1.3 Patient Root Query/Retrieve Information Model - GET +1.2.840.10008.5.1.4.1.2.2.1 Study Root Query/Retrieve Information Model - FIND +1.2.840.10008.5.1.4.1.2.2.2 Study Root Query/Retrieve Information Model - MOVE +1.2.840.10008.5.1.4.1.2.2.3 Study Root Query/Retrieve Information Model - GET +1.2.840.10008.5.1.4.1.2.3.1 Patient/Study Only Query/Retrieve Information Model - FIND +1.2.840.10008.5.1.4.1.2.3.2 Patient/Study Only Query/Retrieve Information Model - GET +1.2.840.10008.5.1.4.1.2.3.3 Patient/Study Only Query/Retrieve Information Model - MOVE +1.2.840.10008.5.1.4.31 Modality Worklist Information Model - FIND +1.2.840.10008.5.1.4.32.1 General Purpose Worklist Information Model - FIND +1.2.840.10008.5.1.4.32.2 General Purpose Scheduled Procedure Step SOP Class +1.2.840.10008.5.1.4.32.3 General Purpose Performed Procedure Step SOP Class +1.2.840.10008.5.1.4.32 General Purpose Worklist Management Meta SOP Class +1.2.840.10008.5.1.4.33 Instance Availability Notification SOP Class +1.2.840.10008.5.1.4.37.1 General Relevant Patient Information Query +1.2.840.10008.5.1.4.37.2 Breast Imaging Relevant Patient Information Query +1.2.840.10008.5.1.4.37.3 Cardiac Relevant Patient Information Query + +1.2.840.113619.5.2 Implicit VR Big Endian DLX (G.E Private) +1.3.12.2.1107.5.9.1 CSA Non-Image Storage +1.3.46.670589.2.5.1.1 3D Subpage Storage diff --git a/Utilities/ITK/Utilities/gdcm/Dicts/dicomV3.dic b/Utilities/ITK/Utilities/gdcm/Dicts/dicomV3.dic new file mode 100644 index 0000000000000000000000000000000000000000..eb61dbff3f62af3e37ff95632121d542357fb773 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/Dicts/dicomV3.dic @@ -0,0 +1,2560 @@ +0000 0000 UL 1 Group Length +0000 0001 UL 1 Command Length to End (RET) +0000 0002 UI 1 Affected SOP Class UID +0000 0003 UI 1 Requested SOP Class UID +0000 0010 SH 1 Command Recognition Code (RET) +0000 0100 US 1 Command Field +0000 0110 US 1 Message ID (first) +0000 0120 US 1 Message ID Responded to +0000 0600 AE 1 Move Destination +0000 0700 US 1 Priority +0000 0800 US 1 Data Set Type +0000 0900 US 1 Status +0000 0901 AT 1 Offending Element +0000 0902 LO 1 Error Comment +0000 0903 US 1 Error ID +0000 1001 UI 1 SOP Requested Instance UID +0000 1000 UI 1 SOP Affected Instance UID +0000 1002 US 1 Event Type ID +0000 1008 US 1 Action Type ID +0000 1020 US 1 Remaining Suboperations +0000 1021 US 1 Completed Suboperations +0000 1022 US 1 Failed Suboperations +0000 1023 US 1 Warning Suboperations +0000 1030 AE 1 AE Title +0000 1031 US 1 Message ID (second) +0000 1005 AT 1 Attribute Identifier List + +0002 0000 UL 1 Group Length +0002 0001 OB 1 File Meta Information Version +0002 0002 UI 1 Media Storage SOP Class UID +0002 0003 UI 1 Media Storage SOP Instance UID +0002 0010 UI 1 Transfer Syntax UID +0002 0012 UI 1 Implementation Class UID +0002 0013 SH 1 Implementation Version Name +0002 0016 AE 1 Source Application Entity Title +0002 0100 UI 1 Private Information Creator UID +0002 0102 OB 1 Private Information + +0004 0000 UL 1 Group Length +0004 1130 CS 1 File-set ID +0004 1141 CS 1-8 File-set Descriptor File ID +0004 1142 CS 1 Specific Character Set of File-set Descriptor File +0004 1200 UL 1 Offset of the First Directory Record of the Root Directory Entity +0004 1202 UL 1 Offset of the Last Directory Record of the Root Directory Entity +0004 1212 US 1 File-set Consistency Flag +0004 1220 SQ 1 Directory Record Sequence +0004 1400 UL 1 Offset of the Next Directory Record +0004 1410 US 1 Record In-use Flag +0004 1420 UL 1 Offset of Referenced Lower-Level Directory Entity +0004 1430 CS 1 Directory Record Type +0004 1432 UI 1 Private Record UID +0004 1500 CS 1-8 Referenced File ID +0004 1504 UL 1 MRDR Directory Record Offset +0004 1510 UI 1 Referenced SOP Class UID in File +0004 1511 UI 1 Referenced SOP Instance UID in File +0004 1512 UI 1 Referenced Transfer Syntax UID in File +0004 151a UI 1-n Referenced Related General SOP Class UID in File +0004 1600 UL 1 Number of References + +0008 0000 UL 1 Group Length +0008 0001 UL 1 Length to End (RET) +0008 0005 CS 1-n Specific Character Set +0008 0008 CS 1-n Image Type +0008 0010 LO 1 Recognition Code (RET) +0008 0012 DA 1 Instance Creation Date +0008 0013 TM 1 Instance Creation Time +0008 0014 UI 1 Instance Creator UID +0008 0016 UI 1 SOP Class UID +0008 0018 UI 1 SOP Instance UID +0008 001a UI 1-n Related General SOP Class UID +0008 001b UI 1 Original Specialized SOP Class UID +0008 0020 DA 1 Study Date +0008 0021 DA 1 Series Date +0008 0022 DA 1 Acquisition Date +0008 0023 DA 1 Content Date +0008 0024 DA 1 Overlay Date +0008 0025 DA 1 Curve Date +0008 002a DT 1 Acquisition Datetime +0008 0030 TM 1 Study Time +0008 0031 TM 1 Series Time +0008 0032 TM 1 Acquisition Time +0008 0033 TM 1 Content Time +0008 0034 TM 1 Overlay Time +0008 0035 TM 1 Curve Time +0008 0040 SS 1 Data Set Type (RET) +0008 0041 LO 1 Data Set Subtype (RET) +0008 0042 CS 1 Nuclear Medicine Series Type (RET) +0008 0050 SH 1 Accession Number +0008 0052 CS 1 Query/Retrieve Level +0008 0054 AE 1-n Retrieve AE Title +0008 0056 CS 1 Instance Availability +0008 0058 UI 1-n Failed SOP Instance UID List +0008 0060 CS 1 Modality +0008 0061 CS 1-n Modalities in Study +0008 0062 UI 1-n SOP Classes in Study +0008 0064 CS 1 Conversion Type +0008 0068 CS 1 Presentation Intent Type +0008 0070 LO 1 Manufacturer +0008 0080 LO 1 Institution Name +0008 0081 ST 1 Institution Address +0008 0082 SQ 1 Institution Code Sequence +0008 0090 PN 1 Referring Physician's Name +0008 0092 ST 1 Referring Physician's Address +0008 0094 SH 1-n Referring Physician's Telephone Numbers +0008 0096 SQ 1 Referring Physician Identification Sequence +0008 0100 SH 1 Code Value +0008 0102 SH 1 Coding Scheme Designator +0008 0103 SH 1 Coding Scheme Version +0008 0104 LO 1 Code Meaning +0008 0105 CS 1 Mapping Resource +0008 0106 DT 1 Context Group Version +0008 0107 DT 1 Context Group Local Version +0008 010b CS 1 Context Group Extension Flag +0008 010c UI 1 Coding Scheme UID +0008 010d UI 1 Context Group Extension Creator UID +0008 010f CS 1 Context Identifier +0008 0110 SQ 1 Coding Scheme Identification Sequence +0008 0112 LO 1 Coding Scheme Registry +0008 0114 ST 1 Coding Scheme External ID +0008 0115 ST 1 Coding Scheme Name +0008 0116 ST 1 Responsible Organization +0008 0201 SH 1 Timezone Offset From UTC +0008 1000 LT 1 Network ID (RET) +0008 1010 SH 1 Station Name +0008 1030 LO 1 Study Description +0008 1032 SQ 1 Procedure Code Sequence +0008 103e LO 1 Series Description +0008 1040 LO 1 Institutional Department Name +0008 1048 PN 1-n Physician(s) of Record +0008 1049 SQ 1 Physician(s) of Record Identification Sequence +0008 1050 PN 1-n Performing Physician's Name +0008 1052 SQ 1 Performing Physician Identification Sequence +0008 1060 PN 1-n Name of Physician(s) Reading Study +0008 1062 SQ 1 Physician(s) Reading Study Identification Sequence +0008 1070 PN 1-n Operator's Name +0008 1072 SQ 1 Operator Identification Sequence +0008 1080 LO 1-n Admitting Diagnoses Description +0008 1084 SQ 1 Admitting Diagnoses Code Sequence +0008 1090 LO 1 Manufacturer's Model Name +0008 1100 SQ 1 Referenced Results Sequence +0008 1110 SQ 1 Referenced Study Sequence +0008 1111 SQ 1 Referenced Performed Procedure Step Sequence +0008 1115 SQ 1 Referenced Series Sequence +0008 1120 SQ 1 Referenced Patient Sequence +0008 1125 SQ 1 Referenced Visit Sequence +0008 1130 SQ 1 Referenced Overlay Sequence +0008 113a SQ 1 Referenced Waveform Sequence +0008 1140 SQ 1 Referenced Image Sequence +0008 1145 SQ 1 Referenced Curve Sequence +0008 114a SQ 1 Referenced Instance Sequence +0008 1150 UI 1 Referenced SOP Class UID +0008 1155 UI 1 Referenced SOP Instance UID +0008 115a UI 1-n SOP Classes Supported +0008 1160 IS 1-n Referenced Frame Number +0008 1195 UI 1 Transaction UID +0008 1197 US 1 Failure Reason +0008 1198 SQ 1 Failed SOP Sequence +0008 1199 SQ 1 Referenced SOP Sequence +0008 1200 SQ 1 Studies Containing Other Referenced Instances Sequence +0008 1250 SQ 1 Related Series Sequence +0008 2110 CS 1 Lossy Image Compression (RET) +0008 2111 ST 1 Derivation Description +0008 2112 SQ 1 Source Image Sequence +0008 2120 SH 1 Stage Name +0008 2122 IS 1 Stage Number +0008 2124 IS 1 Number of Stages +0008 2127 SH 1 View Name +0008 2128 IS 1 View Number +0008 2129 IS 1 Number of Event Timers +0008 212a IS 1 Number of Views in Stage +0008 2130 DS 1-n Event Elapsed Time(s) +0008 2132 LO 1-n Event Timer Name(s) +0008 2142 IS 1 Start Trim +0008 2143 IS 1 Stop Trim +0008 2144 IS 1 Recommended Display Frame Rate +0008 2200 CS 1 Transducer Position (RET) +0008 2204 CS 1 Transducer Orientation (RET) +0008 2208 CS 1 Anatomic Structure (RET) +0008 2218 SQ 1 Anatomic Region Sequence +0008 2220 SQ 1 Anatomic Region Modifier Sequence +0008 2228 SQ 1 Primary Anatomic Structure Sequence +0008 2229 SQ 1 Anatomic Structure, Space or Region Sequence +0008 2230 SQ 1 Primary Anatomic Structure Modifier Sequence +0008 2240 SQ 1 Transducer Position Sequence +0008 2242 SQ 1 Transducer Position Modifier Sequence +0008 2244 SQ 1 Transducer Orientation Sequence +0008 2246 SQ 1 Transducer Orientation Modifier Sequence +0008 3001 SQ 1 Alternate Representation Sequence +0008 4000 LT 1-n Identifying Comments (RET) +0008 9007 CS 4 Frame Type +0008 9092 SQ 1 Referenced Image Evidence Sequence +0008 9121 SQ 1 Referenced Raw Data Sequence +0008 9123 UI 1 Creator-Version UID +0008 9124 SQ 1 Derivation Image Sequence +0008 9154 SQ 1 Source Image Evidence Sequence +0008 9205 CS 1 Pixel Presentation +0008 9206 CS 1 Volumetric Properties +0008 9207 CS 1 Volume Based Calculation Technique +0008 9208 CS 1 Complex Image Component +0008 9209 CS 1 Acquisition Contrast +0008 9215 SQ 1 Derivation Code Sequence +0008 9237 SQ 1 Referenced Grayscale Presentation State Sequence + +0010 0000 UL 1 Group Length +0010 0010 PN 1 Patient's Name +0010 0020 LO 1 Patient ID +0010 0021 LO 1 Issuer of Patient ID +0010 0030 DA 1 Patient's Birth Date +0010 0032 TM 1 Patient's Birth Time +0010 0040 CS 1 Patient's Sex +0010 0050 SQ 1 Patient's Insurance Plan Code Sequence +0010 0101 SQ 1 Patient's Primary Language Code Sequence +0010 0102 SQ 1 Patient's Primary Language Code Modifier Sequence +0010 1000 LO 1-n Other Patient IDs +0010 1001 PN 1-n Other Patient Names +0010 1005 PN 1 Patient's Birth Name +0010 1010 AS 1 Patient's Age +0010 1020 DS 1 Patient's Size +0010 1030 DS 1 Patient's Weight +0010 1040 LO 1 Patient's Address +0010 1050 LT 1-n Insurance Plan Identification (RET) +0010 1060 PN 1 Patient's Mother's Birth Name +0010 1080 LO 1 Military Rank +0010 1081 LO 1 Branch of Service +0010 1090 LO 1 Medical Record Locator +0010 2000 LO 1-n Medical Alerts +0010 2110 LO 1-n Contrast Allergies +0010 2150 LO 1 Country of Residence +0010 2152 LO 1 Region of Residence +0010 2154 SH 1-n Patient's Telephone Numbers +0010 2160 SH 1 Ethnic Group +0010 2180 SH 1 Occupation +0010 21a0 CS 1 Smoking Status +0010 21b0 LT 1 Additional Patient History +0010 21c0 US 1 Pregnancy Status +0010 21d0 DA 1 Last Menstrual Date +0010 21f0 LO 1 Patient's Religious Preference +0010 4000 LT 1 Patient Comments + +0012 0010 LO 1 Clinical Trial Sponsor Name +0012 0020 LO 1 Clinical Trial Protocol ID +0012 0021 LO 1 Clinical Trial Protocol Name +0012 0030 LO 1 Clinical Trial Site ID +0012 0031 LO 1 Clinical Trial Site Name +0012 0040 LO 1 Clinical Trial Subject ID +0012 0042 LO 1 Clinical Trial Subject Reading ID +0012 0050 LO 1 Clinical Trial Time Point ID +0012 0051 ST 1 Clinical Trial Time Point Description +0012 0060 LO 1 Clinical Trial Coordinating Center Name + +0018 0000 UL 1 Group Length +0018 0010 LO 1 Contrast/Bolus Agent +0018 0012 SQ 1 Contrast/Bolus Agent Sequence +0018 0014 SQ 1 Contrast/Bolus Administration Route Sequence +0018 0015 CS 1 Body Part Examined +0018 0020 CS 1-n Scanning Sequence +0018 0021 CS 1-n Sequence Variant +0018 0022 CS 1-n Scan Options +0018 0023 CS 1 MR Acquisition Type +0018 0024 SH 1 Sequence Name +0018 0025 CS 1 Angio Flag +0018 0026 SQ 1 Intervention Drug Information Sequence +0018 0027 TM 1 Intervention Drug Stop Time +0018 0028 DS 1 Intervention Drug Dose +0018 0029 SQ 1 Intervention Drug Sequence +0018 002a SQ 1 Additional Drug Sequence +0018 0030 LO 1-n Radionuclide (RET) +0018 0031 LO 1 Radiopharmaceutical +0018 0032 DS 1 Energy Window Centerline (RET) +0018 0033 DS 1-n Energy Window Total Width (RET) +0018 0034 LO 1 Intervention Drug Name +0018 0035 TM 1 Intervention Drug Start Time +0018 0036 SQ 1 Intervention Sequence +0018 0037 CS 1 Therapy Type (RET) +0018 0038 CS 1 Intervention Status +0018 0039 CS 1 Therapy Description (RET) +0018 003a ST 1 Intervention Description +0018 0040 IS 1 Cine Rate +0018 0050 DS 1 Slice Thickness +0018 0060 DS 1 KVP +0018 0070 IS 1 Counts Accumulated +0018 0071 CS 1 Acquisition Termination Condition +0018 0072 DS 1 Effective Duration +0018 0073 CS 1 Acquisition Start Condition +0018 0074 IS 1 Acquisition Start Condition Data +0018 0075 IS 1 Acquisition Termination Condition Data +0018 0080 DS 1 Repetition Time +0018 0081 DS 1 Echo Time +0018 0082 DS 1 Inversion Time +0018 0083 DS 1 Number of Averages +0018 0084 DS 1 Imaging Frequency +0018 0085 SH 1 Imaged Nucleus +0018 0086 IS 1-n Echo Number(s) +0018 0087 DS 1 Magnetic Field Strength +0018 0088 DS 1 Spacing Between Slices +0018 0089 IS 1 Number of Phase Encoding Steps +0018 0090 DS 1 Data Collection Diameter +0018 0091 IS 1 Echo Train Length +0018 0093 DS 1 Percent Sampling +0018 0094 DS 1 Percent Phase Field of View +0018 0095 DS 1 Pixel Bandwidth +0018 1000 LO 1 Device Serial Number +0018 1004 LO 1 Plate ID +0018 1010 LO 1 Secondary Capture Device ID +0018 1011 LO 1 Hardcopy Creation Device ID +0018 1012 DA 1 Date of Secondary Capture +0018 1014 TM 1 Time of Secondary Capture +0018 1016 LO 1 Secondary Capture Device Manufacturer +0018 1017 LO 1 Hardcopy Device Manufacturer +0018 1018 LO 1 Secondary Capture Device Manufacturer's Model Name +0018 1019 LO 1-n Secondary Capture Device Software Version(s) +0018 101a LO 1-n Hardcopy Device Software Version +0018 101b LO 1 Hardcopy Device Manufacturer's Model Name +0018 1020 LO 1-n Software Version(s) +0018 1022 SH 1 Video Image Format Acquired +0018 1023 LO 1 Digital Image Format Acquired +0018 1030 LO 1 Protocol Name +0018 1040 LO 1 Contrast/Bolus Route +0018 1041 DS 1 Contrast/Bolus Volume +0018 1042 TM 1 Contrast/Bolus Start Time +0018 1043 TM 1 Contrast/Bolus Stop Time +0018 1044 DS 1 Contrast/Bolus Total Dose +0018 1045 IS 1 Syringe Counts +0018 1046 DS 1-n Contrast Flow Rate +0018 1047 DS 1-n Contrast Flow Duration +0018 1048 CS 1 Contrast/Bolus Ingredient +0018 1049 DS 1 Contrast/Bolus Ingredient Concentration +0018 1050 DS 1 Spatial Resolution +0018 1060 DS 1 Trigger Time +0018 1061 LO 1 Trigger Source or Type +0018 1062 IS 1 Nominal Interval +0018 1063 DS 1 Frame Time +0018 1064 LO 1 Framing Type +0018 1065 DS 1-n Frame Time Vector +0018 1066 DS 1 Frame Delay +0018 1067 DS 1 Image Trigger Delay +0018 1068 DS 1 Multiplex Group Time Offset +0018 1069 DS 1 Trigger Time Offset +0018 106a CS 1 Synchronization Trigger +0018 106c US 2 Synchronization Channel +0018 106e UL 1 Trigger Sample Position +0018 1070 LO 1 Radiopharmaceutical Route +0018 1071 DS 1 Radiopharmaceutical Volume +0018 1072 TM 1 Radiopharmaceutical Start Time +0018 1073 TM 1 Radiopharmaceutical Stop Time +0018 1074 DS 1 Radionuclide Total Dose +0018 1075 DS 1 Radionuclide Half Life +0018 1076 DS 1 Radionuclide Positron Fraction +0018 1077 DS 1 Radiopharmaceutical Specific Activity +0018 1080 CS 1 Beat Rejection Flag +0018 1081 IS 1 Low R-R Value +0018 1082 IS 1 High R-R Value +0018 1083 IS 1 Intervals Acquired +0018 1084 IS 1 Intervals Rejected +0018 1085 LO 1 PVC Rejection +0018 1086 IS 1 Skip Beats +0018 1088 IS 1 Heart Rate +0018 1090 IS 1 Cardiac Number of Images +0018 1094 IS 1 Trigger Window +0018 1100 DS 1 Reconstruction Diameter +0018 1110 DS 1 Distance Source to Detector +0018 1111 DS 1 Distance Source to Patient +0018 1114 DS 1 Estimated Radiographic Magnification Factor +0018 1120 DS 1 Gantry/Detector Tilt +0018 1121 DS 1 Gantry/Detector Slew +0018 1130 DS 1 Table Height +0018 1131 DS 1 Table Traverse +0018 1134 CS 1 Table Motion +0018 1135 DS 1-n Table Vertical Increment +0018 1136 DS 1-n Table Lateral Increment +0018 1137 DS 1-n Table Longitudinal Increment +0018 1138 DS 1 Table Angle +0018 113a CS 1 Table Type +0018 1140 CS 1 Rotation Direction +0018 1141 DS 1 Angular Position +0018 1142 DS 1-n Radial Position +0018 1143 DS 1 Scan Arc +0018 1144 DS 1 Angular Step +0018 1145 DS 1 Center of Rotation Offset +0018 1146 DS 1-n Rotation Offset (RET) +0018 1147 CS 1 Field of View Shape +0018 1149 IS 1-2 Field of View Dimension(s) +0018 1150 IS 1 Exposure Time +0018 1151 IS 1 X-ray Tube Current +0018 1152 IS 1 Exposure +0018 1153 IS 1 Exposure in uAs +0018 1154 DS 1 Average Pulse Width +0018 1155 CS 1 Radiation Setting +0018 1156 CS 1 Rectification Type +0018 115a CS 1 Radiation Mode +0018 115e DS 1 Image Area Dose Product +0018 1160 SH 1 Filter Type +0018 1161 LO 1-n Type of Filters +0018 1162 DS 1 Intensifier Size +0018 1164 DS 2 Imager Pixel Spacing +0018 1166 CS 1-n Grid +0018 1170 IS 1 Generator Power +0018 1180 SH 1 Collimator/grid Name +0018 1181 CS 1 Collimator Type +0018 1182 IS 1-2 Focal Distance +0018 1183 DS 1-2 X Focus Center +0018 1184 DS 1-2 Y Focus Center +0018 1190 DS 1-n Focal Spot(s) +0018 1191 CS 1 Anode Target Material +0018 11a0 DS 1 Body Part Thickness +0018 11a2 DS 1 Compression Force +0018 1200 DA 1-n Date of Last Calibration +0018 1201 TM 1-n Time of Last Calibration +0018 1210 SH 1-n Convolution Kernel +0018 1240 IS 1-n Upper/Lower Pixel Values (RET) +0018 1242 IS 1 Actual Frame Duration +0018 1243 IS 1 Count Rate +0018 1244 US 1 Preferred Playback Sequencing +0018 1250 SH 1 Receive Coil Name +0018 1251 SH 1 Transmit Coil Name +0018 1260 SH 1 Plate Type +0018 1261 LO 1 Phosphor Type +0018 1300 DS 1 Scan Velocity +0018 1301 CS 1-n Whole Body Technique +0018 1302 IS 1 Scan Length +0018 1310 US 4 Acquisition Matrix +0018 1312 CS 1 In-plane Phase Encoding Direction +0018 1314 DS 1 Flip Angle +0018 1315 CS 1 Variable Flip Angle Flag +0018 1316 DS 1 SAR +0018 1318 DS 1 dB/dt +0018 1400 LO 1 Acquisition Device Processing Description +0018 1401 LO 1 Acquisition Device Processing Code +0018 1402 CS 1 Cassette Orientation +0018 1403 CS 1 Cassette Size +0018 1404 US 1 Exposures on Plate +0018 1405 IS 1 Relative X-ray Exposure +0018 1450 DS 1 Column Angulation +0018 1460 DS 1 Tomo Layer Height +0018 1470 DS 1 Tomo Angle +0018 1480 DS 1 Tomo Time +0018 1490 CS 1 Tomo Type +0018 1491 CS 1 Tomo Class +0018 1495 IS 1 Number of Tomosynthesis Source Images +0018 1500 CS 1 Positioner Motion +0018 1508 CS 1 Positioner Type +0018 1510 DS 1 Positioner Primary Angle +0018 1511 DS 1 Positioner Secondary Angle +0018 1520 DS 1-n Positioner Primary Angle Increment +0018 1521 DS 1-n Positioner Secondary Angle Increment +0018 1530 DS 1 Detector Primary Angle +0018 1531 DS 1 Detector Secondary Angle +0018 1600 CS 1-3 Shutter Shape +0018 1602 IS 1 Shutter Left Vertical Edge +0018 1604 IS 1 Shutter Right Vertical Edge +0018 1606 IS 1 Shutter Upper Horizontal Edge +0018 1608 IS 1 Shutter Lower Horizontal Edge +0018 1610 IS 2 Center of Circular Shutter +0018 1612 IS 1 Radius of Circular Shutter +0018 1620 IS 2-2n Vertices of the Polygonal Shutter +0018 1622 US 1 Shutter Presentation Value +0018 1623 US 1 Shutter Overlay Group +0018 1700 CS 1-3 Collimator Shape +0018 1702 IS 1 Collimator Left Vertical Edge +0018 1704 IS 1 Collimator Right Vertical Edge +0018 1706 IS 1 Collimator Upper Horizontal Edge +0018 1708 IS 1 Collimator Lower Horizontal Edge +0018 1710 IS 2 Center of Circular Collimator +0018 1712 IS 1 Radius of Circular Collimator +0018 1720 IS 2-2n Vertices of the Polygonal Collimator +0018 1800 CS 1 Acquisition Time Synchronized +0018 1801 SH 1 Time Source +0018 1802 CS 1 Time Distribution Protocol +0018 1803 LO 1 NTP Source Address +0018 2001 IS 1-n Page Number Vector +0018 2002 SH 1-n Frame Label Vector +0018 2003 DS 1-n Frame Primary Angle Vector +0018 2004 DS 1-n Frame Secondary Angle Vector +0018 2005 DS 1-n Slice Location Vector +0018 2006 SH 1-n Display Window Label Vector +0018 2010 DS 2 Nominal Scanned Pixel Spacing +0018 2020 CS 1 Digitizing Device Transport Direction +0018 2030 DS 1 Rotation of Scanned Film +0018 3100 CS 1 IVUS Acquisition +0018 3101 DS 1 IVUS Pullback Rate +0018 3102 DS 1 IVUS Gated Rate +0018 3103 IS 1 IVUS Pullback Start Frame Number +0018 3104 IS 1 IVUS Pullback Stop Frame Number +0018 3105 IS 1-n Lesion Number +0018 4000 LO 1-n Acquisition Comments (RET) +0018 5000 SH 1-n Output Power +0018 5010 LO 3 Transducer Data +0018 5012 DS 1 Focus Depth +0018 5020 LO 1 Processing Function +0018 5021 LO 1 Postprocessing Function +0018 5022 DS 1 Mechanical Index +0018 5024 DS 1 Bone Thermal Index +0018 5026 DS 1 Cranial Thermal Index +0018 5027 DS 1 Soft Tissue Thermal Index +0018 5028 DS 1 Soft Tissue-focus Thermal Index +0018 5029 DS 1 Soft Tissue-surface Thermal Index +0018 5030 DS 1 Dynamic Range (RET) +0018 5040 DS 1 Total Gain (RET) +0018 5050 IS 1 Depth of Scan Field +0018 5100 CS 1 Patient Position +0018 5101 CS 1 View Position +0018 5104 SQ 1 Projection Eponymous Name Code Sequence +0018 5210 DS 6 Image Transformation Matrix (RET) +0018 5212 DS 3 Image Translation Vector (RET) +0018 6000 DS 1 Sensitivity +0018 6011 SQ 1 Sequence of Ultrasound Regions +0018 6012 US 1 Region Spatial Format +0018 6014 US 1 Region Data Type +0018 6016 UL 1 Region Flags +0018 6018 UL 1 Region Location Min X0 +0018 601a UL 1 Region Location Min Y0 +0018 601c UL 1 Region Location Max X1 +0018 601e UL 1 Region Location Max Y1 +0018 6020 SL 1 Reference Pixel X0 +0018 6022 SL 1 Reference Pixel Y0 +0018 6024 US 1 Physical Units X Direction +0018 6026 US 1 Physical Units Y Direction +0018 6028 FD 1 Reference Pixel Physical Value X +0018 602a FD 1 Reference Pixel Physical Value Y +0018 602c FD 1 Physical Delta X +0018 602e FD 1 Physical Delta Y +0018 6030 UL 1 Transducer Frequency +0018 6031 CS 1 Transducer Type +0018 6032 UL 1 Pulse Repetition Frequency +0018 6034 FD 1 Doppler Correction Angle +0018 6036 FD 1 Steering Angle +0018 6038 UL 1 Doppler Sample Volume X Position (RET) +0018 6039 SL 1 Doppler Sample Volume X Position +0018 603a UL 1 Doppler Sample Volume Y Position (RET) +0018 603b SL 1 Doppler Sample Volume Y Position +0018 603c UL 1 TM-Line Position X0 (RET) +0018 603d SL 1 TM-Line Position X0 +0018 603e UL 1 TM-Line Position Y0 (RET) +0018 603f SL 1 TM-Line Position Y0 +0018 6040 UL 1 TM-Line Position X1 (RET) +0018 6041 SL 1 TM-Line Position X1 +0018 6042 UL 1 TM-Line Position Y1 (RET) +0018 6043 SL 1 TM-Line Position Y1 +0018 6044 US 1 Pixel Component Organization +0018 6046 UL 1 Pixel Component Mask +0018 6048 UL 1 Pixel Component Range Start +0018 604a UL 1 Pixel Component Range Stop +0018 604c US 1 Pixel Component Physical Units +0018 604e US 1 Pixel Component Data Type +0018 6050 UL 1 Number of Table Break Points +0018 6052 UL 1-n Table of X Break Points +0018 6054 FD 1-n Table of Y Break Points +0018 6056 UL 1 Number of Table Entries +0018 6058 UL 1-n Table of Pixel Values +0018 605a FL 1-n Table of Parameter Values +0018 6060 FL 1-n R Wave Time Vector +0018 7000 CS 1 Detector Conditions Nominal Flag +0018 7001 DS 1 Detector Temperature +0018 7004 CS 1 Detector Type +0018 7005 CS 1 Detector Configuration +0018 7006 LT 1 Detector Description +0018 7008 LT 1 Detector Mode +0018 700a SH 1 Detector ID +0018 700c DA 1 Date of Last Detector Calibration +0018 700e TM 1 Time of Last Detector Calibration +0018 7010 IS 1 Exposures on Detector Since Last Calibration +0018 7011 IS 1 Exposures on Detector Since Manufactured +0018 7012 DS 1 Detector Time Since Last Exposure +0018 7014 DS 1 Detector Active Time +0018 7016 DS 1 Detector Activation Offset From Exposure +0018 701a DS 2 Detector Binning +0018 7020 DS 2 Detector Element Physical Size +0018 7022 DS 2 Detector Element Spacing +0018 7024 CS 1 Detector Active Shape +0018 7026 DS 1-2 Detector Active Dimension(s) +0018 7028 DS 2 Detector Active Origin +0018 702a LO 1 Detector Manufacturer Name +0018 702b LO 1 Detector Manufacturer's Model Name +0018 7030 DS 2 Field of View Origin +0018 7032 DS 1 Field of View Rotation +0018 7034 CS 1 Field of View Horizontal Flip +0018 7040 LT 1 Grid Absorbing Material +0018 7041 LT 1 Grid Spacing Material +0018 7042 DS 1 Grid Thickness +0018 7044 DS 1 Grid Pitch +0018 7046 IS 2 Grid Aspect Ratio +0018 7048 DS 1 Grid Period +0018 704c DS 1 Grid Focal Distance +0018 7050 CS 1-n Filter Material +0018 7052 DS 1-n Filter Thickness Minimum +0018 7054 DS 1-n Filter Thickness Maximum +0018 7060 CS 1 Exposure Control Mode +0018 7062 LT 1 Exposure Control Mode Description +0018 7064 CS 1 Exposure Status +0018 7065 DS 1 Phototimer Setting +0018 8150 DS 1 Exposure Time in �S +0018 8151 DS 1 X-Ray Tube Current in �A +0018 9004 CS 1 Content Qualification +0018 9005 SH 1 Pulse Sequence Name +0018 9006 SQ 1 MR Imaging Modifier Sequence +0018 9008 CS 1 Echo Pulse Sequence +0018 9009 CS 1 Inversion Recovery +0018 9010 CS 1 Flow Compensation +0018 9011 CS 1 Multiple Spin Echo +0018 9012 CS 1 Multi-planar Excitation +0018 9014 CS 1 Phase Contrast +0018 9015 CS 1 Time of Flight Contrast +0018 9016 CS 1 Spoiling +0018 9017 CS 1 Steady State Pulse Sequence +0018 9018 CS 1 Echo Planar Pulse Sequence +0018 9019 FD 1 Tag Angle First Axis +0018 9020 CS 1 Magnetization Transfer +0018 9021 CS 1 T2 Preparation +0018 9022 CS 1 Blood Signal Nulling +0018 9024 CS 1 Saturation Recovery +0018 9025 CS 1 Spectrally Selected Suppression +0018 9026 CS 1 Spectrally Selected Excitation +0018 9027 CS 1 Spatial Pre-saturation +0018 9028 CS 1 Tagging +0018 9029 CS 1 Oversampling Phase +0018 9030 FD 1 Tag Spacing First Dimension +0018 9032 CS 1 Geometry of k-Space Traversal +0018 9033 CS 1 Segmented k-Space Traversal +0018 9034 CS 1 Rectilinear Phase Encode Reordering +0018 9035 FD 1 Tag Thickness +0018 9036 CS 1 Partial Fourier Direction +0018 9037 CS 1 Cardiac Synchronization Technique +0018 9041 LO 1 Receive Coil Manufacturer Name +0018 9042 SQ 1 MR Receive Coil Sequence +0018 9043 CS 1 Receive Coil Type +0018 9044 CS 1 Quadrature Receive Coil +0018 9045 SQ 1 Multi-Coil Definition Sequence +0018 9046 LO 1 Multi-Coil Configuration +0018 9047 SH 1 Multi-Coil Element Name +0018 9048 CS 1 Multi-Coil Element Used +0018 9049 SQ 1 MR Transmit Coil Sequence +0018 9050 LO 1 Transmit Coil Manufacturer Name +0018 9051 CS 1 Transmit Coil Type +0018 9052 FD 1-2 Spectral Width +0018 9053 FD 1-2 Chemical Shift Reference +0018 9054 CS 1 Volume Localization Technique +0018 9058 US 1 MR Acquisition Frequency Encoding Steps +0018 9059 CS 1 De-coupling +0018 9060 CS 1-2 De-coupled Nucleus +0018 9061 FD 1-2 De-coupling Frequency +0018 9062 CS 1 De-coupling Method +0018 9063 FD 1-2 De-coupling Chemical Shift Reference +0018 9064 CS 1 k-space Filtering +0018 9065 CS 1-2 Time Domain Filtering +0018 9066 US 1-2 Number of Zero fills +0018 9067 CS 1 Baseline Correction +0018 9069 FD 1 Parallel Reduction Factor In-plane +0018 9070 FD 1 Cardiac R-R Interval Specified +0018 9073 FD 1 Acquisition Duration +0018 9074 DT 1 Frame Acquisition Datetime +0018 9075 CS 1 Diffusion Directionality +0018 9076 SQ 1 Diffusion Gradient Direction Sequence +0018 9077 CS 1 Parallel Acquisition +0018 9078 CS 1 Parallel Acquisition Technique +0018 9079 FD 1-n Inversion Times +0018 9080 ST 1 Metabolite Map Description +0018 9081 CS 1 Partial Fourier +0018 9082 FD 1 Effective Echo Time +0018 9083 SQ 1 Metabolite Map Code Sequence +0018 9084 SQ 1 Chemical Shift Sequence +0018 9085 CS 1 Cardiac Signal Source +0018 9087 FD 1 Diffusion b-value +0018 9089 FD 3 Diffusion Gradient Orientation +0018 9090 FD 3 Velocity Encoding Direction +0018 9091 FD 1 Velocity Encoding Minimum Value +0018 9093 US 1 Number of k-Space Trajectories +0018 9094 CS 1 Coverage of k-Space +0018 9095 UL 1 Spectroscopy Acquisition Phase Rows +0018 9098 FD 1-2 Transmitter Frequency +0018 9100 CS 1-2 Resonant Nucleus +0018 9101 CS 1 Frequency Correction +0018 9103 SQ 1 MR Spectroscopy FOV/Geometry Sequence +0018 9104 FD 1 Slab Thickness +0018 9105 FD 3 Slab Orientation +0018 9106 FD 3 Mid Slab Position +0018 9107 SQ 1 MR Spatial Saturation Sequence +0018 9112 SQ 1 MR Timing and Related Parameters Sequence +0018 9114 SQ 1 MR Echo Sequence +0018 9115 SQ 1 MR Modifier Sequence +0018 9117 SQ 1 MR Diffusion Sequence +0018 9118 SQ 1 Cardiac Trigger Sequence +0018 9119 SQ 1 MR Averages Sequence +0018 9125 SQ 1 MR FOV/Geometry Sequence +0018 9126 SQ 1 Volume Localization Sequence +0018 9127 UL 1 Spectroscopy Acquisition Data Columns +0018 9147 CS 1 Diffusion Anisotropy Type +0018 9151 DT 1 Frame Reference Datetime +0018 9152 SQ 1 MR Metabolite Map Sequence +0018 9155 FD 1 Parallel Reduction Factor out-of-plane +0018 9159 UL 1 Spectroscopy Acquisition Out-of-plane Phase Steps +0018 9166 CS 1 Bulk Motion Status +0018 9168 FD 1 Parallel Reduction Factor Second In-plane +0018 9169 CS 1 Cardiac Beat Rejection Technique +0018 9170 CS 1 Respiratory Motion Compensation Technique +0018 9171 CS 1 Respiratory Signal Source +0018 9172 CS 1 Bulk Motion Compensation Technique +0018 9173 CS 1 Bulk Motion Signal Source +0018 9174 CS 1 Applicable Safety Standard Agency +0018 9175 LO 1 Applicable Safety Standard Description +0018 9176 SQ 1 Operating Mode Sequence +0018 9177 CS 1 Operating Mode Type +0018 9178 CS 1 Operating Mode +0018 9179 CS 1 Specific Absorption Rate Definition +0018 9180 CS 1 Gradient Output Type +0018 9181 FD 1 Specific Absorption Rate Value +0018 9182 FD 1 Gradient Output +0018 9183 CS 1 Flow Compensation Direction +0018 9184 FD 1 Tagging Delay +0018 9195 FD 1 Chemical Shifts Minimum Integration Limit in Hz (RET) +0018 9196 FD 1 Chemical Shifts Maximum Integration Limit in Hz (RET) +0018 9197 SQ 1 MR Velocity Encoding Sequence +0018 9198 CS 1 First Order Phase Correction +0018 9199 CS 1 Water Referenced Phase Correction +0018 9200 CS 1 MR Spectroscopy Acquisition Type +0018 9214 CS 1 Respiratory Cycle Position +0018 9217 FD 1 Velocity Encoding Maximum Value +0018 9218 FD 1 Tag Spacing Second Dimension +0018 9219 SS 1 Tag Angle Second Axis +0018 9220 FD 1 Frame Acquisition Duration +0018 9226 SQ 1 MR Image Frame Type Sequence +0018 9227 SQ 1 MR Spectroscopy Frame Type Sequence +0018 9231 US 1 MR Acquisition Phase Encoding Steps in-plane +0018 9232 US 1 MR Acquisition Phase Encoding Steps out-of-plane +0018 9234 UL 1 Spectroscopy Acquisition Phase Columns +0018 9236 CS 1 Cardiac Cycle Position +0018 9239 SQ 1 Specific Absorption Rate Sequence +0018 9295 FD 1 Chemical Shifts Minimum Integration Limit in ppm +0018 9296 FD 1 Chemical Shifts Maximum Integration Limit in ppm +0018 9240 US 1 RF Echo Train Length +0018 9241 US 1 Gradient Echo Train Length +0018 9301 SQ 1 CT Acquisition Type Sequence +0018 9302 CS 1 Acquisition Type +0018 9303 FD 1 Tube Angle +0018 9304 SQ 1 CT Acquisition Details Sequence +0018 9305 FD 1 Revolution Time +0018 9306 FD 1 Single Collimation Width +0018 9307 FD 1 Total Collimation Width +0018 9308 SQ 1 CT Table Dynamics Sequence +0018 9309 FD 1 Table Speed +0018 9310 FD 1 Table Feed per Rotation +0018 9311 FD 1 Spiral Pitch Factor +0018 9312 SQ 1 CT Geometry Sequence +0018 9313 FD 3 Data Collection Center (Patient) +0018 9314 SQ 1 CT Reconstruction Sequence +0018 9315 CS 1 Reconstruction Algorithm +0018 9316 CS 1 Convolution Kernel Group +0018 9317 FD 2 Reconstruction Field of View +0018 9318 FD 3 Reconstruction Target Center (Patient) +0018 9319 FD 1 Reconstruction Angle +0018 9320 SH 1 Image Filter +0018 9321 SQ 1 CT Exposure Sequence +0018 9322 FD 2 Reconstruction Pixel Spacing +0018 9323 CS 1 Exposure Modulation Type +0018 9324 FD 1 Estimated Dose Saving +0018 9325 SQ 1 CT X-ray Details Sequence +0018 9326 SQ 1 CT Position Sequence +0018 9327 FD 1 Table Position +0018 9328 FD 1 Exposure Time in ms +0018 9329 SQ 1 CT Image Frame Type Sequence +0018 9330 FD 1 X-Ray Tube Current in mA +0018 9332 FD 1 Exposure in mAs +0018 9333 CS 1 Constant Volume Flag +0018 9334 CS 1 Fluoroscopy Flag +0018 9335 FD 1 Distance Source to Data Collection Center +0018 9337 US 1 Contrast/Bolus Agent Number +0018 9338 SQ 1 Contrast/Bolus Ingredient Code Sequence +0018 9340 SQ 1 Contrast Administration Profile Sequence +0018 9341 SQ 1 Contrast/Bolus Usage Sequence +0018 9342 CS 1 Contrast/Bolus Agent Administered +0018 9343 CS 1 Contrast/Bolus Agent Detected +0018 9344 CS 1 Contrast/Bolus Agent Phase +0018 9345 FD 1 CTDIvol +0018 a001 SQ 1 Contributing Equipment Sequence +0018 a002 DT 1 Contribution Date Time +0018 a003 ST 1 Contribution Description + +0020 0000 UL 1 Group Length +0020 000d UI 1 Study Instance UID +0020 000e UI 1 Series Instance UID +0020 0010 SH 1 Study ID +0020 0011 IS 1 Series Number +0020 0012 IS 1 Acquisition Number +0020 0013 IS 1 Instance Number +0020 0014 IS 1 Isotope Number (RET) +0020 0015 IS 1 Phase Number (RET) +0020 0016 IS 1 Interval Number (RET) +0020 0017 IS 1 Time Slot Number (RET) +0020 0018 IS 1 Angle Number (RET) +0020 0019 IS 1 Item Number +0020 0020 CS 2 Patient Orientation +0020 0022 IS 1 Overlay Number +0020 0024 IS 1 Curve Number +0020 0026 IS 1 Lookup Table Number +0020 0030 DS 3 Image Position (RET) +0020 0032 DS 3 Image Position (Patient) +0020 0035 DS 6 Image Orientation (RET) +0020 0037 DS 6 Image Orientation (Patient) +0020 0050 DS 1 Location (RET) +0020 0052 UI 1 Frame of Reference UID +0020 0060 CS 1 Laterality +0020 0062 CS 1 Image Laterality +0020 0070 LO 1 Image Geometry Type (RET) +0020 0080 LT 1-n Masking Image (RET) +0020 0100 IS 1 Temporal Position Identifier +0020 0105 IS 1 Number of Temporal Positions +0020 0110 DS 1 Temporal Resolution +0020 0200 UI 1 Synchronization Frame of Reference UID +0020 1000 IS 1 Series in Study +0020 1001 IS 1 Acquisitions in Series (RET) +0020 1002 IS 1 Images in Acquisition +0020 1003 IS 1 Images in Series FIXME (RET) +0020 1004 IS 1 Acquisitions in Study +0020 1005 IS 1 Images in Study FIXME (RET) +0020 1020 LO 1-n Reference (RET) +0020 1040 LO 1 Position Reference Indicator +0020 1041 DS 1 Slice Location +0020 1070 IS 1-n Other Study Numbers +0020 1200 IS 1 Number of Patient Related Studies +0020 1202 IS 1 Number of Patient Related Series +0020 1204 IS 1 Number of Patient Related Instances +0020 1206 IS 1 Number of Study Related Series +0020 1208 IS 1 Number of Study Related Instances +0020 1209 IS 1 Number of Series Related Instances +0020 3100 LO 1-n Source Image IDs (RET) +0020 3401 LO 1 Modifying Device ID (RET) +0020 3402 LO 1 Modified Image ID (RET) +0020 3403 DA 1 Modified Image Date (RET) +0020 3404 LT 1 Modifying Device Manufacturer (RET) +0020 3405 TM 1 Modified Image Time (RET) +0020 3406 LT 1 Modified Image Description (RET) +0020 4000 LT 1 Image Comments +0020 5000 AT 1-n Original Image Identification (RET) +0020 5002 LO 1-n Original Image Identification Nomenclature (RET) +0020 9056 SH 1 Stack ID +0020 9057 UL 1 In-Stack Position Number +0020 9071 SQ 1 Frame Anatomy Sequence +0020 9072 CS 1 Frame Laterality +0020 9111 SQ 1 Frame Content Sequence +0020 9113 SQ 1 Plane Position Sequence +0020 9116 SQ 1 Plane Orientation Sequence +0020 9128 UL 1 Temporal Position Index +0020 9153 FD 1 Trigger Delay Time +0020 9156 US 1 Frame Acquisition Number +0020 9157 UL 1-n Dimension Index Values +0020 9158 LT 1 Frame Comments +0020 9161 UI 1 Concatenation UID +0020 9162 US 1 In-concatenation Number +0020 9163 US 1 In-concatenation Total Number +0020 9164 UI 1 Dimension Organization UID +0020 9165 AT 1 Dimension Index Pointer +0020 9167 AT 1 Functional Group Pointer +0020 9213 LO 1 Dimension Index Private Creator +0020 9221 SQ 1 Dimension Organization Sequence +0020 9222 SQ 1 Dimension Index Sequence +0020 9228 UL 1 Concatenation Frame Offset Number +0020 9238 LO 1 Functional Group Private Creator + +0022 0001 US 1 Light Path Filter Pass-Through Wavelength +0022 0002 US 2 Light Path Filter Pass Band +0022 0003 US 1 Image Path Filter Pass-Through Wavelength +0022 0004 US 2 Image Path Filter Pass Band +0022 0005 CS 1 Patient Eye Movement Commanded +0022 0006 SQ 1 Patient Eye Movement Command Code Sequence +0022 0007 FL 1 Spherical Lens Power +0022 0008 FL 1 Cylinder Lens Power +0022 0009 FL 1 Cylinder Axis +0022 000a FL 1 Emmetropic Magnification +0022 000b FL 1 Intra Ocular Pressure +0022 000c FL 1 Horizontal Field of View +0022 000d CS 1 Pupil Dilated +0022 000e FL 1 Degree of Dilation +0022 0010 FL 1 Stereo Baseline Angle +0022 0011 FL 1 Stereo Baseline Displacement +0022 0012 FL 1 Stereo Horizontal Pixel Offset +0022 0013 FL 1 Stereo Vertical Pixel Offset +0022 0014 FL 1 Stereo Rotation +0022 0015 SQ 1 Acquisition Device Type Code Sequence +0022 0016 SQ 1 Illumination Type Code Sequence +0022 0017 SQ 1 Light Path Filter Type Stack Code Sequence +0022 0018 SQ 1 Image Path Filter Type Stack Code Sequence +0022 0019 SQ 1 Lenses Code Sequence +0022 001a SQ 1 Channel Description Code Sequence +0022 001b SQ 1 Refractive State Sequence +0022 001c SQ 1 Mydriatic Agent Code Sequence +0022 001d SQ 1 Relative Image Position Code Sequence +0022 0020 SQ 1 Stereo Pairs Sequence +0022 0021 SQ 1 Left Image Sequence +0022 0022 SQ 1 Right Image Sequence + +0028 0000 UL 1 Group Length +0028 0002 US 1 Samples per Pixel +0028 0003 US 1 Samples per Pixel Used +0028 0004 CS 1 Photometric Interpretation +0028 0005 SS 1 Image Dimensions (RET) +0028 0006 US 1 Planar Configuration +0028 0008 IS 1 Number of Frames +0028 0009 AT 1-n Frame Increment Pointer +0028 000a AT 1-n Frame Dimension Pointer +0028 0010 US 1 Rows +0028 0011 US 1 Columns +0028 0012 US 1 Planes +0028 0014 US 1 Ultrasound Color Data Present +0028 0030 DS 2 Pixel Spacing +0028 0031 DS 2 Zoom Factor +0028 0032 DS 2 Zoom Center +0028 0034 IS 2 Pixel Aspect Ratio +0028 0040 SH 1 Image Format (RET) +0028 0050 LO 1-n Manipulated Image (RET) +0028 0051 CS 1-n Corrected Image +0028 0060 SH 1 Compression Code (RET) +0028 0100 US 1 Bits Allocated +0028 0101 US 1 Bits Stored +0028 0102 US 1 High Bit +0028 0103 US 1 Pixel Representation +0028 0104 SS 1 Smallest Valid Pixel Value (RET) +0028 0105 SS 1 Largest Valid Pixel Value (RET) +0028 0106 SS 1 Smallest Image Pixel Value +0028 0107 SS 1 Largest Image Pixel Value +0028 0108 SS 1 Smallest Pixel Value in Series +0028 0109 SS 1 Largest Pixel Value in Series +0028 0110 SS 1 Smallest Image Pixel Value in Plane +0028 0111 SS 1 Largest Image Pixel Value in Plane +0028 0120 SS 1 Pixel Padding Value +0028 0200 SS 1 Image Location (RET) +0028 0300 CS 1 Quality Control Image +0028 0301 CS 1 Burned In Annotation +0028 1040 CS 1 Pixel Intensity Relationship +0028 1041 SS 1 Pixel Intensity Relationship Sign +0028 1050 DS 1-n Window Center +0028 1051 DS 1-n Window Width +0028 1052 DS 1 Rescale Intercept +0028 1053 DS 1 Rescale Slope +0028 1054 LO 1 Rescale Type +0028 1055 LO 1-n Window Center & Width Explanation +0028 1080 LT 1 Gray Scale (RET) +0028 1090 CS 1 Recommended Viewing Mode +0028 1100 US 3 Gray Lookup Table Descriptor (RET) +0028 1101 US 3 Red Palette Color Lookup Table Descriptor +0028 1102 US 3 Green Palette Color Lookup Table Descriptor +0028 1103 US 3 Blue Palette Color Lookup Table Descriptor +0028 1199 UI 1 Palette Color Lookup Table UID +0028 1200 OW 1 Gray Lookup Table Data (RET) +0028 1201 OW 1 Red Palette Color Lookup Table Data +0028 1202 OW 1 Green Palette Color Lookup Table Data +0028 1203 OW 1 Blue Palette Color Lookup Table Data +0028 1221 OW 1 Segmented Red Palette Color Lookup Table Data +0028 1222 OW 1 Segmented Green Palette Color Lookup Table Data +0028 1223 OW 1 Segmented Blue Palette Color Lookup Table Data +0028 1300 CS 1 Implant Present +0028 1350 CS 1 Partial View +0028 1351 ST 1 Partial View Description +0028 2110 CS 1 Lossy Image Compression +0028 2112 DS 1-n Lossy Image Compression Ratio +0028 2114 CS 1-n Lossy Image Compression Method +0028 3000 SQ 1 Modality LUT Sequence +0028 3002 US 3 LUT Descriptor +0028 3003 LO 1 LUT Explanation +0028 3004 LO 1 Modality LUT Type +0028 3006 OW 1 LUT Data +0028 3010 SQ 1 VOI LUT Sequence +0028 3110 SQ 1 Softcopy VOI LUT Sequence +0028 4000 LT 1-n Image Presentation Comments (RET) +0028 5000 SQ 1 Bi-Plane Acquisition Sequence +0028 6010 US 1 Representative Frame Number +0028 6020 US 1-n Frame Numbers of Interest (FOI) +0028 6022 LO 1-n Frame(s) of Interest Description +0028 6023 CS 1-n Frame of Interest Type +0028 6030 US 1-n Mask Pointer(s) (RET) +0028 6040 US 1-n R Wave Pointer +0028 6100 SQ 1 Mask Subtraction Sequence +0028 6101 CS 1 Mask Operation +0028 6102 US 2-2n Applicable Frame Range +0028 6110 US 1-n Mask Frame Numbers +0028 6112 US 1 Contrast Frame Averaging +0028 6114 FL 2 Mask Sub-pixel Shift +0028 6120 SS 1 TID Offset +0028 6190 ST 1 Mask Operation Explanation +0028 9001 UL 1 Data Point Rows +0028 9002 UL 1 Data Point Columns +0028 9003 CS 1 Signal Domain Columns +0028 9099 US 1 Largest Monochrome Pixel Value (RET) +0028 9108 CS 1 Data Representation +0028 9110 SQ 1 Pixel Measures Sequence +0028 9132 SQ 1 Frame VOI LUT Sequence +0028 9145 SQ 1 Pixel Value Transformation Sequence +0028 9235 CS 1 Signal Domain Rows + +0032 0000 UL 1 Study Group Length +0032 000a CS 1 Study Status ID +0032 000c CS 1 Study Priority ID +0032 0012 LO 1 Study ID Issuer +0032 0032 DA 1 Study Verified Date +0032 0033 TM 1 Study Verified Time +0032 0034 DA 1 Study Read Date +0032 0035 TM 1 Study Read Time +0032 1000 DA 1 Scheduled Study Start Date +0032 1001 TM 1 Scheduled Study Start Time +0032 1010 DA 1 Scheduled Study Stop Date +0032 1011 TM 1 Scheduled Study Stop Time +0032 1020 LO 1 Scheduled Study Location +0032 1021 AE 1-n Scheduled Study Location AE Title(s) +0032 1030 LO 1 Reason for Study +0032 1031 SQ 1 Requesting Physician Identification Sequence +0032 1032 PN 1 Requesting Physician +0032 1033 LO 1 Requesting Service +0032 1040 DA 1 Study Arrival Date +0032 1041 TM 1 Study Arrival Time +0032 1050 DA 1 Study Completion Date +0032 1051 TM 1 Study Completion Time +0032 1055 CS 1 Study Component Status ID +0032 1060 LO 1 Requested Procedure Description +0032 1064 SQ 1 Requested Procedure Code Sequence +0032 1070 LO 1 Requested Contrast Agent +0032 4000 LT 1 Study Comments + +0038 0000 UL 1 Group Length +0038 0004 SQ 1 Referenced Patient Alias Sequence +0038 0008 CS 1 Visit Status ID +0038 0010 LO 1 Admission ID +0038 0011 LO 1 Issuer of Admission ID +0038 0016 LO 1 Route of Admissions +0038 001a DA 1 Scheduled Admission Date +0038 001b TM 1 Scheduled Admission Time +0038 001c DA 1 Scheduled Discharge Date +0038 001d TM 1 Scheduled Discharge Time +0038 001e LO 1 Scheduled Patient Institution Residence +0038 0020 DA 1 Admitting Date +0038 0021 TM 1 Admitting Time +0038 0030 DA 1 Discharge Date +0038 0032 TM 1 Discharge Time +0038 0040 LO 1 Discharge Diagnosis Description +0038 0044 SQ 1 Discharge Diagnosis Code Sequence +0038 0050 LO 1 Special Needs +0038 0300 LO 1 Current Patient Location +0038 0400 LO 1 Patient's Institution Residence +0038 0500 LO 1 Patient State +0038 4000 LT 1 Visit Comments + +003a 0000 UL 1 Group Length +003a 0004 CS 1 Waveform Originality +003a 0005 US 1 Number of Waveform Channels +003a 0010 UL 1 Number of Waveform Samples +003a 001a DS 1 Sampling Frequency +003a 0020 SH 1 Multiplex Group Label +003a 0200 SQ 1 Channel Definition Sequence +003a 0202 IS 1 Waveform Channel Number +003a 0203 SH 1 Channel Label +003a 0205 CS 1-n Channel Status +003a 0208 SQ 1 Channel Source Sequence +003a 0209 SQ 1 Channel Source Modifiers Sequence +003a 020a SQ 1 Source Waveform Sequence +003a 020c LO 1 Channel Derivation Description +003a 0210 DS 1 Channel Sensitivity +003a 0211 SQ 1 Channel Sensitivity Units Sequence +003a 0212 DS 1 Channel Sensitivity Correction Factor +003a 0213 DS 1 Channel Baseline +003a 0214 DS 1 Channel Time Skew +003a 0215 DS 1 Channel Sample Skew +003a 0218 DS 1 Channel Offset +003a 021a US 1 Waveform Bits Stored +003a 0220 DS 1 Filter Low Frequency +003a 0221 DS 1 Filter High Frequency +003a 0222 DS 1 Notch Filter Frequency +003a 0223 DS 1 Notch Filter Bandwidth +003a 0300 SQ 1 Multiplexed Audio Channels Description Code Sequence +003a 0301 IS 1 Channel Identification Code +003a 0302 CS 1 Channel Mode + +0040 0000 UL 1 Group Length +0040 0001 AE 1-n Scheduled Station AE Title +0040 0002 DA 1 Scheduled Procedure Step Start Date +0040 0003 TM 1 Scheduled Procedure Step Start Time +0040 0004 DA 1 Scheduled Procedure Step End Date +0040 0005 TM 1 Scheduled Procedure Step End Time +0040 0006 PN 1 Scheduled Performing Physician's Name +0040 0007 LO 1 Scheduled Procedure Step Description +0040 0008 SQ 1 Scheduled Protocol Code Sequence +0040 0009 SH 1 Scheduled Procedure Step ID +0040 000a SQ 1 Stage Code Sequence +0040 000b SQ 1 Scheduled Performing Physician Identification Sequence +0040 0010 SH 1-n Scheduled Station Name +0040 0011 SH 1 Scheduled Procedure Step Location +0040 0012 LO 1 Pre-Medication +0040 0020 CS 1 Scheduled Procedure Step Status +0040 0100 SQ 1 Scheduled Procedure Step Sequence +0040 0220 SQ 1 Referenced Non-Image Composite SOP Instance Sequence +0040 0241 AE 1 Performed Station AE Title +0040 0242 SH 1 Performed Station Name +0040 0243 SH 1 Performed Location +0040 0244 DA 1 Performed Procedure Step Start Date +0040 0245 TM 1 Performed Procedure Step Start Time +0040 0250 DA 1 Performed Procedure Step End Date +0040 0251 TM 1 Performed Procedure Step End Time +0040 0252 CS 1 Performed Procedure Step Status +0040 0253 SH 1 Performed Procedure Step ID +0040 0254 LO 1 Performed Procedure Step Description +0040 0255 LO 1 Performed Procedure Type Description +0040 0260 SQ 1 Performed Protocol Code Sequence +0040 0270 SQ 1 Scheduled Step Attributes Sequence +0040 0275 SQ 1 Request Attributes Sequence +0040 0280 ST 1 Comments on the Performed Procedure Step +0040 0281 SQ 1 Performed Procedure Step Discontinuation Reason Code Sequence +0040 0293 SQ 1 Quantity Sequence +0040 0294 DS 1 Quantity +0040 0295 SQ 1 Measuring Units Sequence +0040 0296 SQ 1 Billing Item Sequence +0040 0300 US 1 Total Time of Fluoroscopy +0040 0301 US 1 Total Number of Exposures +0040 0302 US 1 Entrance Dose +0040 0303 US 1-2 Exposed Area +0040 0306 DS 1 Distance Source to Entrance +0040 0307 DS 1 Distance Source to Support (RET) +0040 030e SQ 1 Exposure Dose Sequence +0040 0310 ST 1 Comments on Radiation Dose +0040 0312 DS 1 X-Ray Output +0040 0314 DS 1 Half Value Layer +0040 0316 DS 1 Organ Dose +0040 0318 CS 1 Organ Exposed +0040 0320 SQ 1 Billing Procedure Step Sequence +0040 0321 SQ 1 Film Consumption Sequence +0040 0324 SQ 1 Billing Supplies and Devices Sequence +0040 0330 SQ 1 Referenced Procedure Step Sequence (RET) +0040 0340 SQ 1 Performed Series Sequence +0040 0400 LT 1 Comments on the Scheduled Procedure Step +0040 0440 SQ 1 Protocol Context Sequence +0040 0441 SQ 1 Content Item Modifier Sequence +0040 050a LO 1 Specimen Accession Number +0040 0550 SQ 1 Specimen Sequence +0040 0551 LO 1 Specimen Identifier +0040 0555 SQ 1 Acquisition Context Sequence +0040 0556 ST 1 Acquisition Context Description +0040 059a SQ 1 Specimen Type Code Sequence +0040 06fa LO 1 Slide Identifier +0040 071a SQ 1 Image Center Point Coordinates Sequence +0040 072a DS 1 X offset in Slide Coordinate System +0040 073a DS 1 Y offset in Slide Coordinate System +0040 074a DS 1 Z offset in Slide Coordinate System +0040 08d8 SQ 1 Pixel Spacing Sequence +0040 08da SQ 1 Coordinate System Axis Code Sequence +0040 08ea SQ 1 Measurement Units Code Sequence +0040 1001 SH 1 Requested Procedure ID +0040 1002 LO 1 Reason for the Requested Procedure +0040 1003 SH 1 Requested Procedure Priority +0040 1004 LO 1 Patient Transport Arrangements +0040 1005 LO 1 Requested Procedure Location +0040 1006 SH 1 Placer Order Number / Procedure (RET) +0040 1007 SH 1 Filler Order Number / Procedure (RET) +0040 1008 LO 1 Confidentiality Code +0040 1009 SH 1 Reporting Priority +0040 100a SQ 1 Reason for Requested Procedure Code Sequence +0040 1010 PN 1-n Names of Intended Recipients of Results +0040 1011 SQ 1 Intended Recipients of Results Identification Sequence +0040 1101 SQ 1 Person Identification Code Sequence +0040 1102 ST 1 Person's Address +0040 1103 LO 1-n Person's Telephone Numbers +0040 1400 LT 1 Requested Procedure Comments +0040 2001 LO 1 Reason for the Imaging Service Request (RET) +0040 2004 DA 1 Issue Date of Imaging Service Request +0040 2005 TM 1 Issue Time of Imaging Service Request +0040 2006 SH 1 Placer Order Number / Imaging Service Request (RET) +0040 2007 SH 1 Filler Order Number / Imaging Service Request (RET) +0040 2008 PN 1 Order Entered By +0040 2009 SH 1 Order Enterer's Location +0040 2010 SH 1 Order Callback Phone Number +0040 2016 LO 1 Placer Order Number / Imaging Service Request +0040 2017 LO 1 Filler Order Number / Imaging Service Request +0040 2400 LT 1 Imaging Service Request Comments +0040 3001 LO 1 Confidentiality Constraint on Patient Data Description +0040 4001 CS 1 General Purpose Scheduled Procedure Step Status +0040 4002 CS 1 General Purpose Performed Procedure Step Status +0040 4003 CS 1 General Purpose Scheduled Procedure Step Priority +0040 4004 SQ 1 Scheduled Processing Applications Code Sequence +0040 4005 DT 1 Scheduled Procedure Step Start Date and Time +0040 4006 CS 1 Multiple Copies Flag +0040 4007 SQ 1 Performed Processing Applications Code Sequence +0040 4009 SQ 1 Human Performer Code Sequence +0040 4010 DT 1 Scheduled Procedure Step Modification Date and Time +0040 4011 DT 1 Expected Completion Date and Time +0040 4015 SQ 1 Resulting General Purpose Performed Procedure Steps Sequence +0040 4016 SQ 1 Referenced General Purpose Scheduled Procedure Step Sequence +0040 4018 SQ 1 Scheduled Workitem Code Sequence +0040 4019 SQ 1 Performed Workitem Code Sequence +0040 4020 CS 1 Input Availability Flag +0040 4021 SQ 1 Input Information Sequence +0040 4022 SQ 1 Relevant Information Sequence +0040 4023 UI 1 Referenced General Purpose Scheduled Procedure Step Transaction UID +0040 4025 SQ 1 Scheduled Station Name Code Sequence +0040 4026 SQ 1 Scheduled Station Class Code Sequence +0040 4027 SQ 1 Scheduled Station Geographic Location Code Sequence +0040 4028 SQ 1 Performed Station Name Code Sequence +0040 4029 SQ 1 Performed Station Class Code Sequence +0040 4030 SQ 1 Performed Station Geographic Location Code Sequence +0040 4031 SQ 1 Requested Subsequent Workitem Code Sequence +0040 4032 SQ 1 Non-DICOM Output Code Sequence +0040 4033 SQ 1 Output Information Sequence +0040 4034 SQ 1 Scheduled Human Performers Sequence +0040 4035 SQ 1 Actual Human Performers Sequence +0040 4036 LO 1 Human Performer's Organization +0040 4037 PN 1 Human Performer's Name +0040 8302 DS 1 Entrance Dose in mGy +0040 9096 SQ 1 Real World Value Mapping Sequence +0040 9210 SH 1 LUT Label +0040 9211 US 1 Real World Value Last Value Mapped +0040 9212 FD 1-n Real World Value LUT Data +0040 9216 US 1 Real World Value First Value Mapped +0040 9224 FD 1 Real World Value Intercept +0040 9225 FD 1 Real World Value Slope +0040 a010 CS 1 Relationship Type +0040 a027 LO 1 Verifying Organization +0040 a030 DT 1 Verification Date Time +0040 a032 DT 1 Observation Date Time +0040 a040 CS 1 Value Type +0040 a043 SQ 1 Concept Name Code Sequence +0040 a050 CS 1 Continuity Of Content +0040 a073 SQ 1 Verifying Observer Sequence +0040 a075 PN 1 Verifying Observer Name +0040 a088 SQ 1 Verifying Observer Identification Code Sequence +0040 a0b0 US 2-2n Referenced Waveform Channels +0040 a120 DT 1 DateTime +0040 a121 DA 1 Date +0040 a122 TM 1 Time +0040 a123 PN 1 Person Name +0040 a124 UI 1 UID +0040 a130 CS 1 Temporal Range Type +0040 a132 UL 1-n Referenced Sample Positions +0040 a136 US 1-n Referenced Frame Numbers +0040 a138 DS 1-n Referenced Time Offsets +0040 a13a DT 1-n Referenced Datetime +0040 a160 UT 1 Text Value +0040 a168 SQ 1 Concept Code Sequence +0040 a170 SQ 1 Purpose of Reference Code Sequence +0040 a180 US 1 Annotation Group Number +0040 a195 SQ 1 Modifier Code Sequence +0040 a300 SQ 1 Measured Value Sequence +0040 a301 SQ 1 Numeric Value Qualifier Code Sequence +0040 a30a DS 1-n Numeric Value +0040 a360 SQ 1 Predecessor Documents Sequence +0040 a370 SQ 1 Referenced Request Sequence +0040 a372 SQ 1 Performed Procedure Code Sequence +0040 a375 SQ 1 Current Requested Procedure Evidence Sequence +0040 a385 SQ 1 Pertinent Other Evidence Sequence +0040 a491 CS 1 Completion Flag +0040 a492 LO 1 Completion Flag Description +0040 a493 CS 1 Verification Flag +0040 a504 SQ 1 Content Template Sequence +0040 a525 SQ 1 Identical Documents Sequence +0040 a730 SQ 1 Content Sequence +0040 b020 SQ 1 Annotation Sequence +0040 db00 CS 1 Template Identifier +0040 db06 DT 1 Template Version (RET) +0040 db07 DT 1 Template Local Version (RET) +0040 db0b CS 1 Template Extension Flag (RET) +0040 db0c UI 1 Template Extension Organization UID (RET) +0040 db0d UI 1 Template Extension Creator UID (RET) +0040 db73 UL 1-n Referenced Content Item Identifier + +0050 0000 UL 1 Group Length +0050 0004 CS 1 Calibration Image +0050 0010 SQ 1 Device Sequence +0050 0014 DS 1 Device Length +0050 0016 DS 1 Device Diameter +0050 0017 CS 1 Device Diameter Units +0050 0018 DS 1 Device Volume +0050 0019 DS 1 Inter-Marker Distance +0050 0020 LO 1 Device Description + +0054 0000 UL 1 Group Length +0054 0010 US 1-n Energy Window Vector +0054 0011 US 1 Number of Energy Windows +0054 0012 SQ 1 Energy Window Information Sequence +0054 0013 SQ 1 Energy Window Range Sequence +0054 0014 DS 1 Energy Window Lower Limit +0054 0015 DS 1 Energy Window Upper Limit +0054 0016 SQ 1 Radiopharmaceutical Information Sequence +0054 0017 IS 1 Residual Syringe Counts +0054 0018 SH 1 Energy Window Name +0054 0020 US 1-n Detector Vector +0054 0021 US 1 Number of Detectors +0054 0022 SQ 1 Detector Information Sequence +0054 0030 US 1-n Phase Vector +0054 0031 US 1 Number of Phases +0054 0032 SQ 1 Phase Information Sequence +0054 0033 US 1 Number of Frames in Phase +0054 0036 IS 1 Phase Delay +0054 0038 IS 1 Pause Between Frames +0054 0039 CS 1 Phase Description +0054 0050 US 1-n Rotation Vector +0054 0051 US 1 Number of Rotations +0054 0052 SQ 1 Rotation Information Sequence +0054 0053 US 1 Number of Frames in Rotation +0054 0060 US 1-n R-R Interval Vector +0054 0061 US 1 Number of R-R Intervals +0054 0062 SQ 1 Gated Information Sequence +0054 0063 SQ 1 Data Information Sequence +0054 0070 US 1-n Time Slot Vector +0054 0071 US 1 Number of Time Slots +0054 0072 SQ 1 Time Slot Information Sequence +0054 0073 DS 1 Time Slot Time +0054 0080 US 1-n Slice Vector +0054 0081 US 1 Number of Slices +0054 0090 US 1-n Angular View Vector +0054 0100 US 1-n Time Slice Vector +0054 0101 US 1 Number of Time Slices +0054 0200 DS 1 Start Angle +0054 0202 CS 1 Type of Detector Motion +0054 0210 IS 1-n Trigger Vector +0054 0211 US 1 Number of Triggers in Phase +0054 0220 SQ 1 View Code Sequence +0054 0222 SQ 1 View Modifier Code Sequence +0054 0300 SQ 1 Radionuclide Code Sequence +0054 0302 SQ 1 Administration Route Code Sequence +0054 0304 SQ 1 Radiopharmaceutical Code Sequence +0054 0306 SQ 1 Calibration Data Sequence +0054 0308 US 1 Energy Window Number +0054 0400 SH 1 Image ID +0054 0410 SQ 1 Patient Orientation Code Sequence +0054 0412 SQ 1 Patient Orientation Modifier Code Sequence +0054 0414 SQ 1 Patient Gantry Relationship Code Sequence +0054 0500 CS 1 Slice Progression Direction +0054 1000 CS 2 Series Type +0054 1001 CS 1 Units +0054 1002 CS 1 Counts Source +0054 1004 CS 1 Reprojection Method +0054 1100 CS 1 Randoms Correction Method +0054 1101 LO 1 Attenuation Correction Method +0054 1102 CS 1 Decay Correction +0054 1103 LO 1 Reconstruction Method +0054 1104 LO 1 Detector Lines of Response Used +0054 1105 LO 1 Scatter Correction Method +0054 1200 DS 1 Axial Acceptance +0054 1201 IS 2 Axial Mash +0054 1202 IS 1 Transverse Mash +0054 1203 DS 2 Detector Element Size +0054 1210 DS 1 Coincidence Window Width +0054 1220 CS 1-n Secondary Counts Type +0054 1300 DS 1 Frame Reference Time +0054 1310 IS 1 Primary (Prompts) Counts Accumulated +0054 1311 IS 1-n Secondary Counts Accumulated +0054 1320 DS 1 Slice Sensitivity Factor +0054 1321 DS 1 Decay Factor +0054 1322 DS 1 Dose Calibration Factor +0054 1323 DS 1 Scatter Fraction Factor +0054 1324 DS 1 Dead Time Factor +0054 1330 US 1 Image Index +0054 1400 CS 1-n Counts Included +0054 1401 CS 1 Dead Time Correction Flag + +0060 0000 UL 1 Group Length +0060 3000 SQ 1 Histogram Sequence +0060 3002 US 1 Histogram Number of Bins +0060 3004 US 1 Histogram First Bin Value +0060 3006 US 1 Histogram Last Bin Value +0060 3008 US 1 Histogram Bin Width +0060 3010 LO 1 Histogram Explanation +0060 3020 UL 1-n Histogram Data + +0070 0000 UL 1 Group Length +0070 0001 SQ 1 Graphic Annotation Sequence +0070 0002 CS 1 Graphic Layer +0070 0003 CS 1 Bounding Box Annotation Units +0070 0004 CS 1 Anchor Point Annotation Units +0070 0005 CS 1 Graphic Annotation Units +0070 0006 ST 1 Unformatted Text Value +0070 0008 SQ 1 Text Object Sequence +0070 0009 SQ 1 Graphic Object Sequence +0070 0010 FL 2 Bounding Box Top Left Hand Corner +0070 0011 FL 2 Bounding Box Bottom Right Hand Corner +0070 0012 CS 1 Bounding Box Text Horizontal Justification +0070 0014 FL 2 Anchor Point +0070 0015 CS 1 Anchor Point Visibility +0070 0020 US 1 Graphic Dimensions +0070 0021 US 1 Number of Graphic Points +0070 0022 FL 2-n Graphic Data +0070 0023 CS 1 Graphic Type +0070 0024 CS 1 Graphic Filled +0070 0041 CS 1 Image Horizontal Flip +0070 0042 US 1 Image Rotation +0070 0052 SL 2 Displayed Area Top Left Hand Corner +0070 0053 SL 2 Displayed Area Bottom Right Hand Corner +0070 005a SQ 1 Displayed Area Selection Sequence +0070 0060 SQ 1 Graphic Layer Sequence +0070 0062 IS 1 Graphic Layer Order +0070 0066 US 1 Graphic Layer Recommended Display Grayscale Value +0070 0067 US 3 Graphic Layer Recommended Display RGB Value +0070 0068 LO 1 Graphic Layer Description +0070 0080 CS 1 Content Label +0070 0081 LO 1 Content Description +0070 0082 DA 1 Presentation Creation Date +0070 0083 TM 1 Presentation Creation Time +0070 0084 PN 1 Content Creator's Name +0070 0100 CS 1 Presentation Size Mode +0070 0101 DS 2 Presentation Pixel Spacing +0070 0102 IS 2 Presentation Pixel Aspect Ratio +0070 0103 FL 1 Presentation Pixel Magnification Ratio +0070 0306 CS 1 Shape Type +0070 0308 SQ 1 Registration Sequence +0070 0309 SQ 1 Matrix Registration Sequence +0070 030a SQ 1 Matrix Sequence +0070 030c CS 1 Frame of Reference Transformation Matrix Type +0070 030d SQ 1 Registration Type Code Sequence +0070 030f ST 1 Fiducial Description +0070 0310 SH 1 Fiducial Identifier +0070 0311 SQ 1 Fiducial Identifier Code Sequence +0070 0312 FD 1 Contour Uncertainty Radius +0070 0314 SQ 1 Used Fiducials Sequence +0070 0318 SQ 1 Graphic Coordinates Data Sequence +0070 031a UI 1 Fiducial UID +0070 031c SQ 1 Fiducial Set Sequence +0070 031e SQ 1 Fiducial Sequence + +0088 0000 UL 1 Group Length +0088 0130 SH 1 Storage Media File-set ID +0088 0140 UI 1 Storage Media File-set UID +0088 0200 SQ 1 Icon Image Sequence +0088 0904 LO 1 Topic Title +0088 0906 ST 1 Topic Subject +0088 0910 LO 1 Topic Author +0088 0912 LO 1-32 Topic Keywords + +0100 0000 UL 1 Group Length +0100 0410 CS 1 SOP Instance Status +0100 0420 DT 1 SOP Authorization Date and Time +0100 0424 LT 1 SOP Authorization Comment +0100 0426 LO 1 Authorization Equipment Certification Number + +0400 0000 UL 1 Group Length +0400 0005 US 1 MAC ID Number +0400 0010 UI 1 MAC Calculation Transfer Syntax UID +0400 0015 CS 1 MAC Algorithm +0400 0020 AT 1-n Data Elements Signed +0400 0100 UI 1 Digital Signature UID +0400 0105 DT 1 Digital Signature DateTime +0400 0110 CS 1 Certificate Type +0400 0115 OB 1 Certificate of Signer +0400 0120 OB 1 Signature +0400 0305 CS 1 Certified Timestamp Type +0400 0310 OB 1 Certified Timestamp +0400 0500 SQ 1 Encrypted Attributes Sequence +0400 0510 UI 1 Encrypted Content Transfer Syntax UID +0400 0520 OB 1 Encrypted Content +0400 0550 SQ 1 Modified Attributes Sequence + +2000 0000 UL 1 Group Length +2000 0010 IS 1 Number of Copies +2000 001e SQ 1 Printer Configuration Sequence +2000 0020 CS 1 Print Priority +2000 0030 CS 1 Medium Type +2000 0040 CS 1 Film Destination +2000 0050 LO 1 Film Session Label +2000 0060 IS 1 Memory Allocation +2000 0061 IS 1 Maximum Memory Allocation +2000 0062 CS 1 Color Image Printing Flag +2000 0063 CS 1 Collation Flag +2000 0065 CS 1 Annotation Flag +2000 0067 CS 1 Image Overlay Flag +2000 0069 CS 1 Presentation LUT Flag +2000 006a CS 1 Image Box Presentation LUT Flag +2000 00a0 US 1 Memory Bit Depth +2000 00a1 US 1 Printing Bit Depth +2000 00a2 SQ 1 Media Installed Sequence +2000 00a4 SQ 1 Other Media Available Sequence +2000 00a8 SQ 1 Supported Image Display Formats Sequence +2000 0500 SQ 1 Referenced Film Box Sequence +2000 0510 SQ 1 Referenced Stored Print Sequence + +2010 0000 UL 1 Group Length +2010 0010 ST 1 Image Display Format +2010 0030 CS 1 Annotation Display Format ID +2010 0040 CS 1 Film Orientation +2010 0050 CS 1 Film Size ID +2010 0052 CS 1 Printer Resolution ID +2010 0054 CS 1 Default Printer Resolution ID +2010 0060 CS 1 Magnification Type +2010 0080 CS 1 Smoothing Type +2010 00a6 CS 1 Default Magnification Type +2010 00a7 CS 1-n Other Magnification Types Available +2010 00a8 CS 1 Default Smoothing Type +2010 00a9 CS 1-n Other Smoothing Types Available +2010 0100 CS 1 Border Density +2010 0110 CS 1 Empty Image Density +2010 0120 US 1 Min Density +2010 0130 US 1 Max Density +2010 0140 CS 1 Trim +2010 0150 ST 1 Configuration Information +2010 0152 LT 1 Configuration Information Description +2010 0154 IS 1 Maximum Collated Films +2010 015e US 1 Illumination +2010 0160 US 1 Reflected Ambient Light +2010 0376 DS 2 Printer Pixel Spacing +2010 0500 SQ 1 Referenced Film Session Sequence +2010 0510 SQ 1 Referenced Image Box Sequence +2010 0520 SQ 1 Referenced Basic Annotation Box Sequence + +2020 0000 UL 1 Group Length +2020 0010 US 1 Image Position +2020 0020 CS 1 Polarity +2020 0030 DS 1 Requested Image Size +2020 0040 CS 1 Requested Decimate/Crop Behavior +2020 0050 CS 1 Requested Resolution ID +2020 00a0 CS 1 Requested Image Size Flag +2020 00a2 CS 1 Decimate/Crop Result +2020 0110 SQ 1 Basic Grayscale Image Sequence +2020 0111 SQ 1 Basic Color Image Sequence +2020 0130 SQ 1 Referenced Image Overlay Box Sequence (RET) +2020 0140 SQ 1 Referenced VOI LUT Box Sequence (RET) + +2030 0000 UL 1 Group Length +2030 0010 US 1 Annotation Position +2030 0020 LO 1 Text String + +2040 0000 UL 1 Group Length +2040 0010 SQ 1 Referenced Overlay Plane Sequence +2040 0011 US 1-99 Referenced Overlay Plane Groups +2040 0020 SQ 1 Overlay Pixel Data Sequence +2040 0060 CS 1 Overlay Magnification Type +2040 0070 CS 1 Overlay Smoothing Type +2040 0072 CS 1 Overlay or Image Magnification +2040 0074 US 1 Magnify to Number of Columns +2040 0080 CS 1 Overlay Foreground Density +2040 0082 CS 1 Overlay Background Density +2040 0090 CS 1 Overlay Mode (RET) +2040 0100 CS 1 Threshold Density (RET) +2040 0500 SQ 1 Referenced Image Box Sequence (RET) + +2050 0000 UL 1 Group Length +2050 0010 SQ 1 Presentation LUT Sequence +2050 0020 CS 1 Presentation LUT Shape +2050 0500 SQ 1 Referenced Presentation LUT Sequence + +2100 0000 UL 1 Group Length +2100 0010 SH 1 Print Job ID +2100 0020 CS 1 Execution Status +2100 0030 CS 1 Execution Status Info +2100 0040 DA 1 Creation Date +2100 0050 TM 1 Creation Time +2100 0070 AE 1 Originator +2100 0140 AE 1 Destination AE +2100 0160 SH 1 Owner ID +2100 0170 IS 1 Number of Films +2100 0500 SQ 1 Referenced Print Job Sequence + +2110 0000 UL 1 Group Length +2110 0010 CS 1 Printer Status +2110 0020 CS 1 Printer Status Info +2110 0030 LO 1 Printer Name +2110 0099 SH 1 Print Queue ID + +2120 0000 UL 1 Group Length +2120 0010 CS 1 Queue Status +2120 0050 SQ 1 Print Job Description Sequence +2120 0070 SQ 1 Referenced Print Job Sequence + +2130 0000 UL 1 Group Length +2130 0010 SQ 1 Print Management Capabilities Sequence +2130 0015 SQ 1 Printer Characteristics Sequence +2130 0030 SQ 1 Film Box Content Sequence +2130 0040 SQ 1 Image Box Content Sequence +2130 0050 SQ 1 Annotation Content Sequence +2130 0060 SQ 1 Image Overlay Box Content Sequence +2130 0080 SQ 1 Presentation LUT Content Sequence +2130 00a0 SQ 1 Proposed Study Sequence +2130 00c0 SQ 1 Original Image Sequence + +2200 0000 UL 1 Group Length +2200 0001 CS 1 Label Using Information Extracted From Instances +2200 0002 UT 1 Label Text +2200 0003 CS 1 Label Style Selection +2200 0004 LT 1 Media Disposition +2200 0005 LT 1 Barcode Value +2200 0006 CS 1 Barcode Symbology +2200 0007 CS 1 Allow Media Splitting +2200 0008 CS 1 Include Non-DICOM Objects +2200 0009 CS 1 Include Display Application +2200 000a CS 1 Preserve Composite Instances After Media Creation +2200 000b US 1 Total Number of Pieces of Media Created +2200 000c LO 1 Requested Media Application Profile +2200 000d SQ 1 Referenced Storage Media Sequence +2200 000e AT 1-n Failure Attributes +2200 000f CS 1 Allow Lossy Compression +2200 0020 CS 1 Request Priority + +3002 0000 UL 1 Group Length +3002 0002 SH 1 RT Image Label +3002 0003 LO 1 RT Image Name +3002 0004 ST 1 RT Image Description +3002 000a CS 1 Reported Values Origin +3002 000c CS 1 RT Image Plane +3002 000d DS 3 X-Ray Image Receptor Translation +3002 000e DS 1 X-Ray Image Receptor Angle +3002 0010 DS 6 RT Image Orientation +3002 0011 DS 2 Image Plane Pixel Spacing +3002 0012 DS 2 RT Image Position +3002 0020 SH 1 Radiation Machine Name +3002 0022 DS 1 Radiation Machine SAD +3002 0024 DS 1 Radiation Machine SSD +3002 0026 DS 1 RT Image SID +3002 0028 DS 1 Source to Reference Object Distance +3002 0029 IS 1 Fraction Number +3002 0030 SQ 1 Exposure Sequence +3002 0032 DS 1 Meterset Exposure +3002 0034 DS 4 Diaphragm Position +3002 0040 SQ 1 Fluence Map Sequence +3002 0041 CS 1 Fluence Data Source +3002 0042 DS 1 Fluence Data Scale + +3004 0000 UL 1 DVH Group Length +3004 0001 CS 1 DVH Type +3004 0002 CS 1 Dose Units +3004 0004 CS 1 Dose Type +3004 0006 LO 1 Dose Comment +3004 0008 DS 3 Normalization Point +3004 000a CS 1 Dose Summation Type +3004 000c DS 2-n Grid Frame Offset Vector +3004 000e DS 1 Dose Grid Scaling +3004 0010 SQ 1 RT Dose ROI Sequence +3004 0012 DS 1 Dose Value +3004 0014 CS 1-3 Tissue Heterogeneity Correction +3004 0040 DS 3 DVH Normalization Point +3004 0042 DS 1 DVH Normalization Dose Value +3004 0050 SQ 1 DVH Sequence +3004 0052 DS 1 DVH Dose Scaling +3004 0054 CS 1 DVH Volume Units +3004 0056 IS 1 DVH Number of Bins +3004 0058 DS 2-2n DVH Data +3004 0060 SQ 1 DVH Referenced ROI Sequence +3004 0062 CS 1 DVH ROI Contribution Type +3004 0070 DS 1 DVH Minimum Dose +3004 0072 DS 1 DVH Maximum Dose +3004 0074 DS 1 DVH Mean Dose + +3006 0000 UL 1 Group Length +3006 0002 SH 1 Structure Set Label +3006 0004 LO 1 Structure Set Name +3006 0006 ST 1 Structure Set Description +3006 0008 DA 1 Structure Set Date +3006 0009 TM 1 Structure Set Time +3006 0010 SQ 1 Referenced Frame of Reference Sequence +3006 0012 SQ 1 RT Referenced Study Sequence +3006 0014 SQ 1 RT Referenced Series Sequence +3006 0016 SQ 1 Contour Image Sequence +3006 0020 SQ 1 Structure Set ROI Sequence +3006 0022 IS 1 ROI Number +3006 0024 UI 1 Referenced Frame of Reference UID +3006 0026 LO 1 ROI Name +3006 0028 ST 1 ROI Description +3006 002a IS 3 ROI Display Color +3006 002c DS 1 ROI Volume +3006 0030 SQ 1 RT Related ROI Sequence +3006 0033 CS 1 RT ROI Relationship +3006 0036 CS 1 ROI Generation Algorithm +3006 0038 LO 1 ROI Generation Description +3006 0039 SQ 1 ROI Contour Sequence +3006 0040 SQ 1 Contour Sequence +3006 0042 CS 1 Contour Geometric Type +3006 0044 DS 1 Contour Slab Thickness +3006 0045 DS 3 Contour Offset Vector +3006 0046 IS 1 Number of Contour Points +3006 0048 IS 1 Contour Number +3006 0049 IS 1-n Attached Contours +3006 0050 DS 3-3n Contour Data +3006 0080 SQ 1 RT ROI Observations Sequence +3006 0082 IS 1 Observation Number +3006 0084 IS 1 Referenced ROI Number +3006 0085 SH 1 ROI Observation Label +3006 0086 SQ 1 RT ROI Identification Code Sequence +3006 0088 ST 1 ROI Observation Description +3006 00a0 SQ 1 Related RT ROI Observations Sequence +3006 00a4 CS 1 RT ROI Interpreted Type +3006 00a6 PN 1 ROI Interpreter +3006 00b0 SQ 1 ROI Physical Properties Sequence +3006 00b2 CS 1 ROI Physical Property +3006 00b4 DS 1 ROI Physical Property Value +3006 00c0 SQ 1 Frame of Reference Relationship Sequence +3006 00c2 UI 1 Related Frame of Reference UID +3006 00c4 CS 1 Frame of Reference Transformation Type +3006 00c6 DS 16 Frame of Reference Transformation Matrix +3006 00c8 LO 1 Frame of Reference Transformation Comment + +3008 0000 UL 1 Group Length +3008 0010 SQ 1 Measured Dose Reference Sequence +3008 0012 ST 1 Measured Dose Description +3008 0014 CS 1 Measured Dose Type +3008 0016 DS 1 Measured Dose Value +3008 0020 SQ 1 Treatment Session Beam Sequence +3008 0022 IS 1 Current Fraction Number +3008 0024 DA 1 Treatment Control Point Date +3008 0025 TM 1 Treatment Control Point Time +3008 002a CS 1 Treatment Termination Status +3008 002b SH 1 Treatment Termination Code +3008 002c CS 1 Treatment Verification Status +3008 0030 SQ 1 Referenced Treatment Record Sequence +3008 0032 DS 1 Specified Primary Meterset +3008 0033 DS 1 Specified Secondary Meterset +3008 0036 DS 1 Delivered Primary Meterset +3008 0037 DS 1 Delivered Secondary Meterset +3008 003a DS 1 Specified Treatment Time +3008 003b DS 1 Delivered Treatment Time +3008 0040 SQ 1 Control Point Delivery Sequence +3008 0042 DS 1 Specified Meterset +3008 0044 DS 1 Delivered Meterset +3008 0048 DS 1 Dose Rate Delivered +3008 0050 SQ 1 Treatment Summary Calculated Dose Reference Sequence +3008 0052 DS 1 Cumulative Dose to Dose Reference +3008 0054 DA 1 First Treatment Date +3008 0056 DA 1 Most Recent Treatment Date +3008 005a IS 1 Number of Fractions Delivered +3008 0060 SQ 1 Override Sequence +3008 0062 AT 1 Override Parameter Pointer +3008 0064 IS 1 Measured Dose Reference Number +3008 0066 ST 1 Override Reason +3008 0070 SQ 1 Calculated Dose Reference Sequence +3008 0072 IS 1 Calculated Dose Reference Number +3008 0074 ST 1 Calculated Dose Reference Description +3008 0076 DS 1 Calculated Dose Reference Dose Value +3008 0078 DS 1 Start Meterset +3008 007a DS 1 End Meterset +3008 0080 SQ 1 Referenced Measured Dose Reference Sequence +3008 0082 IS 1 Referenced Measured Dose Reference Number +3008 0090 SQ 1 Referenced Calculated Dose Reference Sequence +3008 0092 IS 1 Referenced Calculated Dose Reference Number +3008 00a0 SQ 1 Beam Limiting Device Leaf Pairs Sequence +3008 00b0 SQ 1 Recorded Wedge Sequence +3008 00c0 SQ 1 Recorded Compensator Sequence +3008 00d0 SQ 1 Recorded Block Sequence +3008 00e0 SQ 1 Treatment Summary Measured Dose Reference Sequence +3008 0100 SQ 1 Recorded Source Sequence +3008 0105 LO 1 Source Serial Number +3008 0110 SQ 1 Treatment Session Application Setup Sequence +3008 0116 CS 1 Application Setup Check +3008 0120 SQ 1 Recorded Brachy Accessory Device Sequence +3008 0122 IS 1 Referenced Brachy Accessory Device Number +3008 0130 SQ 1 Recorded Channel Sequence +3008 0132 DS 1 Specified Channel Total Time +3008 0134 DS 1 Delivered Channel Total Time +3008 0136 IS 1 Specified Number of Pulses +3008 0138 IS 1 Delivered Number of Pulses +3008 013a DS 1 Specified Pulse Repetition Interval +3008 013c DS 1 Delivered Pulse Repetition Interval +3008 0140 SQ 1 Recorded Source Applicator Sequence +3008 0142 IS 1 Referenced Source Applicator Number +3008 0150 SQ 1 Recorded Channel Shield Sequence +3008 0152 IS 1 Referenced Channel Shield Number +3008 0160 SQ 1 Brachy Control Point Delivered Sequence +3008 0162 DA 1 Safe Position Exit Date +3008 0164 TM 1 Safe Position Exit Time +3008 0166 DA 1 Safe Position Return Date +3008 0168 TM 1 Safe Position Return Time +3008 0200 CS 1 Current Treatment Status +3008 0202 ST 1 Treatment Status Comment +3008 0220 SQ 1 Fraction Group Summary Sequence +3008 0223 IS 1 Referenced Fraction Number +3008 0224 CS 1 Fraction Group Type +3008 0230 CS 1 Beam Stopper Position +3008 0240 SQ 1 Fraction Status Summary Sequence +3008 0250 DA 1 Treatment Date +3008 0251 TM 1 Treatment Time + +300a 0000 UL 1 Group Length +300a 0002 SH 1 RT Plan Label +300a 0003 LO 1 RT Plan Name +300a 0004 ST 1 RT Plan Description +300a 0006 DA 1 RT Plan Date +300a 0007 TM 1 RT Plan Time +300a 0009 LO 1-n Treatment Protocols +300a 000a CS 1 Treatment Intent +300a 000b LO 1-n Treatment Sites +300a 000c CS 1 RT Plan Geometry +300a 000e ST 1 Prescription Description +300a 0010 SQ 1 Dose Reference Sequence +300a 0012 IS 1 Dose Reference Number +300a 0013 UI 1 Dose Reference UID +300a 0014 CS 1 Dose Reference Structure Type +300a 0015 CS 1 Nominal Beam Energy Unit +300a 0016 LO 1 Dose Reference Description +300a 0018 DS 3 Dose Reference Point Coordinates +300a 001a DS 1 Nominal Prior Dose +300a 0020 CS 1 Dose Reference Type +300a 0021 DS 1 Constraint Weight +300a 0022 DS 1 Delivery Warning Dose +300a 0023 DS 1 Delivery Maximum Dose +300a 0025 DS 1 Target Minimum Dose +300a 0026 DS 1 Target Prescription Dose +300a 0027 DS 1 Target Maximum Dose +300a 0028 DS 1 Target Underdose Volume Fraction +300a 002a DS 1 Organ at Risk Full-volume Dose +300a 002b DS 1 Organ at Risk Limit Dose +300a 002c DS 1 Organ at Risk Maximum Dose +300a 002d DS 1 Organ at Risk Overdose Volume Fraction +300a 0040 SQ 1 Tolerance Table Sequence +300a 0042 IS 1 Tolerance Table Number +300a 0043 SH 1 Tolerance Table Label +300a 0044 DS 1 Gantry Angle Tolerance +300a 0046 DS 1 Beam Limiting Device Angle Tolerance +300a 0048 SQ 1 Beam Limiting Device Tolerance Sequence +300a 004a DS 1 Beam Limiting Device Position Tolerance +300a 004c DS 1 Patient Support Angle Tolerance +300a 004e DS 1 Table Top Eccentric Angle Tolerance +300a 0051 DS 1 Table Top Vertical Position Tolerance +300a 0052 DS 1 Table Top Longitudinal Position Tolerance +300a 0053 DS 1 Table Top Lateral Position Tolerance +300a 0055 CS 1 RT Plan Relationship +300a 0070 SQ 1 Fraction Group Sequence +300a 0071 IS 1 Fraction Group Number +300a 0072 LO 1 Fraction Group Description +300a 0078 IS 1 Number of Fractions Planned +300a 0079 IS 1 Number of Fraction Pattern Digits Per Day +300a 007a IS 1 Repeat Fraction Cycle Length +300a 007b LT 1 Fraction Pattern +300a 0080 IS 1 Number of Beams +300a 0082 DS 3 Beam Dose Specification Point +300a 0084 DS 1 Beam Dose +300a 0086 DS 1 Beam Meterset +300a 00a0 IS 1 Number of Brachy Application Setups +300a 00a2 DS 3 Brachy Application Setup Dose Specification Point +300a 00a4 DS 1 Brachy Application Setup Dose +300a 00b0 SQ 1 Beam Sequence +300a 00b2 SH 1 Treatment Machine Name +300a 00b3 CS 1 Primary Dosimeter Unit +300a 00b4 DS 1 Source-Axis Distance +300a 00b6 SQ 1 Beam Limiting Device Sequence +300a 00b8 CS 1 RT Beam Limiting Device Type +300a 00ba DS 1 Source to Beam Limiting Device Distance +300a 00bc IS 1 Number of Leaf/Jaw Pairs +300a 00be DS 3-n Leaf Position Boundaries +300a 00c0 IS 1 Beam Number +300a 00c2 LO 1 Beam Name +300a 00c3 ST 1 Beam Description +300a 00c4 CS 1 Beam Type +300a 00c6 CS 1 Radiation Type +300a 00c7 CS 1 High-Dose Technique Type +300a 00c8 IS 1 Reference Image Number +300a 00ca SQ 1 Planned Verification Image Sequence +300a 00cc LO 1-n Imaging Device-Specific Acquisition Parameters +300a 00ce CS 1 Treatment Delivery Type +300a 00d0 IS 1 Number of Wedges +300a 00d1 SQ 1 Wedge Sequence +300a 00d2 IS 1 Wedge Number +300a 00d3 CS 1 Wedge Type +300a 00d4 SH 1 Wedge ID +300a 00d5 IS 1 Wedge Angle +300a 00d6 DS 1 Wedge Factor +300a 00d8 DS 1 Wedge Orientation +300a 00da DS 1 Source to Wedge Tray Distance +300a 00e0 IS 1 Number of Compensators +300a 00e1 SH 1 Material ID +300a 00e2 DS 1 Total Compensator Tray Factor +300a 00e3 SQ 1 Compensator Sequence +300a 00e4 IS 1 Compensator Number +300a 00e5 SH 1 Compensator ID +300a 00e6 DS 1 Source to Compensator Tray Distance +300a 00e7 IS 1 Compensator Rows +300a 00e8 IS 1 Compensator Columns +300a 00e9 DS 2 Compensator Pixel Spacing +300a 00ea DS 2 Compensator Position +300a 00eb DS 1-n Compensator Transmission Data +300a 00ec DS 1-n Compensator Thickness Data +300a 00ed IS 1 Number of Boli +300a 00ee CS 1 Compensator Type +300a 00f0 IS 1 Number of Blocks +300a 00f2 DS 1 Total Block Tray Factor +300a 00f4 SQ 1 Block Sequence +300a 00f5 SH 1 Block Tray ID +300a 00f6 DS 1 Source to Block Tray Distance +300a 00f8 CS 1 Block Type +300a 00f9 LO 1 Accessory Code +300a 00fa CS 1 Block Divergence +300a 00fb CS 1 Block Mounting Position +300a 00fc IS 1 Block Number +300a 00fe LO 1 Block Name +300a 0100 DS 1 Block Thickness +300a 0102 DS 1 Block Transmission +300a 0104 IS 1 Block Number of Points +300a 0106 DS 2-2n Block Data +300a 0107 SQ 1 Applicator Sequence +300a 0108 SH 1 Applicator ID +300a 0109 CS 1 Applicator Type +300a 010a LO 1 Applicator Description +300a 010c DS 1 Cumulative Dose Reference Coefficient +300a 010e DS 1 Final Cumulative Meterset Weight +300a 0110 IS 1 Number of Control Points +300a 0111 SQ 1 Control Point Sequence +300a 0112 IS 1 Control Point Index +300a 0114 DS 1 Nominal Beam Energy +300a 0115 DS 1 Dose Rate Set +300a 0116 SQ 1 Wedge Position Sequence +300a 0118 CS 1 Wedge Position +300a 011a SQ 1 Beam Limiting Device Position Sequence +300a 011c DS 2-2n Leaf/Jaw Positions +300a 011e DS 1 Gantry Angle +300a 011f CS 1 Gantry Rotation Direction +300a 0120 DS 1 Beam Limiting Device Angle +300a 0121 CS 1 Beam Limiting Device Rotation Direction +300a 0122 DS 1 Patient Support Angle +300a 0123 CS 1 Patient Support Rotation Direction +300a 0124 DS 1 Table Top Eccentric Axis Distance +300a 0125 DS 1 Table Top Eccentric Angle +300a 0126 CS 1 Table Top Eccentric Rotation Direction +300a 0128 DS 1 Table Top Vertical Position +300a 0129 DS 1 Table Top Longitudinal Position +300a 012a DS 1 Table Top Lateral Position +300a 012c DS 3 Isocenter Position +300a 012e DS 3 Surface Entry Point +300a 0130 DS 1 Source to Surface Distance +300a 0134 DS 1 Cumulative Meterset Weight +300a 0180 SQ 1 Patient Setup Sequence +300a 0182 IS 1 Patient Setup Number +300a 0184 LO 1 Patient Additional Position +300a 0190 SQ 1 Fixation Device Sequence +300a 0192 CS 1 Fixation Device Type +300a 0194 SH 1 Fixation Device Label +300a 0196 ST 1 Fixation Device Description +300a 0198 SH 1 Fixation Device Position +300a 01a0 SQ 1 Shielding Device Sequence +300a 01a2 CS 1 Shielding Device Type +300a 01a4 SH 1 Shielding Device Label +300a 01a6 ST 1 Shielding Device Description +300a 01a8 SH 1 Shielding Device Position +300a 01b0 CS 1 Setup Technique +300a 01b2 ST 1 Setup Technique Description +300a 01b4 SQ 1 Setup Device Sequence +300a 01b6 CS 1 Setup Device Type +300a 01b8 SH 1 Setup Device Label +300a 01ba ST 1 Setup Device Description +300a 01bc DS 1 Setup Device Parameter +300a 01d0 ST 1 Setup Reference Description +300a 01d2 DS 1 Table Top Vertical Setup Displacement +300a 01d4 DS 1 Table Top Longitudinal Setup Displacement +300a 01d6 DS 1 Table Top Lateral Setup Displacement +300a 0200 CS 1 Brachy Treatment Technique +300a 0202 CS 1 Brachy Treatment Type +300a 0206 SQ 1 Treatment Machine Sequence +300a 0210 SQ 1 Source Sequence +300a 0212 IS 1 Source Number +300a 0214 CS 1 Source Type +300a 0216 LO 1 Source Manufacturer +300a 0218 DS 1 Active Source Diameter +300a 021a DS 1 Active Source Length +300a 0222 DS 1 Source Encapsulation Nominal Thickness +300a 0224 DS 1 Source Encapsulation Nominal Transmission +300a 0226 LO 1 Source Isotope Name +300a 0228 DS 1 Source Isotope Half Life +300a 022a DS 1 Reference Air Kerma Rate +300a 022c DA 1 Air Kerma Rate Reference Date +300a 022e TM 1 Air Kerma Rate Reference Time +300a 0230 SQ 1 Application Setup Sequence +300a 0232 CS 1 Application Setup Type +300a 0234 IS 1 Application Setup Number +300a 0236 LO 1 Application Setup Name +300a 0238 LO 1 Application Setup Manufacturer +300a 0240 IS 1 Template Number +300a 0242 SH 1 Template Type +300a 0244 LO 1 Template Name +300a 0250 DS 1 Total Reference Air Kerma +300a 0260 SQ 1 Brachy Accessory Device Sequence +300a 0262 IS 1 Brachy Accessory Device Number +300a 0263 SH 1 Brachy Accessory Device ID +300a 0264 CS 1 Brachy Accessory Device Type +300a 0266 LO 1 Brachy Accessory Device Name +300a 026a DS 1 Brachy Accessory Device Nominal Thickness +300a 026c DS 1 Brachy Accessory Device Nominal Transmission +300a 0280 SQ 1 Channel Sequence +300a 0282 IS 1 Channel Number +300a 0284 DS 1 Channel Length +300a 0286 DS 1 Channel Total Time +300a 0288 CS 1 Source Movement Type +300a 028a IS 1 Number of Pulses +300a 028c DS 1 Pulse Repetition Interval +300a 0290 IS 1 Source Applicator Number +300a 0291 SH 1 Source Applicator ID +300a 0292 CS 1 Source Applicator Type +300a 0294 LO 1 Source Applicator Name +300a 0296 DS 1 Source Applicator Length +300a 0298 LO 1 Source Applicator Manufacturer +300a 029c DS 1 Source Applicator Wall Nominal Thickness +300a 029e DS 1 Source Applicator Wall Nominal Transmission +300a 02a0 DS 1 Source Applicator Step Size +300a 02a2 IS 1 Transfer Tube Number +300a 02a4 DS 1 Transfer Tube Length +300a 02b0 SQ 1 Channel Shield Sequence +300a 02b2 IS 1 Channel Shield Number +300a 02b3 SH 1 Channel Shield ID +300a 02b4 LO 1 Channel Shield Name +300a 02b8 DS 1 Channel Shield Nominal Thickness +300a 02ba DS 1 Channel Shield Nominal Transmission +300a 02c8 DS 1 Final Cumulative Time Weight +300a 02d0 SQ 1 Brachy Control Point Sequence +300a 02d2 DS 1 Control Point Relative Position +300a 02d4 DS 3 Control Point 3D Position +300a 02d6 DS 1 Cumulative Time Weight +300a 02e0 CS 1 Compensator Divergence +300a 02e1 CS 1 Compensator Mounting Position +300a 02e2 DS 1-n Source to Compensator Distance + +300c 0000 UL 1 Group Length +300c 0002 SQ 1 Referenced RT Plan Sequence +300c 0004 SQ 1 Referenced Beam Sequence +300c 0006 IS 1 Referenced Beam Number +300c 0007 IS 1 Referenced Reference Image Number +300c 0008 DS 1 Start Cumulative Meterset Weight +300c 0009 DS 1 End Cumulative Meterset Weight +300c 000a SQ 1 Referenced Brachy Application Setup Sequence +300c 000c IS 1 Referenced Brachy Application Setup Number +300c 000e IS 1 Referenced Source Number +300c 0020 SQ 1 Referenced Fraction Group Sequence +300c 0022 IS 1 Referenced Fraction Group Number +300c 0040 SQ 1 Referenced Verification Image Sequence +300c 0042 SQ 1 Referenced Reference Image Sequence +300c 0050 SQ 1 Referenced Dose Reference Sequence +300c 0051 IS 1 Referenced Dose Reference Number +300c 0055 SQ 1 Brachy Referenced Dose Reference Sequence +300c 0060 SQ 1 Referenced Structure Set Sequence +300c 006a IS 1 Referenced Patient Setup Number +300c 0080 SQ 1 Referenced Dose Sequence +300c 00a0 IS 1 Referenced Tolerance Table Number +300c 00b0 SQ 1 Referenced Bolus Sequence +300c 00c0 IS 1 Referenced Wedge Number +300c 00d0 IS 1 Referenced Compensator Number +300c 00e0 IS 1 Referenced Block Number +300c 00f0 IS 1 Referenced Control Point Index + +300e 0000 UL 1 Group Length +300e 0002 CS 1 Approval Status +300e 0004 DA 1 Review Date +300e 0005 TM 1 Review Time +300e 0008 PN 1 Reviewer Name + +4000 0000 UL 1 Text Group Length +4000 0010 LT 1-n Text Arbitrary (RET) +4000 4000 LT 1-n Text Comments (RET) + +4008 0000 UL 1 Group Length +4008 0040 SH 1 Results ID +4008 0042 LO 1 Results ID Issuer +4008 0050 SQ 1 Referenced Interpretation Sequence +4008 0100 DA 1 Interpretation Recorded Date +4008 0101 TM 1 Interpretation Recorded Time +4008 0102 PN 1 Interpretation Recorder +4008 0103 LO 1 Reference to Recorded Sound +4008 0108 DA 1 Interpretation Transcription Date +4008 0109 TM 1 Interpretation Transcription Time +4008 010a PN 1 Interpretation Transcriber +4008 010b ST 1 Interpretation Text +4008 010c PN 1 Interpretation Author +4008 0111 SQ 1 Interpretation Approver Sequence +4008 0112 DA 1 Interpretation Approval Date +4008 0113 TM 1 Interpretation Approval Time +4008 0114 PN 1 Physician Approving Interpretation +4008 0115 LT 1 Interpretation Diagnosis Description +4008 0117 SQ 1 Interpretation Diagnosis Code Sequence +4008 0118 SQ 1 Results Distribution List Sequence +4008 0119 PN 1 Distribution Name +4008 011a LO 1 Distribution Address +4008 0200 SH 1 Interpretation ID +4008 0202 LO 1 Interpretation ID Issuer +4008 0210 CS 1 Interpretation Type ID +4008 0212 CS 1 Interpretation Status ID +4008 0300 ST 1 Impressions +4008 4000 ST 1 Results Comments + +4ffe 0000 UL 1 Group Length +4ffe 0001 SQ 1 MAC Parameters Sequence + +5000 0000 UL 1 Group Length +5000 0005 US 1 Curve Dimensions +5000 0010 US 1 Number of Points +5000 0020 CS 1 Type of Data +5000 0022 LO 1 Curve Description +5000 0030 SH 1-n Axis Units +5000 0040 SH 1-n Axis Labels +5000 0103 US 1 Data Value Representation +5000 0104 US 1-n Minimum Coordinate Value +5000 0105 US 1-n Maximum Coordinate Value +5000 0106 SH 1-n Curve Range +5000 0110 US 1-n Curve Data Descriptor +5000 0112 US 1-n Coordinate Start Value +5000 0114 US 1-n Coordinate Step Value +5000 1001 CS 1 Curve Activation Layer +5000 2000 US 1 Audio Type +5000 2002 US 1 Audio Sample Format +5000 2004 US 1 Number of Channels +5000 2006 UL 1 Number of Samples +5000 2008 UL 1 Sample Rate +5000 200a UL 1 Total Time +5000 200c OW 1 Audio Sample Data +5000 200e LT 1 Audio Comments +5000 2500 LO 1 Curve Label +5000 2600 SQ 1 Referenced Overlay Sequence +5000 2610 US 1 Referenced Overlay Group +5000 3000 OW 1 Curve Data + +5002 0000 UL 1 Group Length +5002 0005 US 1 Curve Dimensions +5002 0010 US 1 Number of Points +5002 0020 CS 1 Type of Data +5002 0022 LO 1 Curve Description +5002 0030 SH 1-n Axis Units +5002 0040 SH 1-n Axis Labels +5002 0103 US 1 Data Value Representation +5002 0104 US 1-n Minimum Coordinate Value +5002 0105 US 1-n Maximum Coordinate Value +5002 0106 SH 1-n Curve Range +5002 0110 US 1-n Curve Data Descriptor +5002 0112 US 1-n Coordinate Start Value +5002 0114 US 1-n Coordinate Step Value +5002 2000 US 1 Audio Type +5002 2002 US 1 Audio Sample Format +5002 2004 US 1 Number of Channels +5002 2006 UL 1 Number of Samples +5002 2008 UL 1 Sample Rate +5002 200a UL 1 Total Time +5002 200c OW 1 Audio Sample Data +5002 200e LT 1 Audio Comments +5002 2500 LO 1 Curve Label +5002 2600 SQ 1 Referenced Overlay Sequence +5002 2610 US 1 Referenced Overlay Group +5002 3000 OW 1 Curve Data + +5004 0000 UL 1 Group Length +5004 0005 US 1 Curve Dimensions +5004 0010 US 1 Number of Points +5004 0020 CS 1 Type of Data +5004 0022 LO 1 Curve Description +5004 0030 SH 1-n Axis Units +5004 0040 SH 1-n Axis Labels +5004 0103 US 1 Data Value Representation +5004 0104 US 1-n Minimum Coordinate Value +5004 0105 US 1-n Maximum Coordinate Value +5004 0106 SH 1-n Curve Range +5004 0110 US 1-n Curve Data Descriptor +5004 0112 US 1-n Coordinate Start Value +5004 0114 US 1-n Coordinate Step Value +5004 2000 US 1 Audio Type +5004 2002 US 1 Audio Sample Format +5004 2004 US 1 Number of Channels +5004 2006 UL 1 Number of Samples +5004 2008 UL 1 Sample Rate +5004 200a UL 1 Total Time +5004 200c OW 1 Audio Sample Data +5004 200e LT 1 Audio Comments +5004 2500 LO 1 Curve Label +5004 2600 SQ 1 Referenced Overlay Sequence +5004 2610 US 1 Referenced Overlay Group +5004 3000 OW 1 Curve Data + +5006 0000 UL 1 Group Length +5006 0005 US 1 Curve Dimensions +5006 0010 US 1 Number of Points +5006 0020 CS 1 Type of Data +5006 0022 LO 1 Curve Description +5006 0030 SH 1-n Axis Units +5006 0040 SH 1-n Axis Labels +5006 0103 US 1 Data Value Representation +5006 0104 US 1-n Minimum Coordinate Value +5006 0105 US 1-n Maximum Coordinate Value +5006 0106 SH 1-n Curve Range +5006 0110 US 1-n Curve Data Descriptor +5006 0112 US 1-n Coordinate Start Value +5006 0114 US 1-n Coordinate Step Value +5006 2000 US 1 Audio Type +5006 2002 US 1 Audio Sample Format +5006 2004 US 1 Number of Channels +5006 2006 UL 1 Number of Samples +5006 2008 UL 1 Sample Rate +5006 200a UL 1 Total Time +5006 200c OW 1 Audio Sample Data +5006 200e LT 1 Audio Comments +5006 2500 LO 1 Curve Label +5006 2600 SQ 1 Referenced Overlay Sequence +5006 2610 US 1 Referenced Overlay Group +5006 3000 OW 1 Curve Data + +5008 0000 UL 1 Group Length +5008 0005 US 1 Curve Dimensions +5008 0010 US 1 Number of Points +5008 0020 CS 1 Type of Data +5008 0022 LO 1 Curve Description +5008 0030 SH 1-n Axis Units +5008 0040 SH 1-n Axis Labels +5008 0103 US 1 Data Value Representation +5008 0104 US 1-n Minimum Coordinate Value +5008 0105 US 1-n Maximum Coordinate Value +5008 0106 SH 1-n Curve Range +5008 0110 US 1-n Curve Data Descriptor +5008 0112 US 1-n Coordinate Start Value +5008 0114 US 1-n Coordinate Step Value +5008 2000 US 1 Audio Type +5008 2002 US 1 Audio Sample Format +5008 2004 US 1 Number of Channels +5008 2006 UL 1 Number of Samples +5008 2008 UL 1 Sample Rate +5008 200a UL 1 Total Time +5008 200c OW 1 Audio Sample Data +5008 200e LT 1 Audio Comments +5008 2500 LO 1 Curve Label +5008 2600 SQ 1 Referenced Overlay Sequence +5008 2610 US 1 Referenced Overlay Group +5008 3000 OW 1 Curve Data + +500a 0000 UL 1 Group Length +500a 0005 US 1 Curve Dimensions +500a 0010 US 1 Number of Points +500a 0020 CS 1 Type of Data +500a 0022 LO 1 Curve Description +500a 0030 SH 1-n Axis Units +500a 0040 SH 1-n Axis Labels +500a 0103 US 1 Data Value Representation +500a 0104 US 1-n Minimum Coordinate Value +500a 0105 US 1-n Maximum Coordinate Value +500a 0106 SH 1-n Curve Range +500a 0110 US 1-n Curve Data Descriptor +500a 0112 US 1-n Coordinate Start Value +500a 0114 US 1-n Coordinate Step Value +500a 2000 US 1 Audio Type +500a 2002 US 1 Audio Sample Format +500a 2004 US 1 Number of Channels +500a 2006 UL 1 Number of Samples +500a 2008 UL 1 Sample Rate +500a 200a UL 1 Total Time +500a 200c OW 1 Audio Sample Data +500a 200e LT 1 Audio Comments +500a 2500 LO 1 Curve Label +500a 2600 SQ 1 Referenced Overlay Sequence +500a 2610 US 1 Referenced Overlay Group +500a 3000 OW 1 Curve Data + +500c 0000 UL 1 Group Length +500c 0005 US 1 Curve Dimensions +500c 0010 US 1 Number of Points +500c 0020 CS 1 Type of Data +500c 0022 LO 1 Curve Description +500c 0030 SH 1-n Axis Units +500c 0040 SH 1-n Axis Labels +500c 0103 US 1 Data Value Representation +500c 0104 US 1-n Minimum Coordinate Value +500c 0105 US 1-n Maximum Coordinate Value +500c 0106 SH 1-n Curve Range +500c 0110 US 1-n Curve Data Descriptor +500c 0112 US 1-n Coordinate Start Value +500c 0114 US 1-n Coordinate Step Value +500c 2000 US 1 Audio Type +500c 2002 US 1 Audio Sample Format +500c 2004 US 1 Number of Channels +500c 2006 UL 1 Number of Samples +500c 2008 UL 1 Sample Rate +500c 200a UL 1 Total Time +500c 200c OW 1 Audio Sample Data +500c 200e LT 1 Audio Comments +500c 2500 LO 1 Curve Label +500c 2600 SQ 1 Referenced Overlay Sequence +500c 2610 US 1 Referenced Overlay Group +500c 3000 OW 1 Curve Data + +500e 0000 UL 1 Group Length +500e 0005 US 1 Curve Dimensions +500e 0010 US 1 Number of Points +500e 0020 CS 1 Type of Data +500e 0022 LO 1 Curve Description +500e 0030 SH 1-n Axis Units +500e 0040 SH 1-n Axis Labels +500e 0103 US 1 Data Value Representation +500e 0104 US 1-n Minimum Coordinate Value +500e 0105 US 1-n Maximum Coordinate Value +500e 0106 SH 1-n Curve Range +500e 0110 US 1-n Curve Data Descriptor +500e 0112 US 1-n Coordinate Start Value +500e 0114 US 1-n Coordinate Step Value +500e 2000 US 1 Audio Type +500e 2002 US 1 Audio Sample Format +500e 2004 US 1 Number of Channels +500e 2006 UL 1 Number of Samples +500e 2008 UL 1 Sample Rate +500e 200a UL 1 Total Time +500e 200c OW 1 Audio Sample Data +500e 200e LT 1 Audio Comments +500e 2500 LO 1 Curve Label +500e 2600 SQ 1 Referenced Overlay Sequence +500e 2610 US 1 Referenced Overlay Group +500e 3000 OW 1 Curve Data + +5200 0000 UL 1 Group Length +5200 9229 SQ 1 Shared Functional Groups Sequence +5200 9230 SQ 1 Per-frame Functional Groups Sequence + +5400 0000 UL 1 Group Length +5400 0100 SQ 1 Waveform Sequence +5400 0110 OB 1 Channel Minimum Value +5400 0112 OB 1 Channel Maximum Value +5400 1004 US 1 Waveform Bits Allocated +5400 1006 CS 1 Waveform Sample Interpretation +5400 100a OB 1 Waveform Padding Value +5400 1010 OB 1 Waveform Data + +5600 0000 UL 1 Group Length +5600 0010 OF 1 First Order Phase Correction Angle +5600 0020 OF 1 Spectroscopy Data + +6000 0000 UL 1 Group Length +6000 0010 US 1 Overlay Rows +6000 0011 US 1 Overlay Columns +6000 0012 US 1 Overlay Planes +6000 0015 IS 1 Number of Frames in Overlay +6000 0022 LO 1 Overlay Description +6000 0040 CS 1 Overlay Type +6000 0045 LO 1 Overlay Subtype +6000 0050 SS 2 Overlay Origin +6000 0051 US 1 Image Frame Origin +6000 0052 US 1 Overlay Plane Origin +6000 0060 LT 1 Overlay Compression Code (RET) +6000 0100 US 1 Overlay Bits Allocated +6000 0102 US 1 Overlay Bit Position +6000 0110 LT 1 Overlay Format (RET) +6000 0200 US 1 Overlay Location (RET) +6000 1001 CS 1 Overlay Activation Layer +6000 1100 US 1 Overlay Descriptor - Gray (RET) +6000 1101 US 1 Overlay Descriptor - Red (RET) +6000 1102 US 1 Overlay Descriptor - Green (RET) +6000 1103 US 1 Overlay Descriptor - Blue (RET) +6000 1200 US 1-n Overlays - Gray (RET) +6000 1201 US 1-n Overlays - Red (RET) +6000 1202 US 1-n Overlays - Green (RET) +6000 1203 US 1-n Overlays - Blue (RET) +6000 1301 IS 1 ROI Area +6000 1302 DS 1 ROI Mean +6000 1303 DS 1 ROI Standard Deviation +6000 1500 LO 1 Overlay Label +6000 3000 OW 1 Overlay Data +6000 4000 LT 1-n Overlay Comments (RET) + +6002 0000 UL 1 Group Length +6002 0010 US 1 Rows +6002 0011 US 1 Columns +6002 0012 US 1 Planes +6002 0015 IS 1 Number of Frames in Overlay +6002 0022 LO 1 Overlay Description +6002 0040 CS 1 Overlay Type +6002 0045 LO 1 Overlay Subtype +6002 0050 SS 2 Overlay Origin +6002 0051 US 1 Image Frame Origin +6002 0052 US 1 Overlay Plane Origin +6002 0060 LT 1 Overlay Compression Code (RET) +6002 0100 US 1 Overlay Bits Allocated +6002 0102 US 1 Overlay Bit Position +6002 0110 LT 1 Overlay Format (RET) +6002 0200 US 1 Overlay Location (RET) +6002 1001 US 1 Overlay Activation Layer +6002 1100 US 1 Overlay Descriptor - Gray (RET) +6002 1101 US 1 Overlay Descriptor - Red (RET) +6002 1102 US 1 Overlay Descriptor - Green (RET) +6002 1103 US 1 Overlay Descriptor - Blue (RET) +6002 1200 US 1-n Overlays - Gray +6002 1201 US 1-n Overlays - Red +6002 1202 US 1-n Overlays - Green +6002 1203 US 1-n Overlays - Blue +6002 1301 IS 1 ROI Area +6002 1302 DS 1 ROI Mean +6002 1303 DS 1 ROI Standard Deviation +6002 1500 LO 1 Overlay Label +6002 3000 OW 1 Overlay Data +6002 4000 LT 1-n Overlay Comments (RET) + +6004 0000 UL 1 Group Length +6004 0010 US 1 Rows +6004 0011 US 1 Columns +6004 0012 US 1 Planes +6004 0015 IS 1 Number of Frames in Overlay +6004 0022 LO 1 Overlay Description +6004 0040 CS 1 Overlay Type +6004 0045 LO 1 Overlay Subtype +6004 0050 SS 2 Overlay Origin +6004 0051 US 1 Image Frame Origin +6004 0052 US 1 Overlay Plane Origin +6004 0060 LT 1 Overlay Compression Code (RET) +6004 0100 US 1 Overlay Bits Allocated +6004 0102 US 1 Overlay Bit Position +6004 0110 LT 1 Overlay Format (RET) +6004 0200 US 1 Overlay Location (RET) +6004 1001 US 1 Overlay Activation Layer +6004 1100 US 1 Overlay Descriptor - Gray (RET) +6004 1101 US 1 Overlay Descriptor - Red (RET) +6004 1102 US 1 Overlay Descriptor - Green (RET) +6004 1103 US 1 Overlay Descriptor - Blue (RET) +6004 1200 US 1-n Overlays - Gray +6004 1201 US 1-n Overlays - Red +6004 1202 US 1-n Overlays - Green +6004 1203 US 1-n Overlays - Blue +6004 1301 IS 1 ROI Area +6004 1302 DS 1 ROI Mean +6004 1303 DS 1 ROI Standard Deviation +6004 1500 LO 1 Overlay Label +6004 3000 OW 1 Overlay Data +6004 4000 LT 1-n Overlay Comments (RET) + +6006 0000 UL 1 Group Length +6006 0010 US 1 Rows +6006 0011 US 1 Columns +6006 0012 US 1 Planes +6006 0015 IS 1 Number of Frames in Overlay +6006 0022 LO 1 Overlay Description +6006 0040 CS 1 Overlay Type +6006 0045 LO 1 Overlay Subtype +6006 0050 SS 2 Overlay Origin +6006 0051 US 1 Image Frame Origin +6006 0052 US 1 Overlay Plane Origin +6006 0060 LT 1 Overlay Compression Code (RET) +6006 0100 US 1 Overlay Bits Allocated +6006 0102 US 1 Overlay Bit Position +6006 0110 LT 1 Overlay Format (RET) +6006 0200 US 1 Overlay Location (RET) +6006 1001 US 1 Overlay Activation Layer +6006 1100 US 1 Overlay Descriptor - Gray (RET) +6006 1101 US 1 Overlay Descriptor - Red (RET) +6006 1102 US 1 Overlay Descriptor - Green (RET) +6006 1103 US 1 Overlay Descriptor - Blue (RET) +6006 1200 US 1-n Overlays - Gray +6006 1201 US 1-n Overlays - Red +6006 1202 US 1-n Overlays - Green +6006 1203 US 1-n Overlays - Blue +6006 1301 IS 1 ROI Area +6006 1302 DS 1 ROI Mean +6006 1303 DS 1 ROI Standard Deviation +6006 1500 LO 1 Overlay Label +6006 3000 OW 1 Overlay Data +6006 4000 LT 1-n Overlay Comments (RET) + +6008 0000 UL 1 Group Length +6008 0010 US 1 Rows +6008 0011 US 1 Columns +6008 0012 US 1 Planes +6008 0015 IS 1 Number of Frames in Overlay +6008 0022 LO 1 Overlay Description +6008 0040 CS 1 Overlay Type +6008 0045 LO 1 Overlay Subtype +6008 0050 SS 2 Overlay Origin +6008 0051 US 1 Image Frame Origin +6008 0052 US 1 Overlay Plane Origin +6008 0060 LT 1 Overlay Compression Code (RET) +6008 0100 US 1 Overlay Bits Allocated +6008 0102 US 1 Overlay Bit Position +6008 0110 LT 1 Overlay Format (RET) +6008 0200 US 1 Overlay Location (RET) +6008 1001 US 1 Overlay Activation Layer +6008 1100 US 1 Overlay Descriptor - Gray (RET) +6008 1101 US 1 Overlay Descriptor - Red (RET) +6008 1102 US 1 Overlay Descriptor - Green (RET) +6008 1103 US 1 Overlay Descriptor - Blue (RET) +6008 1200 US 1-n Overlays - Gray +6008 1201 US 1-n Overlays - Red +6008 1202 US 1-n Overlays - Green +6008 1203 US 1-n Overlays - Blue +6008 1301 IS 1 ROI Area +6008 1302 DS 1 ROI Mean +6008 1303 DS 1 ROI Standard Deviation +6008 1500 LO 1 Overlay Label +6008 3000 OW 1 Overlay Data +6008 4000 LT 1-n Overlay Comments (RET) + +600a 0000 UL 1 Group Length +600a 0010 US 1 Rows +600a 0011 US 1 Columns +600a 0012 US 1 Planes +600a 0015 IS 1 Number of Frames in Overlay +600a 0022 LO 1 Overlay Description +600a 0040 CS 1 Overlay Type +600a 0045 LO 1 Overlay Subtype +600a 0050 SS 2 Overlay Origin +600a 0051 US 1 Image Frame Origin +600a 0052 US 1 Overlay Plane Origin +600a 0060 LT 1 Overlay Compression Code (RET) +600a 0100 US 1 Overlay Bits Allocated +600a 0102 US 1 Overlay Bit Position +600a 0110 LT 1 Overlay Format (RET) +600a 0200 US 1 Overlay Location (RET) +600a 1001 US 1 Overlay Activation Layer +600a 1100 US 1 Overlay Descriptor - Gray (RET) +600a 1101 US 1 Overlay Descriptor - Red (RET) +600a 1102 US 1 Overlay Descriptor - Green (RET) +600a 1103 US 1 Overlay Descriptor - Blue (RET) +600a 1200 US 1-n Overlays - Gray +600a 1201 US 1-n Overlays - Red +600a 1202 US 1-n Overlays - Green +600a 1203 US 1-n Overlays - Blue +600a 1301 IS 1 ROI Area +600a 1302 DS 1 ROI Mean +600a 1303 DS 1 ROI Standard Deviation +600a 1500 LO 1 Overlay Label +600a 3000 OW 1 Overlay Data +600a 4000 LT 1-n Overlay Comments (RET) + +600c 0000 UL 1 Group Length +600c 0010 US 1 Rows +600c 0011 US 1 Columns +600c 0012 US 1 Planes +600c 0015 IS 1 Number of Frames in Overlay +600c 0022 LO 1 Overlay Description +600c 0040 CS 1 Overlay Type +600c 0045 LO 1 Overlay Subtype +600c 0050 SS 2 Overlay Origin +600c 0051 US 1 Image Frame Origin +600c 0052 US 1 Overlay Plane Origin +600c 0060 LT 1 Overlay Compression Code (RET) +600c 0100 US 1 Overlay Bits Allocated +600c 0102 US 1 Overlay Bit Position +600c 0110 LT 1 Overlay Format (RET) +600c 0200 US 1 Overlay Location (RET) +600c 1001 US 1 Overlay Activation Layer +600c 1100 US 1 Overlay Descriptor - Gray (RET) +600c 1101 US 1 Overlay Descriptor - Red (RET) +600c 1102 US 1 Overlay Descriptor - Green (RET) +600c 1103 US 1 Overlay Descriptor - Blue (RET) +600c 1200 US 1-n Overlays - Gray +600c 1201 US 1-n Overlays - Red +600c 1202 US 1-n Overlays - Green +600c 1203 US 1-n Overlays - Blue +600c 1301 IS 1 ROI Area +600c 1302 DS 1 ROI Mean +600c 1303 DS 1 ROI Standard Deviation +600c 1500 LO 1 Overlay Label +600c 3000 OW 1 Overlay Data +600c 4000 LT 1-n Overlay Comments (RET) + +600e 0000 UL 1 Group Length +600e 0010 US 1 Rows +600e 0011 US 1 Columns +600e 0012 US 1 Planes +600e 0015 IS 1 Number of Frames in Overlay +600e 0022 LO 1 Overlay Description +600e 0040 CS 1 Overlay Type +600e 0045 LO 1 Overlay Subtype +600e 0050 SS 2 Overlay Origin +600e 0051 US 1 Image Frame Origin +600e 0052 US 1 Overlay Plane Origin +600e 0060 LT 1 Overlay Compression Code (RET) +600e 0100 US 1 Overlay Bits Allocated +600e 0102 US 1 Overlay Bit Position +600e 0110 LT 1 Overlay Format (RET) +600e 0200 US 1 Overlay Location (RET) +600e 1001 US 1 Overlay Activation Layer +600e 1100 US 1 Overlay Descriptor - Gray (RET) +600e 1101 US 1 Overlay Descriptor - Red (RET) +600e 1102 US 1 Overlay Descriptor - Green (RET) +600e 1103 US 1 Overlay Descriptor - Blue (RET) +600e 1200 US 1-n Overlays - Gray +600e 1201 US 1-n Overlays - Red +600e 1202 US 1-n Overlays - Green +600e 1203 US 1-n Overlays - Blue +600e 1301 IS 1 ROI Area +600e 1302 DS 1 ROI Mean +600e 1303 DS 1 ROI Standard Deviation +600e 1500 LO 1 Overlay Label +600e 3000 OW 1 Overlay Data +600e 4000 LT 1-n Overlay Comments (RET) + +7fe0 0000 UL 1 Group Length +7fe0 0010 OB 1 Pixel Data + +fffa fffa SQ 1 Digital Signatures Sequence +fffc fffc OB 1 Data Set Trailing Padding +fffe e000 UL 1 Item +fffe e00d UL 1 Item Delimitation Item +fffe e0dd UL 1 Sequence Delimitation Item diff --git a/Utilities/ITK/Utilities/gdcm/Dicts/dicomV3PhilipsIntera.dic b/Utilities/ITK/Utilities/gdcm/Dicts/dicomV3PhilipsIntera.dic new file mode 100644 index 0000000000000000000000000000000000000000..0619d24b5eb4df2f80dec943812a4428b82da5ab --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/Dicts/dicomV3PhilipsIntera.dic @@ -0,0 +1,37 @@ + +2001 0010 LO 1 Private Creator Group 2001 +2001 1001 FL 1 Chemical Shift +2001 1002 IS 1 Chemical Shift Number MR +2001 1003 FL 1 Diffusion B-Factor +2001 1004 CS 1 Diffusion Direction +2001 1006 CS 1 Image Enhanced +2001 1007 CS 1 Image Type ED ES +2001 1008 IS 1 Phase Number +2001 100a IS 1 Slice Number MR +2001 100b CS 1 Slice Orientation +2001 1011 FL 1 Diffusion Echo Time +2001 1012 CS 1 Dynamic Series +2001 1013 SL 1 EPI Factor +2001 1014 SL 1 Number of Echoes +2001 1015 SS 1 Number of Locations +2001 1016 SS 1 Number of PC Directions +2001 1017 SL 1 Number of Phases MR +2001 1018 SL 1 Number of Slices MR +2001 1019 CS 1 Partial Matrix Scanned +2001 101a FL 1-n PC Velocity +2001 101b FL 1 Prepulse Delay +2001 101c CS 1 Prepulse Type +2001 101d IS 1 Reconstruction Number MR +2001 101f CS 1 Respiration Sync +2001 1021 CS 1 SPIR +2001 1022 FL 1 Water Fat Shift +2001 105f SQ 1 Stack Sequence +2001 102d SS 1 Number of Stack Slices +2001 1032 FL 1-n Stack Radial Angle +2001 1035 SS 1-n Stack Slice Number +2001 1036 CS 1-n Stack Type +2001 1060 SL 1 Number of Stacks +2001 1081 IS 1 Number of Dynamic Scans +2005 0010 LO 1 Private Creator Group 2005 +2005 1020 SL 1 Number of Chemical Shifts +2005 10a1 CS 1 Syncra Scan Type diff --git a/Utilities/ITK/Utilities/gdcm/Dicts/dicomVR.dic b/Utilities/ITK/Utilities/gdcm/Dicts/dicomVR.dic new file mode 100644 index 0000000000000000000000000000000000000000..6a1f2277aa2ddd2f4a3fd0afd7552dcb812a044e --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/Dicts/dicomVR.dic @@ -0,0 +1,27 @@ +AE Application Entity; // At most 16 bytes +AS Age String; // Exactly 4 bytes +AT Attribute Tag; // 2 16-bit unsigned short integers +CS Code String; // At most 16 bytes +DA Date; // Exactly 8 bytes +DS Decimal String; // At most 16 bytes +DT Date Time; // At most 26 bytes +FL Floating Point Single; // 32-bit IEEE 754:1985 float +FD Floating Point Double; // 64-bit IEEE 754:1985 double +IS Integer String; // At most 12 bytes +LO Long String; // At most 64 chars +LT Long Text; // At most 10240 chars +OB Other Byte String; // String of bytes (VR independant) +OW Other Word String; // String of 16-bit words (VR dependant) +PN Person Name; // At most 64 chars +SH Short String; // At most 16 chars +SL Signed Long; // Exactly 4 bytes +SQ Sequence of Items; // Not Applicable +SS Signed Short; // Exactly 2 bytes +ST Short Text; // At most 1024 chars +TM Time; // At most 16 bytes +UI Unique Identifier; // At most 64 bytes +UL Unsigned Long; // Exactly 4 bytes +UN Unknown; // Any length of bytes +US Unsigned Short; // Exactly 2 bytes +UT Unlimited Text; // At most 2^32 -1 chars + diff --git a/Utilities/ITK/Utilities/gdcm/Dicts/gdcm.dic.in b/Utilities/ITK/Utilities/gdcm/Dicts/gdcm.dic.in new file mode 100644 index 0000000000000000000000000000000000000000..37ab8acf06649a7af2632518e96644f1e6bc15c9 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/Dicts/gdcm.dic.in @@ -0,0 +1 @@ +@TEST_DICT_BODY@ diff --git a/Utilities/ITK/Utilities/gdcm/INSTALL b/Utilities/ITK/Utilities/gdcm/INSTALL new file mode 100644 index 0000000000000000000000000000000000000000..922c4ae000362ac67f4e04d2038f3b6e0d2b94d7 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/INSTALL @@ -0,0 +1,19 @@ +################################################### +The installation documentation entry point is Doc/Website/Installation.html +################################################### +As of May 2004, cmake has taken over the world^W autotools, therefore +you'll need to grab a recent version from: http://cmake.org (later than 1.8.3) + + Then install instruction are: + * cvs -d:pserver:anonymous@cvs.creatis.insa-lyon.fr:2402/cvs/public login + answer anonymous + * cvs -d:pserver:anonymous@cvs.creatis.insa-lyon.fr:2402/cvs/public co gdcm + * mkdir gdcmbin + * cd gdcmbin + * ccmake ../gdcm + [select your configuration] + * Press 'c' (configure), Press 'g' (generate) + * make + * make install + + diff --git a/Utilities/ITK/Utilities/gdcm/PACKAGER b/Utilities/ITK/Utilities/gdcm/PACKAGER new file mode 100644 index 0000000000000000000000000000000000000000..7a8d88da775953c1d80980273d47ec2f3cb846c9 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/PACKAGER @@ -0,0 +1,140 @@ +Here is the checklist when freezing a version of gdcm: + +* First stage, checkings: + 1/ Un*x: + Notation: we here assume you have a cvs tree in GDCMHOME directory. + cvs -d:pserver:anonymous@cvs.creatis.insa-lyon.fr:2402/cvs/public login + cvs -d:pserver:anonymous@cvs.creatis.insa-lyon.fr:2402/cvs/public co gdcm + cd gdcm + export GDCMHOME=`pwd` + cvs -d:pserver:anonymous@cvs.creatis.insa-lyon.fr:2402/cvs/public co gdcmData + + 1a/ check the full compilation is effective: + ./autogen.sh --enable-vtk --enable-python --enable-doxygen + make + + 1b/ check the python test suite is clean: + cd gdcmPython + export PYTHONPATH=`pwd`/.. + ln -s .libs/pygdcm.so _gdcm.so + ln -s .libs/vtkgdcmPython.so . + python testSuite.py + + 1c/ check the setup.py distutil script is operational and then validate + its produced packages through the test suite, in all following cases + - Direct installation: + cd $GDCMHOME + python setup.py install --prefix=/tmp + cd /tmp/lib/python2.2/site-packages/ + ln -s $GDCMHOME/gdcmData . + export PYTHONPATH=`pwd` + cd gdcmPython/ + python testSuite.py + cd $GDCMHOME + \rm -fr build /tmp/lib + - Binary distribution: + cd $GDCMHOME + make clean + [ or you migth get some complains about the function + PyVTKClass_vtkGdcmReaderNew being multiply defined: this is + because of the loose definition of vtkSources in setup.py + in which the usage of the glob function will produce a link + stage with multiple occurences of vtkGdcmReaderPython.o)]. + python setup.py bdist --formats=rpm + su + rpm -Uvh dist/gdcmPython-0.*.i386.rpm + cd /usr/lib/python2.2/site-packages/ + ln -s $GDCMHOME/gdcmData . + cd gdcmPython + python testSuite.py + rpm --erase gdcmPython + - Source distribution and then binary distribution (out of build + source distro): + cd $GDCMHOME + [make clean (see above) ] + python setup.py sdist + cd /tmp + tar zxvf $GDCMHOME/dist/gdcmPython-*.tar.gz + cd gdcmPython-*/ + python setup.py bdist --formats=rpm + cd dist + As root, repeat above installation with rpm and test. + + 2/ Windoze: + Notation: we consider that GDCMHOME is the directory obtained from the + following checkout. + cvs -d:pserver:anonymous@cvs.creatis.insa-lyon.fr:2402/cvs/public login + cvs -d:pserver:anonymous@cvs.creatis.insa-lyon.fr:2402/cvs/public co gdcm + cd gdcm + cvs -d:pserver:anonymous@cvs.creatis.insa-lyon.fr:2402/cvs/public co gdcmData + + 2a/ compile all projects in the gdcm.dsw workspace. + + 2b/ set the PYTHONPATH environement variable to the gdcm/gdcmPython + directory + check the python test suite is clean (python testSuite.py) + cd gdcmPython + python testSuite.py + + 2c/ check the setup.py distutil script is operational and then validate + its produced packages through the test suite, in all following cases + - Direct installation: + cd $(GDCMHOME) + python setup.py install --prefix="c:\tmp" + cd /tmp/Lib/site-packages/ + copy $(GDCMDATAHOME) . + export PYTHONPATH="c:\tmp\Lib\site-packages" + cd gdcmPython/ + python testSuite.py + remove $(GDCMHOME)\build directory + - Binary distribution: + cd $(GDCMHOME) + python setup.py bdist --formats=wininst + install $(GDCMHOME)\dist\gdcmPython-xxx.win32-py2.2.exe + cd $(PYTHONHOME)\Lib\site-packages\ + Check out gdcmData + cd gdcmPython + clean up PYTHONPATH + python testSuite.py + remove $(GDCMHOME)\build directory + - Source distribution and then binary distribution (out of build + source distro): + cd $(GDCMHOME) + python setup.py sdist --formats=zip + unzip $(GDCMHOME)\dist\gdcmPython-xxx.zip in TMPHOME directory + cd $(TMPHOME) + cd gdcmPython-*/ + python setup.py bdist --formats=wininst + As root, repeat above installation with exe and test. + +* Second stage: preparing packaging: + - Update the version number in configure.in (AM_INIT_AUTOMAKE) + - Update the version number in setup.py (version entry in setup object). + +* Third stage: packaging + 1/ Un*x + 1a/ Packaging at the C/C++/Python level (i.e. exports both libraries, + include files and python package) + - Make sure you have a ~/.rpmmacros file containing the line + %_topdir <somedirectoryPath> + and that <somedirectoryPath> exists and contains the subdirs + BUILD, SOURCES, RPMS/i386, SRPMS, SPECS + - cd $(GDCMHOME) + - ./autogen.sh --enable-vtk --enable-python --enable-doxygen + - make release (generates gdcm-x.y.z.tar.gz) + - rpm -ta gdcm-x.y.z.tar.gz + - collect the result in <somedirectoryPath>/RPMS/i386/ and + <somedirectoryPath>/SRPMS. + 1b/ Packaging at the python level: + cd $(GDCMHOME) + python setup.py sdist + python setup.py bdist --formats=rpm + collect both source distro and binary distro + + 2/ Un*x + 2a/ Packaging at the python level: + cd $(GDCMHOME) + python setup.py sdist --formats=zip + python setup.py bdist --formats=wininst + collect both source distro and binary distro + diff --git a/Utilities/ITK/Utilities/gdcm/README b/Utilities/ITK/Utilities/gdcm/README new file mode 100644 index 0000000000000000000000000000000000000000..f4f531397c4cc6d635c5601dd90f4d40ae8df3e2 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/README @@ -0,0 +1,28 @@ +For a general introduction/features/limitations/requirement please +refer to http://www.creatis.insa-lyon.fr/Public/Gdcm + +Just a quick note on the build process of GDCM. GDCM build process +make use of the cmake software(*). This allow us: +1. To get rid of the autoconf/autotools insanity +2. Transparently generate Unix Makefiles, NMake Makefiles, +Borland Makefiles, VS6/7/8 Project, XCode 1.5... +3. Automatic nightly testing, one of the most important thing +for a robust library/software devlpt process. GDCM devpt is develop +based on the XP definition, and to preserve backward compatibility +make sure that code is working from one release to another: each night +we configure, we build and we test GDCM. The result are then send to +the dashboard located at: + + http://public.kitware.com/dashboard.php?name=gdcm + +A continuous dashboard make also sure that aby commit did not introduce +any error on another plateform, a warning or broke a test... + +Therefore you should be able to use GDCM from the bleeding edge without +knowing to much on what is going on. All you need to do is have a look +at the GDCM dashboard, and if your plateform is 'green' then you can +update your cvs copy and compile safely knowing that there are very few chances +that something won't work. Cheers ! + + +(*) http://www.cmake.org for more information diff --git a/Utilities/ITK/Utilities/gdcm/README.ITK.txt b/Utilities/ITK/Utilities/gdcm/README.ITK.txt new file mode 100644 index 0000000000000000000000000000000000000000..70fb620d41955937cb2648bd97e3bd161ea813cb --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/README.ITK.txt @@ -0,0 +1,14 @@ +This directory contains a subset of the CREATIS Dicom library +gdcm version 1.0. We only include enough of distribution to build +gdcm. We do not include the standard executables that come with +gdcm (PrintHeader, vtkviewer, or any python sample). + +We'd like to thank the Creatis lab for distributing a public GDCM +IO library, and modifying the license to be BSD compatible + +Modifications +------------- + +We reuse the jpeg library from ITK instead of building the one shipped +with gdcm. Therefore all gdcmjpeg* name were changed to itkjpeg*. +Same thing for include directory diff --git a/Utilities/ITK/Utilities/gdcm/gdcm.spec.in b/Utilities/ITK/Utilities/gdcm/gdcm.spec.in new file mode 100644 index 0000000000000000000000000000000000000000..d073f57ef2951c262826be997aa35cc409d5aa5c --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/gdcm.spec.in @@ -0,0 +1,48 @@ +# Note that this is NOT a relocatable package +%define ver @VERSION@ +%define RELEASE 1 +%define rel %{?CUSTOM_RELEASE} %{!?CUSTOM_RELEASE:%RELEASE} +%define prefix /usr + +Summary: Dicom library +Name: gdcm +Version: %ver +Release: %rel +License: BSD +Group: Development/Tools +URL: http://www.creatis.insa-lyon.fr/Public/Gdcm +Source0: http://www.creatis.insa-lyon.fr/Public/Gdcm/gdcm-%{version}.tar.gz +BuildRoot: %{_tmppath}/gdcm-root +Requires: python2 +BuildRequires: doxygen, swig13, python2 +Packager: Fabrice Bellet <Fabrice.Bellet@creatis.insa-lyon.fr> + +%description +gdcm is a library dedicated to read and write DICOM files. + +%prep +%setup -q + +%build +%configure --enable-doxygen --enable-python +make + +%install +%makeinstall + +%clean +rm -rf $RPM_BUILD_ROOT + +%files +%defattr(-,root,root) +%doc AUTHORS INSTALL NEWS README TODO +%{_libdir}/libgdcm* +%{_datadir}/gdcm +%{_libdir}/python*/site-packages/gdcm +%{_includedir}/*.h + +%changelog +* Mon Mar 17 2003 Fabrice Bellet <Fabrice.Bellet@creatis.insa-lyon.fr> 0.1.0-1 +- Rebuild for Red Hat Linux 7.3 +- First packaging. + diff --git a/Utilities/ITK/Utilities/gdcm/gdcmConfigure.h.in b/Utilities/ITK/Utilities/gdcm/gdcmConfigure.h.in new file mode 100644 index 0000000000000000000000000000000000000000..806d5ae4b3835dec1706c88a00e3e1590efbe28d --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/gdcmConfigure.h.in @@ -0,0 +1,98 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmConfigure.h.in,v $ + Language: C++ + Date: $Date: 2006/02/27 23:11:35 $ + Version: $Revision: 1.8 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#ifndef __gdcmConfigure_h +#define __gdcmConfigure_h + +/* This header is configured by GDCM's build process. */ + +/*--------------------------------------------------------------------------*/ +/* Platform Features */ + +/* Byte order. */ +#cmakedefine GDCM_WORDS_BIGENDIAN + +/* Allow access to UINT32_MAX , cf gdcmCommon.h */ +#define __STDC_LIMIT_MACROS + +/* Hard code the path to the public dictionary */ +#define PUB_DICT_PATH "@GDCM_PUB_DICT_PATH@" + +/* Hardcode the path to GDCM_DATA_ROOT */ +#define GDCM_DATA_ROOT "@GDCM_DATA_ROOT@" + +/* Usefull in particular for loadshared where the full path + * to the lib is needed */ +#define GDCM_EXECUTABLE_OUTPUT_PATH "@EXECUTABLE_OUTPUT_PATH@" +#define GDCM_LIBRARY_OUTPUT_PATH "@LIBRARY_OUTPUT_PATH@" + +/* For older gcc / broken plateform */ +#cmakedefine GDCM_NO_ANSI_STRING_STREAM + +/* I guess something important */ +#cmakedefine CMAKE_HAVE_STDINT_H +#cmakedefine CMAKE_HAVE_INTTYPES_H + +/* This variable allows you to have helpful debug statement */ +/* That are in between #ifdef / endif in the gdcm code */ +/* That means if GDCM_DEBUG is OFF there shouldn't be any 'cout' at all ! */ +/* only cerr, for instance 'invalid file' will be allowed */ +#cmakedefine GDCM_DEBUG + +/* Whether we are building shared libraries. */ +/* This was important as long as GDCM is LGPL */ +#cmakedefine BUILD_SHARED_LIBS + +/* GDCM uses __FUNCTION__ which is not ANSI C, but C99 */ +#cmakedefine GDCM_COMPILER_HAS_FUNCTION + + +/* GetMacAddress require a lot of include file to access low level API */ +#cmakedefine CMAKE_HAVE_UNISTD_H +#cmakedefine CMAKE_HAVE_STDLIB_H +#cmakedefine CMAKE_HAVE_SYS_IOCTL_H +#cmakedefine CMAKE_HAVE_SYS_SOCKET_H +#cmakedefine CMAKE_HAVE_SYS_SOCKIO_H +#cmakedefine CMAKE_HAVE_NET_IF_H +#cmakedefine CMAKE_HAVE_NETINET_IN_H +#cmakedefine CMAKE_HAVE_NET_IF_DL_H +#cmakedefine CMAKE_HAVE_NET_IF_ARP_H +#cmakedefine HAVE_SA_LEN + +#cmakedefine GDCM_FORCE_BIGENDIAN_EMULATION + +/* For OpenJPEG */ +#cmakedefine OPJ_EXPORTS +#cmakedefine OPJ_STATIC + +/*--------------------------------------------------------------------------*/ +/* GDCM Versioning */ + +/* Version number. */ +#define GDCM_MAJOR_VERSION @GDCM_MAJOR_VERSION@ +#define GDCM_MINOR_VERSION @GDCM_MINOR_VERSION@ +#define GDCM_BUILD_VERSION @GDCM_BUILD_VERSION@ +#define GDCM_VERSION "@GDCM_VERSION@" + +/*--------------------------------------------------------------------------*/ +/* GDCM deprecation mechanism */ +#cmakedefine GDCM_LEGACY_REMOVE +#cmakedefine GDCM_LEGACY_SILENT + + +#endif diff --git a/Utilities/ITK/Utilities/gdcm/src/.cvsignore b/Utilities/ITK/Utilities/gdcm/src/.cvsignore new file mode 100644 index 0000000000000000000000000000000000000000..30a9615f03da8e36010d2db36e371fde5de29912 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/.cvsignore @@ -0,0 +1,18 @@ +*.o +*.so +.deps +.libs +Makefile.in +Makefile +*.lo +*.la +*Debug* +*Release* +config.h +config.h.in +stamp-h +stamp-h1 +stamp-h.in +DartTestfile.txt +cmake.check_depends +cmake.depends diff --git a/Utilities/ITK/Utilities/gdcm/src/CMakeLists.txt b/Utilities/ITK/Utilities/gdcm/src/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..f7e967c483893ed704fd7674821c88f478723c2f --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/CMakeLists.txt @@ -0,0 +1,83 @@ +#----------------------------------------------------------------------------- +# Rebuild gdcm whenever a file starting with gdcm* is modified +INCLUDE_REGULAR_EXPRESSION("^gdcm.*$") + +# Add proper includes +INCLUDE_DIRECTORIES( + ${GDCM_SOURCE_DIR}/src + ${GDCM_BINARY_DIR} #for gdcmConfigure.h + ${GDCM_BINARY_DIR}/src #for gdcmjpeg 8, 12 and 16 +) + +SET(libgdcm_la_SOURCES + gdcmArgMgr.cxx + gdcmBase.cxx + gdcmBinEntry.cxx + gdcmContentEntry.cxx + gdcmDebug.cxx + gdcmDicomDir.cxx + gdcmDicomDirElement.cxx + gdcmDicomDirImage.cxx + gdcmDicomDirMeta.cxx + gdcmDicomDirObject.cxx + gdcmDicomDirPatient.cxx + gdcmDicomDirVisit.cxx + gdcmDicomDirSerie.cxx + gdcmDicomDirStudy.cxx + gdcmDict.cxx + gdcmDictEntry.cxx + gdcmDictGroupName.cxx + gdcmDictSet.cxx + gdcmDirList.cxx + gdcmDocEntry.cxx + gdcmDocEntryArchive.cxx + gdcmDocEntrySet.cxx + gdcmDocument.cxx + gdcmElementSet.cxx + gdcmException.cxx + gdcmFileHelper.cxx + gdcmGlobal.cxx + gdcmFile.cxx + gdcmJPEGFragment.cxx + gdcmJPEGFragmentsInfo.cxx + gdcmJpeg8.cxx + gdcmJpeg12.cxx + gdcmJpeg16.cxx + gdcmJpeg2000.cxx + gdcmOrientation.cxx + gdcmPixelReadConvert.cxx + gdcmPixelWriteConvert.cxx + gdcmRLEFrame.cxx + gdcmRLEFramesInfo.cxx + gdcmSeqEntry.cxx + gdcmSerieHelper.cxx + gdcmSQItem.cxx + gdcmTS.cxx + gdcmUtil.cxx + gdcmValEntry.cxx + gdcmValidator.cxx + gdcmVR.cxx + ${GDCM_BINARY_DIR}/src/gdcmDefaultDicts.cxx + ) + +ADD_LIBRARY(itkgdcm ${libgdcm_la_SOURCES}) +TARGET_LINK_LIBRARIES(itkgdcm + itkjpeg8 + itkjpeg12 + itkjpeg16 + itkopenjpeg +) +IF(WIN32) + IF(NOT BORLAND) + TARGET_LINK_LIBRARIES(itkgdcm wsock32 snmpapi) + ENDIF(NOT BORLAND) +ENDIF(WIN32) + +# Need nsl to resolve gethostbyname on SunOS-5.8 +# and socket also +IF(CMAKE_SYSTEM MATCHES "SunOS.*") + TARGET_LINK_LIBRARIES(itkgdcm socket nsl) +ENDIF(CMAKE_SYSTEM MATCHES "SunOS.*") + +INSTALL_FILES(/include/InsightToolkit/gdcm/src "\\.h$") +INSTALL_TARGETS(/lib/InsightToolkit itkgdcm) diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcm.h b/Utilities/ITK/Utilities/gdcm/src/gdcm.h new file mode 100644 index 0000000000000000000000000000000000000000..8d30d2d130f08cbf3cefafa312c0b84e877a015a --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcm.h @@ -0,0 +1,45 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcm.h,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:38 $ + Version: $Revision: 1.4 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#ifndef GDCM_H +#define GDCM_H + +// General purpose include file. This file should be included by +// external users of gdcm. It exposes the necessary API. + +#include "gdcmCommon.h" +#include "gdcmUtil.h" +#include "gdcmDebug.h" + +#include "gdcmDictEntry.h" +#include "gdcmDict.h" +#include "gdcmDictSet.h" + +#include "gdcmDocument.h" +#include "gdcmFile.h" + +#include "gdcmFileHelper.h" +#include "gdcmSerieHelper.h" + +#include "gdcmValEntry.h" +#include "gdcmBinEntry.h" +#include "gdcmSeqEntry.h" + +#include "gdcmValidator.h" + +#endif diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmArgMgr.cxx b/Utilities/ITK/Utilities/gdcm/src/gdcmArgMgr.cxx new file mode 100644 index 0000000000000000000000000000000000000000..25bf79579ef8dd6fc730da3848b4502e6709f0fc --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmArgMgr.cxx @@ -0,0 +1,906 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmArgMgr.cxx,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:38 $ + Version: $Revision: 1.2 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#include <stdio.h> +#include <iostream> +#include <ctype.h> +#include <string.h> // For strlen + +// No strcasecmp in WIN32 world, but stricmp +// http://www.opengroup.org/onlinepubs/007908799/xsh/strcasecmp.html +#ifdef _WIN32 +#define strcasecmp stricmp +#endif + +#include <string.h> // For strtok and strlen +#include <stdlib.h> // For strtol and strtod + +#include "gdcmArgMgr.h" + +namespace gdcm +{ +//------------------------------------------------------------------------- +// Constructor / Destructor + +/** + * \brief constructor + * @param argc arguments count, as passed to main() + * @param argv pointers array on the arguments passed to main() + */ + ArgMgr::ArgMgr(int argc, char **argv) + { + int i; + int nblettre; + ArgUsed = NULL; + Appel = NULL; + + /* Read the parameters of the command line *************************/ + for ( ArgCount=0, nblettre=1 , i=0; i<argc; i++) + { + if ( FiltreLong(argv[i]) ) + { + std::cout << "Argument too long ( > " + << ARG_LONG_MAX << ")" << std::endl; + return; + } + if ( argv[i][0] == '@' ) + { + nblettre += ArgLoadFromFile ( &argv[i][1] ); + } + else + { + ArgLab [ArgCount] = strcpy ( (char *)malloc(strlen(argv[i])+1), argv[i] ) ; + nblettre += 1 + strlen(ArgLab[ArgCount]); + ArgCount++; + } + if (ArgCount >= ARGMAXCOUNT ) + { + std::cout << "Too many Arguments ( more than " + << ARGMAXCOUNT << ")" << std::endl; + return; + } + } + + /* Fills an array with the already used parameters ****/ + ArgUsed = (char *)calloc (1, ArgCount ); + + /* Builds the full string with all the parameters **************/ + Appel = (char *) calloc (1, nblettre ); + + for ( *Appel = '\0', i=0; i<ArgCount; i++) + { + strcat ( Appel, ArgLab [i] ) ; + strcat ( Appel, " " ) ; + } + + /* Splitting label from label value *************************************/ + for ( i=0; i<ArgCount; i++) + { + char * egaloufin = ArgLab[i] ; + while ( (*egaloufin != '\0') && (*egaloufin != '=') ) + egaloufin ++ ; + if ( *egaloufin ) *(egaloufin++) = '\0'; + ArgStr[i]= egaloufin; + } + + /* Set labels to upper-case (labels are not case sensitive ) *********/ + for ( i=0; i<ArgCount; i++) + ArgLab[i] = Majuscule ( ArgLab[i] ) ; + + /* Standard arguments are managed by ArgStdArgs **********************/ + ArgStdArgs(); + } + +/** + * \brief canonical destructor + */ +ArgMgr::~ArgMgr() +{ + for(int i=0;i<ArgCount;i++) + if ( ArgLab[i] ) + free(ArgLab[i]); + if ( ArgUsed ) + free(ArgUsed); + if ( Appel ) + free(Appel); +} + +/** + * \brief checks if a parameter exists in the command line + * @param param label name + * @return 0 if label is not found + * else, returns the number of the spot it was found last time. + */ +int ArgMgr::ArgMgrDefined( const char *param ) +{ + int i; + bool trouve; + char *temp; + temp = Majuscule ( param ) ; + for ( i = ArgCount-1; i>0; i-- ) + { + trouve = ( strcmp( ArgLab[i], temp )==0 ) ; + if ( trouve ) + { + ArgUsed[i] = true ; + for ( int j=1; j<i; j++) + { + if ( (!ArgUsed[j])&&(!strcmp(ArgLab[i],ArgLab[j])) ) + ArgUsed[j] = i ; + } + return i ; + } + } + return 0 ; +} + +/** + * \brief Gets the parameter value, read on the command line + * @param param name of the searched parameter label + * @return Value, as a char array, of the parameter + * whose label is given. + */ +char *ArgMgr::ArgMgrValue ( const char *param ) +{ + int trouve ; + if ( (trouve = ArgMgrDefined ( param )) != false ) + return ArgStr[trouve] ; + else + return NULL ; +} + +/** + * \brief Search for the first not yet used label + * @return Pointer to the char array holding the first non used label + */ +const char *ArgMgr::ArgMgrUnused ( ) +{ + int i ; + for ( i=ArgCount-1; i>0; i-- ) + { + if ( ! ArgUsed[i] ) + { + ArgMgrDefined(ArgLab[i]); + return ArgLab[i] ; + } + } + return NULL ; +} + +/** + * \brief Prints unused labels, if any + * @return number of unused labels + */ +int ArgMgr::ArgMgrPrintUnusedLabels () +{ + const char *label; + int i=0; + while ( (label=ArgMgrUnused())!=0 ) + { + if (i==0) + std::cout << "\n Unused Labels:" << std::endl + << "==============" << std::endl; + std::cout << "Label : " << label << " = " + << ArgMgrValue(label) << std::endl; + i++; + } + return i; +} + +/** + * \brief Prints program usage + * @param usage array of pointers to the documentation lines of the program. + * @return exception code + */ +int ArgMgr::ArgMgrUsage(const char **usage ) +{ + while ( *usage ) + std::cout << std::endl << *(usage++); + std::cout << std::endl; + return (0); +} + +/** + * \brief Forget it, right now ... + * Saves a char. array in a parameter file + * whose name is given on command line by : PARAMOUT=??? + * or, as a default, by ARG_DEFAULT_PARAMOUT + * @param param char. array that defines the parameter + * @return Entier correspondant au rang dans la liste de labels + */ +int ArgMgr::ArgMgrSave ( const char *param ) +{ + static int deja = 0; + FILE *fd; + if ( *ArgParamOut == '\0' ) + return 0; + if ( deja ) + { + fd = fopen ( ArgParamOut, "a+" ); + } + else + { + deja = 1; + fd = fopen ( ArgParamOut, "w" ); + } + if ( !fd ) + return 0; + fprintf ( fd, "%s\n", param ); + fclose ( fd ); + return 1; +} + +/** + * \brief Gets an int value passed as an argument to a program + * (use default value if not found) + * EXAMPLE: int dimx = ArgMgrGetInt ( "DIMX", 256 ); + * @param label label name + * @param defaultVal default value + * @return parameter value + */ +int ArgMgr::ArgMgrGetInt(const char *label, int defaultVal) +{ + return ( (ArgMgrDefined(label)) + ? (atoi(ArgMgrValue(label))) + : (defaultVal) ); +} + +/** + * \brief Gets a float value passed as an argument to a program + * (use default value if not found) + * EXAMPLE: float scale = ArgMgrGetFloat ( "SCALE", 0.33 ); + * @param param label name + * @param defaultVal default value + * @return parameter value + */ +float ArgMgr::ArgMgrGetFloat(const char *param, float defaultVal) +{ + return ( (ArgMgrDefined(param)) + ? ((float)atof(ArgMgrValue(param))) + : (defaultVal) ); +} + +/** + * \brief Gets a 'string' value passed as an argument to a program + * (use default value if not found) + * EXAMPLE : char *imageName = ArgMgrGetString( "NAME", "test.dcm" ); + * @param param label name + * @param defaultVal default value + * @return parameter value + */ +const char *ArgMgr::ArgMgrGetString(const char *param, const char *defaultVal) +{ + return ( (ArgMgrDefined(param)) + ? (ArgMgrValue(param)) + : (defaultVal) ); +} + +/** + * \brief Gets a value amongst a set of values + * (use default value if not found) + * EXAMPLE: int nlab = ArgMgrGetLabel("CONFIRM","NO\\YES", 0); + * @param param label name + * @param liste character Chain describing the various values. + * Value are separated by '\\'. + * Not case sensitive. + * @param val number of default value + * @return int : range of value amongst the values list + */ +int ArgMgr::ArgMgrGetLabel (const char *param, const char *liste, int val ) +{ + char *lab; + const char *vallab; + int i = 1; + char *tmp; + tmp = (char *) malloc(strlen(liste)+1); + strcpy(tmp,liste); + + if ( (vallab = ArgMgrGetString(param,(const char *)NULL)) != 0 ) + { + for ( lab = strtok (tmp,"\\"); + lab != 0; + lab = strtok(0L,"\\"), i++ ) + { + // strcmp ignoring case + if( strcasecmp(lab, vallab) == 0) + return i; + } + val=0; + } + free(tmp); + return val; +} + +/** + * \brief Demands a value amongst a set of values (abort if not found) + * EXaMPLE: int nlab = ArgMgrWantLabel("CONFIRM","NO\\YES", usage); + * @param param label name + * @param liste character Chain describing the various values. + * Labels are separated by '\\'. + * No case sensitive. + * WARNING this will be changed (not const) + * @param usage Usage program (displayed if label not found) + * @return int : range of value amongst the values list + */ +int ArgMgr::ArgMgrWantLabel (const char *param, char *liste, const char **usage ) +{ + char *lab; + const char *vallab; + int i = 1; + if ( (vallab = ArgMgrGetString(param,0)) != 0 ) + { + for ( lab = strtok (liste,"\\"); lab != 0; lab = strtok(0L,"\\"), i++ ) + if ( strcasecmp(lab,vallab)==0) + return i; + return 0; + } + ArgMgrUsage(usage); + return 0; +} + +/** + * \brief Demands an int value passed as an argument to a program + * If not found usage is displayed and the prog aborted + * EXAMPLE: int dimx = ArgMgrWantInt ( "DIMX", usage ); + * @param label label name + * @param usage Usage program (displayed if label not found) + * @return parameter value + */ +int ArgMgr::ArgMgrWantInt (const char *label, const char **usage) +{ + return ( (ArgMgrDefined(label) ) + ? (atoi(ArgMgrValue(label) ) ) + : (ArgMgrUsage(usage),1) ); +} + +/** + * \brief Demands a float value passed as an argument to a program + * If not found usage is displayed and the prog aborted + * EXAMPLE: float scale = ArgMgrWantFloat ( "SCALE", usage ); + * @param label label name + * @param usage Usage program (displayed if label not found) + * @return parameter value + */ +float ArgMgr::ArgMgrWantFloat (const char *label, const char **usage) +{ + return ( (ArgMgrDefined(label) ) + ? ((float)atof(ArgMgrValue(label) ) ) + : (ArgMgrUsage(usage),(float)1.0) ); +} + +/** + * \brief Demands a 'string' value passed as an argument to a program + * If not found usage is displayed and the prog aborted + * EXAMPLE: char *code = ArgMgrWantString ( "CODE", usage ); + * @param label Parameter label + * @param usage Usage program (displayed if label not found) + * @return parameter value + */ +char *ArgMgr::ArgMgrWantString(const char *label, const char **usage) +{ + return ( (ArgMgrDefined(label) ) + ? (ArgMgrValue(label) ) + : (ArgMgrUsage(usage),(char*)0) ); +} + +/** + * \brief decodes and returns an array of 'STRING' + * EXAMPLE: char **codes = ArgMgrGetListOfString ( "CODES", &nbOfCodes ); + * @param label label name + * @param number nb of found 'STRINGs' + * @return Pointer to the 'STRING' array; NULL if error + */ +char **ArgMgr::ArgMgrGetListOfString ( const char *label, int *number ) +{ + int taille; + char *value = ArgMgrValue(label); + char **liste; + char **elem; + char *chainecur; + if (!value) + { + *number = 0; + return 0; + } + *number = IdStrCountChar(value,',')+1; /* nb Elements = nb Commas +1 */ + taille = *number; + liste = (char **) malloc (sizeof(char*) * taille + strlen(value)+1); + if ( !liste ) + return 0; + value = strcpy( ((char*)liste)+sizeof(char*) * taille, value ); + for ( elem = liste, chainecur = strtok(value,", "); + taille>0; + taille--, chainecur = (chainecur) ? strtok ( 0, ", " ) : 0 ) + { + *(elem++) = chainecur; + } + return liste; +} + +/** + * \brief decodes and returns an array of 'INT' + * EXAMPLE: int *points = ArgMgrGetListOfInt ( "POINTS", &nbOfPoints ); + * @param label label name + * @param number nb of found INT + * @return Pointer to the INT array; NULL if error + */ +int *ArgMgr::ArgMgrGetListOfInt ( const char *label, int *number ) +{ + char *value = ArgMgrValue(label); + int *liste; + int *elem; + int taille; + if (!value) + { + *number = 0; + return 0; + } + *number = IdStrCountChar(value,',')+1; /* nb Elements = nb Commas +1 */ + taille= *number; + liste = (int *) calloc (1,sizeof(int)*taille ); + if ( !liste ) + return 0; + elem = liste; + //*number = 1; + + while ( taille>0 ) + { + *(elem++) = (int) strtol ( value, &value, 10 ); + if ( *value == '\0' ) + return liste; + if ( *(value++) != ',' ) + { + free (liste); + return 0; + } + taille --; + } +return liste; +} + +/** + * \brief decodes and returns an array of 'FLOAT' + * @param label label name + * @param number number of found FLOATs + * @return Pointer to the FLOAT array; NULL if error + */ +float *ArgMgr::ArgMgrGetListOfFloat ( const char *label, int *number ) +{ + char *value = ArgMgrValue(label); + float *liste; + float *elem; + int taille; + if (!value) + return 0; + *number = IdStrCountChar(value,',')+1; /* nb Elements = nb Commas +1 */ + taille= *number; + liste = (float *) calloc (1,sizeof(float)*taille ); + if ( !liste ) + { + *number = 0; + return 0; + } + elem = liste; + //*number = 1; + + while ( taille>0 ) + { + *(elem++) = (float) strtod ( value, &value ); + if ( *value == '\0' ) + return liste; + if ( *(value++) != ',' ) + { + free (liste); + return 0; + } + taille --; + } +return liste; +} + +/** + * \brief decodes and returns an array of 'INT pairs', passed in decimal + * @param param label name + * @param number nb of found pairs + * @return pointer to the array of 'INT pairs'; NULL if fail + */ +int *ArgMgr::ArgMgrGetIntEnum ( const char *param, int *number ) +{ + char *value = ArgMgrValue(param); + int *liste; + if (!value) + { + *number = 0; + return 0; + } + liste = IdStrIntEnum(value, number); + return liste; +} + +/** + * \brief decodes and returns an array of 'INT16 pairs', passed in hexadecimal + * @param param label name + * @param number nb of found pairs + * @return pointer to the array of 'INT16 pairs'; NULL if fail + */ +uint16_t *ArgMgr::ArgMgrGetXInt16Enum ( const char *param, int *number ) +{ + char *value = ArgMgrValue(param); + uint16_t *liste; + if (!value) + { + *number = 0; + return 0; + } + liste = IdStrXInt16Enum(value, number); + return liste; +} +/** + * \brief decodes and returns an array of 'FLOAT pairs' + * @param param label name + * @param number nb of found pairs + * @return pointer to the array of 'FLOAT pairs'; NULL if fail + + */ +float *ArgMgr::ArgMgrGetFloatEnum ( const char *param, int *number ) +{ + char *value = ArgMgrValue(param); + float *liste; + if (!value) + { + *number = 0; + return 0; + } + liste = IdStrFloatEnum(value, number); + return liste; +} + +// ------------------------ Those are 'service functions' --------------------- +// ------------------------ internal use only --------------------- + +/** + * \brief Counts the nb of occurrences of a given charact within a 'string' + * @param chaine Pointer to the 'string' + * @param caract charact to count + * @return occurence number + */ +int ArgMgr::IdStrCountChar (char *chaine, int caract) +{ + int i=0; + char *ptr; + for ( ptr = chaine ; *ptr!='\0' ; ptr ++ ) + if (*ptr==caract) + i++; + return i; +} + +/** + * \brief returns an array of 'INT pairs' + * @param value char array decribing a set of 'INT pairs' (f1-l1, f2-l2, ...) + * @param number nb of found INT pairs + * @return pointer to the array of 'INT pairs' + */ +int *ArgMgr::IdStrIntEnum ( char* value, int *number) +{ + int* liste; + int taille; + int i; + + *number = IdStrCountChar(value,',')+1; /* nb Elements = nb Commas +1 */ + taille= *number; + liste = (int *) calloc (1,sizeof(int)*2*taille ); + if ( !liste ) + { + return 0; + } + i=0; + while ( taille>0 ) + { + liste[i] = (int) strtol ( value, &value, 10 ); + if ( *value == '\0' ) + { + liste[i+1]=liste[i]; + return liste; + } + if ( *(value++) != '-' ) + { + liste[i+1]=liste[i]; + value--; + } + else + { + liste[i+1] = (int) strtol ( value, &value, 10 ); + } + if ( *value == '\0' ) + return liste; + if ( *(value++) != ',' ) + { + free (liste); + return 0; + } + taille --; i+=2; + } + return liste; +} + +/** + * \brief returns an array of set of 'INT16 pairs', passed in Hexadecimal + * @param value char array decribing a set of 'INT16 pairs' (f1-l1, f2-l2, ...) + * coded in hexadecimal e.g. 0x0008,0x00ac + * @param number nb of found pairs + * @return array of set of 'INT16 pairs' + */ +uint16_t *ArgMgr::IdStrXInt16Enum ( char *value, int *number) +{ + uint16_t *liste; + int taille; + int i; + + *number = IdStrCountChar(value,',')+1; /* nb Elements = nb Commas +1 */ + taille= *number; + liste = (uint16_t *) calloc (1,sizeof(uint16_t)*2*taille ); + if ( !liste ) + { + return 0; + } + i=0; + while ( taille>0 ) + { + liste[i] = (uint16_t) strtol ( value, &value, 16 ); + if ( *value == '\0' ) + { + liste[i+1]=liste[i]; + return liste; + } + if ( *(value++) != '-' ) + { + liste[i+1]=liste[i]; + value--; + } + else + { + liste[i+1] = (uint16_t) strtol ( value, &value, 16 ); + } + if ( *value == '\0' ) + return liste; + if ( *(value++) != ',' ) + { + free (liste); + return 0; + } + taille --; i+=2; + } + return liste; +} +/** + * \brief returns an array of 'FLOAT pairs' + * @param value char array decribing a set of 'FLOAT pairs' (f1-l1, f2-l2, ...) + * @param number nb of found pairs + * @return pointer to the array of 'FLOAT pairs'; NULL if fail + */ +float *ArgMgr::IdStrFloatEnum (char *value, int *number) +{ + float *liste; + int taille; + int i; + *number = IdStrCountChar(value,',')+1; /* nb Elements = nb Commas +1 */ + taille= *number; + liste = (float *) calloc (1,sizeof(float)*2*taille ); + if ( !liste ) + return 0; + i=0; + while ( taille>0 ) + { + liste[i] = (float) strtod ( value, &value ); + if ( *value == '\0' ) + { + liste[i+1]=liste[i]; + return liste; + } + if ( *(value++) != '-' ) + { + liste[i+1]=liste[i]; + value--; + } + else + { + liste[i+1] = (float) strtod ( value, &value ); + } + if ( *value == '\0' ) + return liste; + if ( *(value++) != ',' ) + { + free (liste); + return 0; + } + taille --; i+=2; + } + return liste; +} + +//----------------------------------------------------------------------------- +// Protected + +//----------------------------------------------------------------------------- +// Private + +/************************************************************************** +* * +* Nom de la fonction : Majuscule * +* Role ............. : Creates a new Upper case char array. * +* parameters ....... : Pointer to the initial char array. * * +* Valeur retournee . : Pointer to the new Upper case char array. * +* * +**************************************************************************/ +char *ArgMgr::Majuscule (const char *chaine ) +{ + char *ptr, *ptr2, *ptr3; + ptr2 = (char *)malloc(strlen(chaine)*sizeof(char)+1); + ptr3=ptr2; + for ( ptr = (char *)chaine ; *ptr!='\0' ; ptr ++ ) + { + *ptr3 = toupper ( * ptr ); ptr3++; + } + *ptr3='\0'; + return ptr2; +} + +/************************************************************************** +* * +* Nom de la fonction : FiltreLong * +* Role ............. : Stops the program if argument is too long. * +* ARG_LONG_MAX defines max length. * +* parameters ....... : Pointer to the argument. * +* Valeur retournee . : false if OK. * +* true if KO. * +**************************************************************************/ +int ArgMgr::FiltreLong ( const char *arg ) +{ + int n = 0 ; + while ( (n++<ARG_LONG_MAX) && (*(arg++) != '\0') ) ; + return (n>=ARG_LONG_MAX) ; +} + +/*------------------------------------------------------------------------ + | Role : Reads a parameter from a file + | Return : Type : char * + | Role : pointer to the label + | parameters : param : char * + | Role : one where the parameter will be stored + | fd : FILE * + | Role : File description (assumed to be open) + +------------------------------------------------------------------------*/ +const char *ArgMgr::LoadedParam ( const char *param, FILE *fd ) +{ + int carlu; + char *car = (char *)param; + int quote = false; + int nbcar = 0; + + /* remove spaces at the beginning****/ + while ( isspace(carlu=fgetc (fd)) ); + if (carlu==EOF) + return 0; + /* Search for a " */ + if ( carlu=='\"' ) + { + carlu=fgetc(fd); + quote=true; + /* Read all the characters */ + } + while ( (carlu!=EOF) + && ( ( (!quote)&&(!isspace(carlu)) ) + ||( (quote)&& !(carlu=='\"') ) ) ) + { + *(car++) = (char) carlu; + nbcar ++; + /* sans depasser la taille max*/ + if ( nbcar >= ARG_LONG_MAX ) + { + std::cout << "\nError: Argument too long ( > " + << ARG_LONG_MAX << ")in parameter file." + << std::endl; + break; + } + carlu = fgetc(fd); + } + *car = '\0'; + return param; +} + +/*------------------------------------------------------------------------ + | Role : Reading of arguments in a parameter file + | (this function is recursive). + | Return : Type : int + | Role : length needed to store all the parameters + | parameters : filename : char * + | Role : parameter File name + | + +------------------------------------------------------------------------*/ +int ArgMgr::ArgLoadFromFile ( const char *filename ) +{ + int nbl = 0; + char param[ARG_LONG_MAX+1]; + FILE *fch; + + fch = fopen ( filename, ID_RFILE_TEXT ); + while ( LoadedParam (param, fch ) ) + { + int n = strlen(param); + if ( param[0]=='@' ) + { + nbl += ArgLoadFromFile ( ¶m[1] ); + } + else + { + ArgLab [ArgCount] = strcpy ((char *) malloc(n+1), param ) ; + nbl += n + 1 ; + ArgCount++; + if ( ArgCount >= ARGMAXCOUNT ) + break; + } + } + fclose ( fch ); + return nbl; +} + +/*------------------------------------------------------------------------ + | Role : Standard parameters management (on command line) + | Return : Type : void + | parameters : none + +------------------------------------------------------------------------*/ +void ArgMgr::ArgStdArgs() +{ + char *logfile; + FILE *fd; + + if ( (ArgParamOut=ArgMgrValue((char*)ARG_LABEL_PARAMOUT))==0 ) + ArgParamOut = ARG_DEFAULT_PARAMOUT; + if ( (logfile = ArgMgrValue((char*)ARG_LABEL_LOGFILE))!=0) + { + if ( *logfile == '\0' ) + logfile = (char *)ARG_DEFAULT_LOGFILE; + fd = fopen ( logfile, "a+" ); + if ( fd ) + { + fprintf ( fd, "%s\n", Appel ); + fclose ( fd ); + } + } +} + +/*------------------------------------------------------------------------ + | Role : Sets in Upper Case. + | Return : Type : char * + | parameters : char * + +------------------------------------------------------------------------*/ +char *ArgMgr::maj ( char *a ) +{ + char *b = a; + while ( *b !=0 ) + { + if ( *b<='z' && *b>='a' ) *b = *b+'A'-'a'; + b++; + } + return a; +} +//----------------------------------------------------------------------------- +// Print + +//----------------------------------------------------------------------------- +} // end namespace gdcm diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmArgMgr.h b/Utilities/ITK/Utilities/gdcm/src/gdcmArgMgr.h new file mode 100644 index 0000000000000000000000000000000000000000..619dac5a48d3638eb9e66ea1011f8d35040f46cf --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmArgMgr.h @@ -0,0 +1,112 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmArgMgr.h,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:38 $ + Version: $Revision: 1.2 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#ifndef ___ARG_MGR__ +#define ___ARG_MGR__ + +#include "gdcmCommon.h" +#include <stdio.h> // for FILE +#include <stdlib.h> // For atof + +namespace gdcm +{ + +#define ID_RFILE_TEXT "rt" +#define ARGMAXCOUNT 100 // Maximum number of arguments +#define ARG_LONG_MAX 1000 + +// default file name +#define ARG_DEFAULT_PARAMOUT "fileout.par" +#define ARG_DEFAULT_LOGFILE "gdcm.log" + +#define ARG_LABEL_LOGFILE "LOG" +#define ARG_LABEL_PARAMOUT "paramout" + +#define START_USAGE(usage) const char *usage[] = { +#define FINISH_USAGE 0}; + +//----------------------------------------------------------------------------- +/** + * \brief class designed for command line arguments management + * (to make programmer's live easier) + * NOT Dicom dependant (could be used for any kind + * of 'command line program') + */ + +class GDCM_EXPORT ArgMgr +{ +public: + ArgMgr(int argc, char **argv); + ~ArgMgr(); + + int ArgMgrDefined (const char *param); // Checks if Param is defined + char *ArgMgrValue (const char *param); // Returns Param value + const char *ArgMgrUnused (void); // Returns a never used arg. + int ArgMgrSave (const char *); // Save of parameters out + int ArgMgrUsage (const char **usage); // Display program usage + int ArgMgrPrintUnusedLabels (void); // Prints unused labels + + int ArgMgrGetInt (const char *param, int); // Gets an int (with default value) + float ArgMgrGetFloat (const char *param, float);// Gets a float (with default value) + const char *ArgMgrGetString(const char *param, const char* ext = 0);// Gets a string (with default value) + int ArgMgrGetLabel (const char *param, const char *, int); + + int ArgMgrWantInt (const char *param, const char **usage); // Demands an int + float ArgMgrWantFloat (const char *param, const char **usage); // Demands a float + char *ArgMgrWantString(const char *param, const char **usage); // Demands a string + int ArgMgrWantLabel (const char *param, char *, const char **usage); + + int *ArgMgrGetListOfInt (const char *param, int *); // Gets a list of int + float *ArgMgrGetListOfFloat (const char *param, int *); // Gets a list of float + char **ArgMgrGetListOfString(const char *param, int *); // Gets a list of string + + int *ArgMgrGetIntEnum (const char *param, int *); // Gets a list of int pairs + uint16_t *ArgMgrGetXInt16Enum (const char *param, int *); // Gets a list of int16 pairs + float *ArgMgrGetFloatEnum (const char *param, int *); // Gets a list of float pairs + +private : + + int FiltreLong (const char *); + const char *LoadedParam(const char *, FILE *); + int ArgLoadFromFile (const char *); + void ArgStdArgs (void); + + // These ones are 'general purpose methods' + char *maj (char *); + char *Majuscule (const char *); + + int IdStrCountChar (char *chaine,int caract); + int *IdStrIntEnum (char *value, int *number); + uint16_t *IdStrXInt16Enum (char *value, int *number); + float *IdStrFloatEnum (char *value, int *number); + +// --------------- Attributes ------------------------------ + +private : + + const char *ArgParamOut; // Output File Name for param + + char *ArgUsed; // Used Arguments + char *ArgLab[ARGMAXCOUNT]; // Arguments Labels + char *ArgStr[ARGMAXCOUNT]; // Arguments 'strings' + int ArgCount; // Number of arguments passed + char *Appel; +}; +} // end namespace gdcm + +#endif diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmBase.cxx b/Utilities/ITK/Utilities/gdcm/src/gdcmBase.cxx new file mode 100644 index 0000000000000000000000000000000000000000..fd1059a2795572966d0defcfd1c18852a7dd67c5 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmBase.cxx @@ -0,0 +1,64 @@ + /*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmBase.cxx,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:38 $ + Version: $Revision: 1.3 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#include "gdcmBase.h" + +namespace gdcm +{ +//------------------------------------------------------------------------- +// Constructor / Destructor +/** + * \brief canonical constructor + */ +Base::Base( ) +{ + PrintLevel = 0; +} + +/** + * \brief canonical destructor + * \note If the Header was created by the File constructor, + * it is destroyed by the File + */ +Base::~Base() +{ +} + +//----------------------------------------------------------------------------- +// Public + +//----------------------------------------------------------------------------- +// Protected + +//----------------------------------------------------------------------------- +// Private + +//----------------------------------------------------------------------------- +// Print +/** + * \brief Print all the object + * @param os The output stream to be written to. + * @param indent Indentation string to be prepended during printing + */ +void Base::Print(std::ostream &, std::string const & ) +{ +} + +//----------------------------------------------------------------------------- +} // end namespace gdcm + diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmBase.h b/Utilities/ITK/Utilities/gdcm/src/gdcmBase.h new file mode 100644 index 0000000000000000000000000000000000000000..eb023307f6cb013515df739ee1154661864cd9d4 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmBase.h @@ -0,0 +1,59 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmBase.h,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:38 $ + Version: $Revision: 1.3 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#ifndef GDCMBASE_H +#define GDCMBASE_H + +#include "gdcmCommon.h" +#include <iostream> + +namespace gdcm +{ +//----------------------------------------------------------------------------- +/** + * \brief Base class of all gdcm classes. + * Contains the Print related methods : + * - Print + * - SetPrintLevel / GetPrintLevel + */ +class GDCM_EXPORT Base +{ +public: + Base( ); + virtual ~Base(); + + /// \brief Printer + virtual void Print(std::ostream &os = std::cout, + std::string const & indent = "" ); + + /// \brief Sets the print level for the Dicom Header Elements + /// \note 0 for Light Print; 1 for 'medium' Print, 2 for Heavy Print + void SetPrintLevel(int level) { PrintLevel = level; } + + /// \brief Gets the print level for the Dicom Entries + int GetPrintLevel() { return PrintLevel; } + +protected: + /// \brief Amount of printed details for each Dicom Entries : + /// 0 : stands for the least detail level. + int PrintLevel; +}; +} // end namespace gdcm + +//----------------------------------------------------------------------------- +#endif diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmBinEntry.cxx b/Utilities/ITK/Utilities/gdcm/src/gdcmBinEntry.cxx new file mode 100644 index 0000000000000000000000000000000000000000..85ec8ce57d6605098c858b45ab11dd321168de84 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmBinEntry.cxx @@ -0,0 +1,249 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmBinEntry.cxx,v $ + Language: C++ + Date: $Date: 2006/02/20 15:56:57 $ + Version: $Revision: 1.10 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#include "gdcmBinEntry.h" +#include "gdcmContentEntry.h" +#include "gdcmUtil.h" +#include "gdcmDebug.h" //hidden way to include sstream + +#include <fstream> +#include <iostream> // for std::ios_base, since <ios> does not exist on gcc/Solaris + +namespace gdcm +{ +//----------------------------------------------------------------------------- +// Constructor / Destructor +/** + * \brief Constructor from a given BinEntry + */ +BinEntry::BinEntry(DictEntry *e) + :ContentEntry(e) +{ + BinArea = 0; + SelfArea = true; +} + +/** + * \brief Constructor from a given BinEntry + * @param e Pointer to existing Doc entry + */ +BinEntry::BinEntry(DocEntry *e) + : ContentEntry(e->GetDictEntry()) +{ + Copy(e); + + BinArea = 0; + SelfArea = true; +} + +/** + * \brief Canonical destructor. + */ +BinEntry::~BinEntry() +{ + if (BinArea && SelfArea) + { + delete[] BinArea; + BinArea = 0; // let's be carefull ! + } +} + +//----------------------------------------------------------------------------- +// Public +/** + * \brief canonical Writer + * @param fp already open file pointer + * @param filetype type of the file (ACR, ImplicitVR, ExplicitVR, ...) +*/ +void BinEntry::WriteContent(std::ofstream *fp, FileType filetype) +{ + DocEntry::WriteContent(fp, filetype); + uint8_t *binArea8 = BinArea; //safe notation + size_t lgr = GetLength(); + if (BinArea) // the binArea was *actually* loaded + { + + // The same operation should be done if we wanted + // to write image with Big Endian Transfer Syntax, + // while working on Little Endian Processor + // --> forget Big Endian Transfer Syntax writting! + // Next DICOM version will give it up ... + + // --> + // --> FIXME + // --> + // The stuff looks nice, but it's probably bugged, + // since troubles occur on big endian processors (SunSparc, Motorola) + // while reading the pixels of a + // gdcm-written Little-Endian 16 bits per pixel image + +#if defined(GDCM_WORDS_BIGENDIAN) || defined(GDCM_FORCE_BIGENDIAN_EMULATION) + + /// \todo FIXME : Right now, we only care of Pixels element + /// we should deal with *all* the BinEntries + /// Well, not really since we are not interpreting values read... + + // 8 Bits Pixels *are* OB, 16 Bits Pixels *are* OW + // -value forced while Reading process- + + //--> + // --> + // --> WARNING + // --> the following lines *looked* very clever, + // --> but they don't work on big endian processors. + // --> since I've no access for the moment to a big endian proc :-( + // --> I comment them out, to see the result on the dash board + // --> + + // --> Revert to initial code : TestWriteSimple hangs on Darwin :-( + if (GetGroup() == 0x7fe0 && GetVR() == "OW") + { + uint16_t *binArea16 = (uint16_t*)binArea8; + binary_write (*fp, binArea16, lgr ); + } + else + { + // For any other VR, BinEntry is re-written as-is + binary_write (*fp, binArea8, lgr ); + } + + //--> + // --> + // --> WARNING + // --> remove the following line, an uncomment the previous ones, + // --> if it doesn't work better + // --> + /*binary_write ( *fp, binArea8, lgr ); // Elem value*/ + +#else + binary_write ( *fp, binArea8, lgr ); // Elem value +#endif //GDCM_WORDS_BIGENDIAN + + } + else + { + // nothing was loaded, but we need to skip space on disc + + // --> WARNING : nothing is written; + // --> the initial data (on the the source image) is lost + // --> user is *not* informed ! + + fp->seekp(lgr, std::ios::cur); + } +} + +/** + * \brief Sets the value (non string) of the current Dicom Header Entry + */ +void BinEntry::SetBinArea( uint8_t *area, bool self ) +{ + if (BinArea && SelfArea) + delete[] BinArea; + + BinArea = area; + SelfArea=self; +} + +/** + * \brief Compute the full length of the elementary DataEntry (not only value + * length) depending on the VR. + */ +uint32_t BinEntry::ComputeFullLength() +{ + return GetFullLength(); +} + +//----------------------------------------------------------------------------- +// Protected + +//----------------------------------------------------------------------------- +// Private + +//----------------------------------------------------------------------------- +// Print +/** + * \brief Prints a BinEntry (Dicom entry) + * @param os ostream we want to print in + * @param indent Indentation string to be prepended during printing + */ +void BinEntry::Print(std::ostream &os, std::string const & ) +{ + os << "B "; + DocEntry::Print(os); + itksys_ios::ostringstream s; + void* binArea = GetBinArea(); + if (binArea) + { + if ( GetVR() == "FL" ) + { + int l = GetReadLength()/4 - 1; + float *beg = (float *)GetBinArea(); + s << " [" << *beg; + if ( l!= 0) + for (int i=0;i<l;i++) + { + beg++; + s << "\\" << *beg; + } + s << "]"; + } + else if ( GetVR() == "FD" ) + { + int l = GetReadLength()/8 - 1; + double *beg = (double *)GetBinArea(); + s << " [" << *beg; + if ( l!= 0) + for (int i=0;i<l;i++) + { + beg++; + s << "\\" << *beg; + } + s << "]"; + } + else + { + if ( Util::IsCleanArea( GetBinArea(),GetLength() ) ) + { + std::string cleanString = + Util::CreateCleanString( GetBinArea(),GetLength() ); + s << " [" << cleanString << "]"; + } + else + { + //s << " [" << GetValue() + s << " [" << GDCM_BINLOADED << ";" + << "length = " << GetLength() << "]"; + } + } + } + else + { + if ( GetLength() == 0 ) + { + s << " []"; + } + else + { + s << " [" <<GetValue() << "]"; + } + } + os << s.str(); +} + +//----------------------------------------------------------------------------- +} // end namespace gdcm diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmBinEntry.h b/Utilities/ITK/Utilities/gdcm/src/gdcmBinEntry.h new file mode 100644 index 0000000000000000000000000000000000000000..8fb4cb0ebd435f1853f0703fa21e3a3019da315d --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmBinEntry.h @@ -0,0 +1,73 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmBinEntry.h,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:38 $ + Version: $Revision: 1.4 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#ifndef GDCMBINENTRY_H +#define GDCMBINENTRY_H + +#include "gdcmContentEntry.h" +#include <iostream> + +namespace gdcm +{ + +//----------------------------------------------------------------------------- +/** + * \brief Any Dicom Document (File or DicomDir) contains + * a set of DocEntry - Dicom entries - + * BinEntry is an elementary DocEntry (i.e. a ContentEntry, + * as opposed to SeqEntry) whose content is non std::string + * representable + * BinEntry is a specialisation of ContentEntry + */ + +class GDCM_EXPORT BinEntry : public ContentEntry +{ +public: + BinEntry( DictEntry *e ); + BinEntry( DocEntry *d ); + + ~BinEntry(); + + void Print( std::ostream &os = std::cout, std::string const &indent = "" ); + + void WriteContent( std::ofstream *fp, FileType ft); + + /// \brief Returns the area value of the current Dicom Entry + /// when it's not string-translatable (e.g : LUT table, overlay, icon) + uint8_t *GetBinArea() { return BinArea; } + void SetBinArea( uint8_t *area, bool self = true ); + + uint32_t ComputeFullLength(); + + /// \brief Sets SelfArea + void SetSelfArea(bool area) { SelfArea = area; } + /// \brief Returns SelfArea + bool IsSelfArea() { return SelfArea; } + +private: + /// \brief memory area to hold 'non std::string' representable values + /// (ie : Lookup Tables, overlays, icons) + uint8_t *BinArea; + /// \brief Whether BinEntry has its own BinArea or not + bool SelfArea; +}; + +} // end namespace gdcm +//----------------------------------------------------------------------------- +#endif + diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmCommon.h b/Utilities/ITK/Utilities/gdcm/src/gdcmCommon.h new file mode 100644 index 0000000000000000000000000000000000000000..587fe3cdaa8b38762710c0f308e89d854c54dfab --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmCommon.h @@ -0,0 +1,233 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmCommon.h,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:38 $ + Version: $Revision: 1.23 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#ifndef GDCMCOMMON_H +#define GDCMCOMMON_H + +#include "gdcmConfigure.h" + +//----------------------------------------------------------------------------- +//This is needed when compiling in debug mode +#ifdef _MSC_VER +// 'identifier' : class 'type' needs to have dll-interface to be used by +// clients of class 'type2' +#pragma warning ( disable : 4251 ) +// non dll-interface class 'type' used as base for dll-interface class 'type2' +#pragma warning ( disable : 4275 ) +// 'identifier' : identifier was truncated to 'number' characters in the +// debug information +#pragma warning ( disable : 4786 ) +//'identifier' : decorated name length exceeded, name was truncated +#pragma warning ( disable : 4503 ) +// C++ exception specification ignored except to indicate a +// function is not __declspec(nothrow) +#pragma warning ( disable : 4290 ) +// signed/unsigned mismatch +#pragma warning ( disable : 4018 ) +// return type for 'identifier' is '' (ie; not a UDT or reference to UDT. Will +// produce errors if applied using infix notation +#pragma warning ( disable : 4284 ) +// 'type' : forcing value to bool 'true' or 'false' (performance warning) +// //#pragma warning ( disable : 4800 ) +#endif //_MSC_VER + +//----------------------------------------------------------------------------- +#ifdef CMAKE_HAVE_STDINT_H + #include <stdint.h> +#else +#ifdef CMAKE_HAVE_INTTYPES_H + // Old system only have this + #include <inttypes.h> // For uint8_t uint16_t and uint32_t +#else +// Broken plateforms do not respect C99 and do not provide those typedef +// Special case for recent Borland compiler, comes with stdint.h +#if defined(_MSC_VER) || defined(__BORLANDC__) && (__BORLANDC__ < 0x0560) \ + || defined(__MINGW32__) +typedef signed char int8_t; +typedef signed short int16_t; +typedef signed int int32_t; +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +#else +#error "Sorry your plateform is not supported" +#endif // defined(_MSC_VER) || defined(__BORLANDC__) && (__BORLANDC__ < 0x0560) || defined(__MINGW32__) +#endif // CMAKE_HAVE_INTTYPES_H +#endif // CMAKE_HAVE_STDINT_H + +// Basically for VS6 and bcc 5.5.1: +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#if defined(_WIN32) && defined(BUILD_SHARED_LIBS) + #ifdef gdcm_EXPORTS + #define GDCM_EXPORT __declspec( dllexport ) + #else + #define GDCM_EXPORT __declspec( dllimport ) + #endif +#else + #define GDCM_EXPORT +#endif + +#include <string> +#define FASTTAGKEY 0 + +// FIXME: Should rewrite this: +#if FASTTAGKEY +#include <iostream> +#include <iomanip> +#endif +#if defined(_MSC_VER) && (_MSC_VER == 1200) +/* ostream operator for std::string since VS6 does not provide it*/ +#include <iostream> +#endif + + +//----------------------------------------------------------------------------- +/// \brief namespace for Grass root DiCoM +namespace gdcm +{ + +// Centralize information about the gdcm dictionary in only one file: +#ifndef PUB_DICT_PATH +# define PUB_DICT_PATH "../Dicts/" +#endif +#define PUB_DICT_NAME "DicomV3Dict" +#define PUB_DICT_FILENAME "gdcm.dic" +#define DICT_ELEM "DicomDir.dic" +#define DICT_TS "dicomTS.dic" +#define DICT_VR "dicomVR.dic" +#define DICT_GROUP_NAME "DictGroupName.dic" + +GDCM_EXPORT extern const std::string GDCM_UNKNOWN; +GDCM_EXPORT extern const std::string GDCM_UNFOUND; +GDCM_EXPORT extern const std::string GDCM_BINLOADED; +GDCM_EXPORT extern const std::string GDCM_NOTLOADED; +GDCM_EXPORT extern const std::string GDCM_UNREAD; +GDCM_EXPORT extern const std::string GDCM_NOTASCII; +GDCM_EXPORT extern const std::string GDCM_PIXELDATA; +/// \brief TagKey is made to hold the standard Dicom Tag +/// (Group number, Element number) +/// Instead of using the two '16 bits integers' as the Hask Table key, we +/// converted into a string (e.g. 0x0018,0x0050 converted into "0018|0050") +/// It appears to be a huge waste of time. +/// We'll fix the mess up -without any change in the API- as soon as the bench +/// marks are fully performed. + +#if FASTTAGKEY +typedef union { + uint16_t tab[2]; + uint32_t tagkey; + } TagKey; +/* ostream operator for TagKey */ +inline std::ostream& operator<<(std::ostream& _O, TagKey _val) +{ + _O.setf( std::ios::right); + return (_O << std::hex << std::setw( 4 ) << std::setfill( '0' ) + << _val.tab[0] << '|' << std::setw( 4 ) << std::setfill( '0' ) + << _val.tab[1] << std::setfill( ' ' ) << std::dec); +} +inline bool operator==(TagKey _self, TagKey _val) +{ + return _self.tagkey == _val.tagkey; +} +inline bool operator<(TagKey _self, TagKey _val) +{ + // This expression is a tad faster but PrintFile output + // is more difficult to read + //return _self.tagkey < _val.tagkey; + + // More usal order of dicom tags: + if( _self.tab[0] == _val.tab[0] ) + return _self.tab[1] < _val.tab[1]; + return _self.tab[0] < _val.tab[0]; +} +#else +typedef std::string TagKey; +#endif +#if defined(_MSC_VER) && (_MSC_VER == 1200) +// Doing everything within gdcm namespace to avoid polluting 3d party software +inline std::ostream& operator<<(std::ostream& _O, std::string _val) +{ + return _O << _val.c_str(); +} +#endif + +/// \brief TagName is made to hold the 'non hexa" fields (VR, VM, Name) +/// of Dicom Entries +typedef std::string TagName; + +/// \brief various types of a DICOM file (for internal use only) +enum FileType { + Unknown = 0, + ExplicitVR, // DicomDir is in this case. Except when it's ImplicitVR !... + ImplicitVR, + ACR, + ACR_LIBIDO, + JPEG +}; + +/// \brief type of the elements composing a DICOMDIR (for internal use only) +enum DicomDirType { + DD_UNKNOWN = 0, + DD_META, + DD_PATIENT, + DD_STUDY, + DD_SERIE, + DD_IMAGE, + DD_VISIT +}; + +/// \brief comparison operators (as used in SerieHelper::AddRestriction() ) +enum CompOperators { + GDCM_EQUAL = 0, + GDCM_DIFFERENT, + GDCM_GREATER, + GDCM_GREATEROREQUAL, + GDCM_LESS, + GDCM_LESSOREQUAL +}; + +/// \brief Loading mode +enum LodModeType +{ + LD_ALL = 0x00000000, // Load all + LD_NOSEQ = 0x00000001, // Don't load Sequences + LD_NOSHADOW = 0x00000002, // Don't load odd groups + LD_NOSHADOWSEQ = 0x00000004 // Don't load Sequences if they belong + // to an odd group + // (*exclusive* from LD_NOSEQ and LD_NOSHADOW) +}; + +/** + * \brief structure, for internal use only + */ +struct Element +{ + /// Dicom Group number + unsigned short int Group; + /// Dicom Element number + unsigned short int Elem; + /// value (coded as a std::string) of the Element + std::string Value; +}; + +} //namespace gdcm +//----------------------------------------------------------------------------- +#endif diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmContentEntry.cxx b/Utilities/ITK/Utilities/gdcm/src/gdcmContentEntry.cxx new file mode 100644 index 0000000000000000000000000000000000000000..e9bbe1ff36c91a00aac6bb7a5d14f11facb89a60 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmContentEntry.cxx @@ -0,0 +1,82 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmContentEntry.cxx,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:38 $ + Version: $Revision: 1.3 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#include "gdcmContentEntry.h" +#include "gdcmVR.h" +#include "gdcmTS.h" +#include "gdcmGlobal.h" +#include "gdcmUtil.h" +#include "gdcmDebug.h" + +#include <fstream> + +namespace gdcm +{ + +//----------------------------------------------------------------------------- +// Constructor / Destructor +/** + * \brief Constructor for a given DictEntry + * @param e Pointer to existing dictionary entry + */ +ContentEntry::ContentEntry(DictEntry *e) + : DocEntry(e) +{ + Value = GDCM_UNFOUND; +} + +/** + * \brief Constructor for a given DocEntry + * @param e Pointer to existing Doc entry + */ +ContentEntry::ContentEntry(DocEntry *e) + : DocEntry(e->GetDictEntry()) +{ + Copy(e); +} + +/** + * \brief Canonical destructor. + */ +ContentEntry::~ContentEntry () +{ +} + +//----------------------------------------------------------------------------- +// Print + +//----------------------------------------------------------------------------- +// Public +void ContentEntry::Copy(DocEntry *doc) +{ + DocEntry::Copy(doc); + + ContentEntry *entry = dynamic_cast<ContentEntry *>(doc); + if ( entry ) + Value = entry->Value; +} + +//----------------------------------------------------------------------------- +// Protected + +//----------------------------------------------------------------------------- +// Private + +//----------------------------------------------------------------------------- +} // end namespace gdcm + diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmContentEntry.h b/Utilities/ITK/Utilities/gdcm/src/gdcmContentEntry.h new file mode 100644 index 0000000000000000000000000000000000000000..ddf07b236d3613ce5cefa3b7743ce436e124bc64 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmContentEntry.h @@ -0,0 +1,70 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmContentEntry.h,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:38 $ + Version: $Revision: 1.3 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#ifndef GDCMCONTENTENTRY_H +#define GDCMCONTENTENTRY_H + +#include "gdcmDocEntry.h" + +#include <iostream> + +namespace gdcm +{ +//----------------------------------------------------------------------------- +/** + * \brief Any Dicom Document (File or DicomDir) contains + * a set of DocEntry - Dicom entries - + * (when successfuly parsed against a given Dicom dictionary) + * ContentEntry is an elementary DocEntry (as opposed to SeqEntry). + * Depending on the type of its content, + * ContentEntry is specialized as a ValEntry or a BinEntry + */ +class GDCM_EXPORT ContentEntry : public DocEntry +{ +public: + virtual void WriteContent(std::ofstream *fp, FileType filetype) = 0; + + /// Sets the value (string) of the current Dicom entry + virtual void SetValue(std::string const &val) { Value = val; } + /// \brief Returns the 'Value' (e.g. "Dupond^Marcel") converted + /// into a 'string', event if it's physically stored on disk as an integer + /// (e.g. : 0x000c returned as "12") + std::string const &GetValue() const { return Value; } + + void Copy(DocEntry *doc); + +protected: + // Contructors are protected, not to be invoked by end user. + ContentEntry(DictEntry *e); + ContentEntry(DocEntry *d); + // Destructor is protected, not to be invoked by end user. + ~ContentEntry(); + +private: +// Members : + /// \brief Dicom entry value, internaly represented as a std::string. + /// The Value Representation (\ref VR) is independently used + /// in order to interpret (decode) this field. + std::string Value; +}; + +} // end namespace gdcm + +//----------------------------------------------------------------------------- +#endif + diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmDebug.cxx b/Utilities/ITK/Utilities/gdcm/src/gdcmDebug.cxx new file mode 100644 index 0000000000000000000000000000000000000000..40469262501db614cff098817606edefd19771f0 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmDebug.cxx @@ -0,0 +1,115 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmDebug.cxx,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:38 $ + Version: $Revision: 1.5 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#include "gdcmDebug.h" +#include <iostream> + +namespace gdcm +{ +//----------------------------------------------------------------------------- +// Warning message level to be displayed +static bool DebugFlag = false; +static bool DebugToFile = false; +static std::ofstream DebugFile; + +//----------------------------------------------------------------------------- +// Constructor / Destructor +Debug::Debug() +{ +} + +Debug::~Debug() +{ + if ( DebugFile.is_open() ) + DebugFile.close(); +} + +//----------------------------------------------------------------------------- +// Public +/** + * \brief Sets the debug flag + * @param flag Set the debug flag + */ +void Debug::SetDebugFlag (bool flag) +{ + DebugFlag = flag; +} + +/** + * \brief Gets the debug flag value + * @return debug flag value + */ +bool Debug::GetDebugFlag () +{ + return DebugFlag; +} + +/** + * \brief Accessor + * @param flag whether we want to redirect to file + */ +void Debug::SetDebugToFile (bool flag) +{ + DebugToFile = flag; +} + +/** + * \brief Accessor to know whether debug info are redirected to file + */ +bool Debug::GetDebugToFile () +{ + return DebugToFile; +} + +/** + * \brief Set the filename the debug stream should be redirect to + * Settting a filename also sets DebugToFile to true + * @param filename File to redirect debug info + * Absolutely nothing is check. You have to pass in + * a correct filename + */ +void Debug::SetDebugFilename (std::string const &filename) +{ + DebugToFile = true; // Just in case ... + DebugFlag = true; // Just in case ... + if ( DebugFile.is_open() ) + DebugFile.close(); + DebugFile.open( filename.c_str() ); +} + +/** + * \brief Internal use only. Allow us to retrieve the static from anywhere + * in gdcm code + * @return Debug file + */ +std::ofstream &Debug::GetDebugFile () +{ + return DebugFile; +} + +//----------------------------------------------------------------------------- +// Protected + +//----------------------------------------------------------------------------- +// Private + +//----------------------------------------------------------------------------- +// Print + +//----------------------------------------------------------------------------- +} // end namespace gdcm diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmDebug.h b/Utilities/ITK/Utilities/gdcm/src/gdcmDebug.h new file mode 100644 index 0000000000000000000000000000000000000000..db5c38da90b1413e4c8583b9cb02951f7df2f000 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmDebug.h @@ -0,0 +1,251 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmDebug.h,v $ + Language: C++ + Date: $Date: 2006/02/20 15:56:57 $ + Version: $Revision: 1.8 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#ifndef GDCMDEBUG_H +#define GDCMDEBUG_H + +#include "gdcmCommon.h" + +#include <itksys/ios/sstream> +#include <fstream> +#include <assert.h> +#include <errno.h> + +namespace gdcm +{ +//----------------------------------------------------------------------------- + +/** + * \brief Debug is an object for debugging in program. + * It has 2 debugging modes : + * - error : for bad library use, seriously wrong DICOM + * - debug : for information/debug messages + * - warning : for warning about DICOM quality (kosher) + * - assert : design by contract implementation. A function should have + * proper input and proper output. + * (should not happen, not user controlled) + * + * A debugging message is only shown if the flag is on (DebugFlag) + * This is static var and can be set at beginning of code: + * gdcm::Debug::SetDebugOn(); + */ +class GDCM_EXPORT Debug +{ +public: + Debug(); + ~Debug(); + + /// \brief This is a global flag that controls whether any debug, warning + /// messages are displayed. + static void SetDebugFlag (bool flag); + static bool GetDebugFlag (); + /// \brief Sets the Debug Flag to true + static void DebugOn () { SetDebugFlag(true); } + /// \brief Sets the Debug Flag to false + static void DebugOff () { SetDebugFlag(false); } + + /// \brief This is a global flag that controls if debug are redirected + /// to a file or not + static void SetDebugToFile (bool flag); + static bool GetDebugToFile (); + /// \brief Next debug messages will be sent in the debug file + static void DebugToFileOn () { SetDebugToFile(true); } + /// \brief Next debug messages will be sent in the standard output + static void DebugToFileOff () { SetDebugToFile(false); } + + static void SetDebugFilename (std::string const &filename); + + static std::ofstream &GetDebugFile (); +}; + +} // end namespace gdcm + +// Here we define function this is the only way to be able to pass +// stuff with indirection like: +// gdcmDebug( "my message:" << i << '\t' ); +// You cannot use function unless you use vnsprintf ... + +// __FUNCTION is not always defined by preprocessor +// In c++ we should use __PRETTY_FUNCTION__ instead... +#ifdef GDCM_COMPILER_HAS_FUNCTION +// Handle particular case for GNU C++ which also defines __PRETTY_FUNCTION__ +// which is a lot nice in C++ +#ifdef __BORLANDC__ +# define __FUNCTION__ __FUNC__ +#endif +#ifdef __GNUC__ +# define GDCM_FUNCTION __PRETTY_FUNCTION__ +#else +# define GDCM_FUNCTION __FUNCTION__ +#endif //__GNUC__ +#else +# define GDCM_FUNCTION "<unknow>" +#endif //GDCM_COMPILER_HAS_FUNCTION + +/** + * \brief Debug + * @param msg message part + */ +#ifdef NDEBUG +#define gdcmDebugMacro(msg) {} +#else +#define gdcmDebugMacro(msg) \ +{ \ + if( Debug::GetDebugFlag() ) \ + { \ + itksys_ios::ostringstream osmacro; \ + osmacro << "Debug: In " __FILE__ ", line " << __LINE__ \ + << ", function " << GDCM_FUNCTION << '\n' \ + << "Last system error was: " << strerror(errno) \ + << '\n' << msg << "\n\n"; \ + if( Debug::GetDebugToFile() ) \ + Debug::GetDebugFile() << osmacro.str() << std::endl; \ + else \ + std::cerr << osmacro.str() << std::endl; \ + } \ +} +#endif //NDEBUG + +/** + * \brief Warning + * @param msg message part + */ +#ifdef NDEBUG +#define gdcmWarningMacro(msg) {} +#else +#define gdcmWarningMacro(msg) \ +{ \ + if( Debug::GetDebugFlag() ) \ + { \ + itksys_ios::ostringstream osmacro; \ + osmacro << "Warning: In " __FILE__ ", line " << __LINE__ \ + << ", function " << GDCM_FUNCTION << "\n" \ + << msg << "\n\n"; \ + if( Debug::GetDebugToFile() ) \ + Debug::GetDebugFile() << osmacro.str() << std::endl; \ + else \ + std::cerr << osmacro.str() << std::endl; \ + } \ +} +#endif //NDEBUG + +/** + * \brief Error + * @param msg second message part + */ +#ifdef NDEBUG +#define gdcmErrorMacro(msg) {} +#else +#define gdcmErrorMacro(msg) \ +{ \ + itksys_ios::ostringstream osmacro; \ + osmacro << "Error: In " __FILE__ ", line " << __LINE__ \ + << ", function " << GDCM_FUNCTION << '\n' \ + << msg << "\n\n"; \ + if( Debug::GetDebugToFile() ) \ + Debug::GetDebugFile() << osmacro.str() << std::endl; \ + else \ + std::cerr << osmacro.str() << std::endl; \ +} +#endif //NDEBUG + +/** + * \brief Assert + * @param arg argument to test + * An easy solution to pass also a message is to do: + * gdcmAssertMacro( "my message" && 2 < 3 ) + */ +#ifdef NDEBUG +#define gdcmAssertMacro(arg) {} +#else +#define gdcmAssertMacro(arg) \ +{ \ + if( !(arg) ) \ + { \ + itksys_ios::ostringstream osmacro; \ + osmacro << "Assert: In " __FILE__ ", line " << __LINE__ \ + << ", function " << GDCM_FUNCTION \ + << "\n\n"; \ + if( Debug::GetDebugToFile() ) \ + Debug::GetDebugFile() << osmacro.str() << std::endl; \ + else \ + std::cerr << osmacro.str() << std::endl; \ + assert ( arg ); \ + } \ +} +#endif //NDEBUG + +//----------------------------------------------------------------------------- +// +// Define GDCM_LEGACY macro to mark legacy methods where they are +// declared in their class. +// +// WARNING : Don't try to use it with 'inline' methods ! +// +//Example usage: +// +// // @deprecated Replaced by MyOtherMethod() as of gdcm 2.0. +// GDCM_LEGACY(void MyMethod()); +#if defined(GDCM_LEGACY_REMOVE) + // Remove legacy methods completely. +# define GDCM_LEGACY(method) +#elif defined(GDCM_LEGACY_SILENT) || defined(SWIG) + // Provide legacy methods with no warnings. +# define GDCM_LEGACY(method) method +#else + // Setup compile-time warnings for uses of deprecated methods if + // possible on this compiler. +# if defined(__GNUC__) && !defined(__INTEL_COMPILER) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) +#if defined(__APPLE__) && (__GNUC__ == 3) && (__GNUC_MINOR__ == 3) +// Seems like there is a bug in APPLE gcc for deprecated attribute and ctor +// This is fixed in g++ 4.0 (Tiger) +# define GDCM_LEGACY(method) method +#else +# define GDCM_LEGACY(method) method __attribute__((deprecated)) +#endif +# elif defined(_MSC_VER) && _MSC_VER >= 1300 +# define GDCM_LEGACY(method) __declspec(deprecated) method +# else +# define GDCM_LEGACY(method) method +# endif +#endif + +// Macros to create runtime deprecation warning messages in function +// bodies. Example usage: +// +// void MyClass::MyOldMethod() +// { +// GDCM_LEGACY_BODY(MyClass::MyOldMethod, 2.0); +// } +// +// void MyClass::MyMethod() +// { +// GDCM_LEGACY_REPLACED_BODY(MyClass::MyMethod, 5.0, +// MyClass::MyOtherMethod); +// } +#if defined(GDCM_LEGACY_REMOVE) || defined(GDCM_LEGACY_SILENT) +# define GDCM_LEGACY_BODY(method, version) +# define GDCM_LEGACY_REPLACED_BODY(method, version, replace) +#else +# define GDCM_LEGACY_BODY(method, version) \ + gdcmWarningMacro(#method " was deprecated for gdcm" #version " and will be removed in a future version.") +# define GDCM_LEGACY_REPLACED_BODY(method, version, replace) \ + gdcmWarningMacro(#method " was deprecated for gdcm" #version " and will be removed in a future version. Use " #replace " instead.") +#endif + +#endif diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmDefaultDicts.cxx.in b/Utilities/ITK/Utilities/gdcm/src/gdcmDefaultDicts.cxx.in new file mode 100644 index 0000000000000000000000000000000000000000..417dfcb8033788450cfcf9af6bbab4dbb1231846 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmDefaultDicts.cxx.in @@ -0,0 +1,119 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmDefaultDicts.cxx.in,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:38 $ + Version: $Revision: 1.6 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#ifndef GDCMDEFAULTDICTS_H +#define GDCMDEFAULTDICTS_H + +#include "gdcmDict.h" +#include "gdcmDictEntry.h" +#include "gdcmTS.h" +#include "gdcmVR.h" +#include "gdcmDictGroupName.h" +#include "gdcmDicomDirElement.h" + +namespace gdcm +{ + +typedef struct +{ + uint16_t group; + uint16_t element; + const char *vr; + const char *vm; + const char *name; +} DICT_ENTRY; + +static DICT_ENTRY datadir[] = { +@DICOM_DATA_DICTIONARY@ +}; + +void FillDefaultDataDict(Dict *d) +{ + unsigned int i = 0; + DICT_ENTRY n = datadir[i]; + while( n.name != 0 ) + { + const DictEntry e( n.group, n.element, n.vr, n.vm, n.name); + d->AddEntry( e ); + n = datadir[++i]; + } +} + +void FillDefaultTSDict(TSHT &ts) +{ +@DICOM_TS_DICTIONARY@ +} + +void FillDefaultVRDict(VRHT &vr) +{ +@DICOM_VR_DICTIONARY@ +} + +void FillDefaultDictGroupName(DictGroupNameHT &groupName) +{ +@DICT_GROUP_NAME_DICTIONARY@ +} + +typedef struct +{ + const char *type; + unsigned short group; + unsigned short element; + const char *value; +} ELEMENT; + +static ELEMENT dataElement[] = { +@DICOM_DIR_DICTIONARY@ +}; + +void FillDefaultDIRDict(DicomDirElement *dde) +{ + unsigned int i = 0; + ELEMENT e = dataElement[i]; + Element elem; + DicomDirType type; + std::string strType; + + while( e.type != 0 ) + { + // Force to use the string comparision operator == + strType = e.type; + if( strType == "metaElem" ) + type = DD_META; + else if( strType == "patientElem" ) + type = DD_PATIENT; + else if( strType == "studyElem" ) + type = DD_STUDY; + else if( strType == "serieElem" ) + type = DD_SERIE; + else if( strType == "imageElem" ) + type = DD_IMAGE; + else + type = DD_UNKNOWN; + + elem.Group = e.group; + elem.Elem = e.element; + elem.Value = e.value; + dde->AddEntry( type, elem); + e = dataElement[++i]; + } +} + +} //end gdcm namespace +#endif + diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmDicomDir.cxx b/Utilities/ITK/Utilities/gdcm/src/gdcmDicomDir.cxx new file mode 100644 index 0000000000000000000000000000000000000000..f57cc05201d2baed51503af5db077c3ffdb3f344 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmDicomDir.cxx @@ -0,0 +1,1228 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmDicomDir.cxx,v $ + Language: C++ + Date: $Date: 2006/02/20 15:56:57 $ + Version: $Revision: 1.12 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +//----------------------------------------------------------------------------- +// For full DICOMDIR description, see: +// PS 3.3-2003, pages 731-750 +//----------------------------------------------------------------------------- +#include "gdcmDicomDir.h" +#include "gdcmDicomDirObject.h" +#include "gdcmDicomDirStudy.h" +#include "gdcmDicomDirSerie.h" +#include "gdcmDicomDirVisit.h" +#include "gdcmDicomDirImage.h" +#include "gdcmDicomDirPatient.h" +#include "gdcmDicomDirMeta.h" +#include "gdcmDicomDirElement.h" +#include "gdcmDirList.h" +#include "gdcmUtil.h" +#include "gdcmDebug.h" +#include "gdcmGlobal.h" +#include "gdcmFile.h" +#include "gdcmSeqEntry.h" +#include "gdcmSQItem.h" +#include "gdcmValEntry.h" + +#include <fstream> +#include <string> +#include <algorithm> +#include <sys/types.h> + +#ifdef _MSC_VER +# define getcwd _getcwd +#endif + +#if defined(_MSC_VER) || defined(__BORLANDC__) +# include <direct.h> +#else +# include <unistd.h> +#endif + +#if defined(__BORLANDC__) + #include <mem.h> // for memset +#endif + +// ---------------------------------------------------------------------------- +// Note for future developpers +// ---------------------------------------------------------------------------- +// +// Dicom PS 3.3 describes the relationship between Directory Records, as follow +// (see also PS 4.3, 2004, page 50 for Entity-Relationship model) +// +// Directory Record Type Directory Record Types which may be included +// in the next lower-level directory Entity +// +// (Root directory Entity) PATIENT, TOPIC, PRIVATE +// +// PATIENT STUDY, PRIVATE +// +// STUDY SERIES, VISIT, RESULTS, STUDY COMPONENT, PRIVATE +// +// SERIES IMAGE, OVERLAYS, MODALITY LUT, VOI LUT, +// CURVE, STORED PRINT, RT DOSE, RT STRUCTURE SET +// RT PLAN, RT TREAT RECORD, PRESENTATION, WAVEFORM, +// SR DOCUMENT, KEY OBJECT DOC, SPECTROSCOPY, +// RAW DATA, REGISTRATION, FIDUCIAL, PRIVATE, +// ENCAP DOC +// IMAGE +// OVERLAY +// MODALITY LUT +// VOI LUT +// CURVE +// STORED PRINT +// RT DOSE +// RT STRUCTURE SET +// RT PLAN +// RT TREAT RECORD +// PRESENTATION +// WAVEFORM +// SR DOCUMENT +// KEY OBJECT DOC +// SPECTROSCOPY +// RAW DATA +// REGISTRATION +// FIDUCIAL +// PRIVATE +// ENCAP DOC +// +// ---------------------- +// The current gdcm version only deals with : +// +// (Root directory Entity) PATIENT +// PATIENT STUDY +// STUDY SERIES +// STUDY VISIT +// SERIES IMAGE +// IMAGE / +// +// DicomDir::CreateDicomDir will have to be completed +// Treelike structure management will have to be upgraded +// ---------------------------------------------------------------------------- + +namespace gdcm +{ +//----------------------------------------------------------------------------- +// Constructor / Destructor +/** + * \brief Constructor : creates an empty DicomDir + */ +DicomDir::DicomDir() + :Document( ) +{ + Initialize(); // sets all private fields to NULL + ParseDir = false; + NewMeta(); +} + +#ifndef GDCM_LEGACY_REMOVE +/** + * \brief Constructor Parses recursively the directory and creates the DicomDir + * or uses an already built DICOMDIR, depending on 'parseDir' value. + * @param fileName name + * - of the root directory (parseDir = true) + * - of the DICOMDIR (parseDir = false) + * @param parseDir boolean + * - true if user passed an entry point + * and wants to explore recursively the directories + * - false if user passed an already built DICOMDIR file + * and wants to use it + * @deprecated use : new DicomDir() + [ SetLoadMode(lm) + ] SetDirectoryName(name) + * or : new DicomDir() + SetFileName(name) + */ +DicomDir::DicomDir(std::string const &fileName, bool parseDir ): + Document( ) +{ + // At this step, Document constructor is already executed, + // whatever user passed (either a root directory or a DICOMDIR) + // and whatever the value of parseDir was. + // (nothing is cheked in Document constructor, to avoid overhead) + + ParseDir = parseDir; + SetLoadMode (LD_ALL); // concerns only dicom files + SetFileName( fileName ); + Load( ); +} +#endif + +/** + * \brief Canonical destructor + */ +DicomDir::~DicomDir() +{ + SetStartMethod(NULL,NULL,NULL); + SetProgressMethod(NULL,NULL,NULL); + SetEndMethod(NULL,NULL,NULL); + + ClearPatient(); + if ( MetaElems ) + { + delete MetaElems; + } +} + +//----------------------------------------------------------------------------- +// Public + +/** + * \brief Loader. use SetFileName(fn) + * or SetLoadMode(lm) + SetDirectoryName(dn) before ! + * @return false if file cannot be open or no swap info was found, + * or no tag was found. + */ +bool DicomDir::Load( ) +{ + // We should clean out anything that already exists. + Initialize(); // sets all private fields to NULL + + if (!ParseDir) + { + if ( ! this->Document::Load( ) ) + return false; + } + return DoTheLoadingJob( ); +} + +#ifndef GDCM_LEGACY_REMOVE +/** + * \brief Loader. (DEPRECATED : kept not to break the API) + * @param fileName file to be open for parsing + * @return false if file cannot be open or no swap info was found, + * or no tag was found. + * @deprecated use SetFileName(n) + Load() instead + */ +bool DicomDir::Load(std::string const &fileName ) +{ + // We should clean out anything that already exists. + Initialize(); // sets all private fields to NULL + + SetFileName( fileName ); + if (!ParseDir) + { + if ( ! this->Document::Load( ) ) + return false; + } + return DoTheLoadingJob( ); +} + +/// DEPRECATED : use SetDirectoryName(dname) instead +/** + * \brief Loader. (DEPRECATED : kept not to break the API) + * @param paseDir Parse Dir + * @deprecated use SetDirectoryName(dname) instead + */ +void DicomDir::SetParseDir(bool parseDir) +{ + ParseDir = parseDir; +} +#endif + +/** + * \brief Does the Loading Job (internal use only) + * @return false if file cannot be open or no swap info was found, + * or no tag was found. + */ +bool DicomDir::DoTheLoadingJob( ) +{ + // We should clean out anything that already exists. + Initialize(); // sets all private fields to NULL + + if (!ParseDir) + { + // Only if user passed a DICOMDIR + // ------------------------------ + Fp = 0; + if ( !OpenFile() ) + { + return false; + } + if (!Document::Load() ) + { + return false; + } + + if ( GetFirstEntry() == 0 ) // when user passed a Directory to parse + { + gdcmWarningMacro( "Entry HT empty for file: "<< GetFileName()); + return false; + } + // Directory record sequence + DocEntry *e = GetDocEntry(0x0004, 0x1220); + if ( !e ) + { + gdcmWarningMacro( "NO 'Directory record sequence' (0x0004,0x1220)" + << " in file " << GetFileName()); + return false; + } + else + CreateDicomDir(); + } + else + { + // Only if user passed a root directory + // ------------------------------------ + if ( GetFileName() == "." ) + { + // user passed '.' as Name + // we get current directory name + char buf[2048]; + const char *cwd = getcwd(buf, 2048); + if( cwd ) + { + SetFileName( buf ); // will be converted into a string + } + else + { + gdcmErrorMacro( "Path was too long to fit on 2048 bytes" ); + } + } + NewMeta(); + gdcmDebugMacro( "Parse directory and create the DicomDir : " + << GetFileName() ); + ParseDirectory(); + } + return true; +} + +/** + * \brief This predicate, based on hopefully reasonable heuristics, + * decides whether or not the current document was properly parsed + * and contains the mandatory information for being considered as + * a well formed and usable DicomDir. + * @return true when Document is the one of a reasonable DicomDir, + * false otherwise. + */ +bool DicomDir::IsReadable() +{ + if ( Filetype == Unknown ) + { + gdcmErrorMacro( "Wrong filetype for " << GetFileName()); + return false; + } + if ( !MetaElems ) + { + gdcmWarningMacro( "Meta Elements missing in DicomDir"); + return false; + } + if ( Patients.size() <= 0 ) + { + gdcmWarningMacro( "NO Patient in DicomDir"); + return false; + } + + return true; +} + +/** + * \brief adds *the* Meta to a partially created DICOMDIR + */ +DicomDirMeta *DicomDir::NewMeta() +{ + if ( MetaElems ) + delete MetaElems; + + DocEntry *entry = GetFirstEntry(); + if ( entry ) + { + MetaElems = new DicomDirMeta(true); // true = empty + + entry = GetFirstEntry(); + while( entry ) + { + if ( dynamic_cast<SeqEntry *>(entry) ) + break; + + RemoveEntryNoDestroy(entry); + MetaElems->AddEntry(entry); + + entry = GetFirstEntry(); + } + } + else // after root directory parsing + { + MetaElems = new DicomDirMeta(false); // false = not empty + } + MetaElems->SetSQItemNumber(0); // To avoid further missprinting + return MetaElems; +} + +/** + * \brief adds a new Patient (with the basic elements) to a partially created + * DICOMDIR + */ +DicomDirPatient *DicomDir::NewPatient() +{ + DicomDirPatient *p = new DicomDirPatient(); + AddPatientToEnd( p ); + return p; +} + +/** + * \brief Remove all Patients + */ +void DicomDir::ClearPatient() +{ + for(ListDicomDirPatient::iterator cc = Patients.begin(); + cc!= Patients.end(); + ++cc) + { + delete *cc; + } + Patients.clear(); +} + +/** + * \brief Get the first entry while visiting the DicomDirPatients + * \return The first DicomDirPatient if found, otherwhise NULL + */ +DicomDirPatient *DicomDir::GetFirstPatient() +{ + ItPatient = Patients.begin(); + if ( ItPatient != Patients.end() ) + return *ItPatient; + return NULL; +} + +/** + * \brief Get the next entry while visiting the DicomDirPatients + * \note : meaningfull only if GetFirstEntry already called + * \return The next DicomDirPatient if found, otherwhise NULL + */ +DicomDirPatient *DicomDir::GetNextPatient() +{ + gdcmAssertMacro (ItPatient != Patients.end()); + + ++ItPatient; + if ( ItPatient != Patients.end() ) + return *ItPatient; + return NULL; +} + +/** + * \brief fills the whole structure, starting from a root Directory + */ +void DicomDir::ParseDirectory() +{ + CreateDicomDirChainedList( GetFileName() ); + CreateDicomDir(); +} + +void DicomDir::SetStartMethod( DicomDir::Method *method, void *arg ) +{ + SetStartMethod(method,arg,NULL); +} + +void DicomDir::SetProgressMethod( DicomDir::Method *method, void *arg ) +{ + SetProgressMethod(method,arg,NULL); +} + +void DicomDir::SetEndMethod( DicomDir::Method *method, void *arg ) +{ + SetEndMethod(method,arg,NULL); +} + +/** + * \brief Set the start method to call when the parsing of the + * directory starts. + * @param method Method to call + * @param arg Argument to pass to the method + * @param argDelete Argument + * \warning In python : the arg parameter isn't considered + */ +void DicomDir::SetStartMethod( DicomDir::Method *method, void *arg, + DicomDir::Method *argDelete ) +{ + if ( StartArg && StartMethodArgDelete ) + { + StartMethodArgDelete( StartArg ); + } + + StartMethod = method; + StartArg = arg; + StartMethodArgDelete = argDelete; +} + + +/** + * \brief Set the progress method to call when the parsing of the + * directory progress + * @param method Method to call + * @param arg Argument to pass to the method + * @param argDelete Argument + * \warning In python : the arg parameter isn't considered + */ +void DicomDir::SetProgressMethod( DicomDir::Method *method, void *arg, + DicomDir::Method *argDelete ) +{ + if ( ProgressArg && ProgressMethodArgDelete ) + { + ProgressMethodArgDelete( ProgressArg ); + } + + ProgressMethod = method; + ProgressArg = arg; + ProgressMethodArgDelete = argDelete; +} + +/** + * \brief Set the end method to call when the parsing of the directory ends + * @param method Method to call + * @param arg Argument to pass to the method + * @param argDelete Argument + * \warning In python : the arg parameter isn't considered + */ +void DicomDir::SetEndMethod( DicomDir::Method *method, void *arg, + DicomDir::Method *argDelete ) +{ + if ( EndArg && EndMethodArgDelete ) + { + EndMethodArgDelete( EndArg ); + } + + EndMethod = method; + EndArg = arg; + EndMethodArgDelete = argDelete; +} + +/** + * \brief Set the method to delete the argument + * The argument is destroyed when the method is changed or when the + * class is destroyed + * @param method Method to call to delete the argument + */ +void DicomDir::SetStartMethodArgDelete( DicomDir::Method *method ) +{ + StartMethodArgDelete = method; +} + +/** + * \brief Set the method to delete the argument + * The argument is destroyed when the method is changed or when the + * class is destroyed + * @param method Method to call to delete the argument + */ +void DicomDir::SetProgressMethodArgDelete( DicomDir::Method *method ) +{ + ProgressMethodArgDelete = method; +} + +/** + * \brief Set the method to delete the argument + * The argument is destroyed when the method is changed or when + * the class is destroyed + * @param method Method to call to delete the argument + */ +void DicomDir::SetEndMethodArgDelete( DicomDir::Method *method ) +{ + EndMethodArgDelete = method; +} + +/** + * \brief writes on disc a DICOMDIR + * \ warning does NOT add the missing elements in the header : + * it's up to the user doing it ! + * @param fileName file to be written to + * @return false only when fail to open + */ + +bool DicomDir::Write(std::string const &fileName) +{ + int i; + uint16_t sq[6] = { 0x0004, 0x1220, 0x5153, 0x0000, 0xffff, 0xffff }; + uint16_t sqt[4]= { 0xfffe, 0xe0dd, 0x0000, 0x0000 }; + + std::ofstream *fp = new std::ofstream(fileName.c_str(), + std::ios::out | std::ios::binary); + if ( !fp ) + { + gdcmWarningMacro("Failed to open(write) File: " << fileName.c_str()); + return false; + } + + char filePreamble[128]; + memset(filePreamble, 0, 128); + fp->write(filePreamble, 128); + binary_write( *fp, "DICM"); + + DicomDirMeta *ptrMeta = GetMeta(); + ptrMeta->WriteContent(fp, ExplicitVR); + + // force writing 0004|1220 [SQ ], that CANNOT exist within DicomDirMeta + for(i=0;i<6;++i) + { + binary_write(*fp, sq[i]); + } + + for(ListDicomDirPatient::iterator cc = Patients.begin(); + cc != Patients.end(); + ++cc ) + { + (*cc)->WriteContent( fp, ExplicitVR ); + } + + // force writing Sequence Delimitation Item + for(i=0;i<4;++i) + { + binary_write(*fp, sqt[i]); // fffe e0dd 0000 0000 + } + + fp->close(); + delete fp; + + return true; +} + +/** + * \brief Anonymize a DICOMDIR + * @return true + */ + +bool DicomDir::Anonymize() +{ + ValEntry *v; + // Something clever to be found to forge the Patient names + itksys_ios::ostringstream s; + int i = 1; + for(ListDicomDirPatient::iterator cc = Patients.begin(); + cc!= Patients.end(); + ++cc) + { + s << i; + v = (*cc)->GetValEntry(0x0010, 0x0010) ; // Patient's Name + if (v) + { + v->SetValue(s.str()); + } + + v = (*cc)->GetValEntry(0x0010, 0x0020) ; // Patient ID + if (v) + { + v->SetValue(" "); + } + + v = (*cc)->GetValEntry(0x0010, 0x0030) ; // Patient's BirthDate + if (v) + { + v->SetValue(" "); + } + s << ""; + i++; + } + return true; +} + +//----------------------------------------------------------------------------- +// Protected +/** + * \brief create a Document-like chained list from a root Directory + * @param path entry point of the tree-like structure + */ +void DicomDir::CreateDicomDirChainedList(std::string const &path) +{ + CallStartMethod(); + DirList dirList(path,1); // gets recursively the file list + unsigned int count = 0; + VectDocument list; + File *f; + + DirListType fileList = dirList.GetFilenames(); + + for( DirListType::iterator it = fileList.begin(); + it != fileList.end(); + ++it ) + { + Progress = (float)(count+1)/(float)fileList.size(); + CallProgressMethod(); + if ( Abort ) + { + break; + } + + f = new File( ); + f->SetLoadMode(LoadMode); // we allow user not to load Sequences, + // or Shadow groups, or ...... + f->SetFileName( it->c_str() ); + /*int res = */f->Load( ); + + if ( f->IsReadable() ) + { + // Add the file to the chained list: + list.push_back(f); + gdcmDebugMacro( "Readable " << it->c_str() ); + } + else + { + delete f; + } + count++; + } + // sorts Patient/Study/Serie/ + std::sort(list.begin(), list.end(), DicomDir::HeaderLessThan ); + + std::string tmp = dirList.GetDirName(); + //for each File of the chained list, add/update the Patient/Study/Serie/Image info + SetElements(tmp, list); + CallEndMethod(); + + for(VectDocument::iterator itDoc=list.begin(); + itDoc!=list.end(); + ++itDoc) + { + delete dynamic_cast<File *>(*itDoc); + } +} + +/** + * \brief CallStartMethod + */ +void DicomDir::CallStartMethod() +{ + Progress = 0.0f; + Abort = false; + if ( StartMethod ) + { + StartMethod( StartArg ); + } +} + +/** + * \brief CallProgressMethod + */ +void DicomDir::CallProgressMethod() +{ + if ( ProgressMethod ) + { + ProgressMethod( ProgressArg ); + } +} + +/** + * \brief CallEndMethod + */ +void DicomDir::CallEndMethod() +{ + Progress = 1.0f; + if ( EndMethod ) + { + EndMethod( EndArg ); + } +} + +//----------------------------------------------------------------------------- +// Private +/** + * \brief Sets all fields to NULL + */ +void DicomDir::Initialize() +{ + StartMethod = NULL; + ProgressMethod = NULL; + EndMethod = NULL; + StartMethodArgDelete = NULL; + ProgressMethodArgDelete = NULL; + EndMethodArgDelete = NULL; + StartArg = NULL; + ProgressArg = NULL; + EndArg = NULL; + + Progress = 0.0; + Abort = false; + + MetaElems = NULL; +} + +/** + * \brief create a 'gdcm::DicomDir' from a DICOMDIR Header + */ +void DicomDir::CreateDicomDir() +{ + // The SeqEntries of "Directory Record Sequence" are parsed. + // When a DicomDir tag ("PATIENT", "STUDY", "SERIE", "IMAGE") is found : + // 1 - we save the beginning iterator + // 2 - we continue to parse + // 3 - we find an other tag + // + we create the object for the precedent tag + // + loop to 1 - + gdcmDebugMacro("Create DicomDir"); + + // Directory record sequence + DocEntry *e = GetDocEntry(0x0004, 0x1220); + if ( !e ) + { + gdcmWarningMacro( "No Directory Record Sequence (0004,1220) found"); + return; + } + + SeqEntry *s = dynamic_cast<SeqEntry *>(e); + if ( !s ) + { + gdcmWarningMacro( "Element (0004,1220) is not a Sequence ?!?"); + return; + } + + NewMeta(); + + DocEntry *d; + std::string v; + SQItem *si; + + SQItem *tmpSI=s->GetFirstSQItem(); + while(tmpSI) + { + d = tmpSI->GetDocEntry(0x0004, 0x1430); // Directory Record Type + if ( ValEntry* valEntry = dynamic_cast<ValEntry *>(d) ) + { + v = valEntry->GetValue(); + } + else + { + gdcmWarningMacro( "(0004,1430) not a ValEntry ?!?"); + continue; + } + + // A decent DICOMDIR has much more images than series, + // more series than studies, and so on. + // This is the right order to perform the tests + + if ( v == "IMAGE " ) + { + si = new DicomDirImage(true); + if ( !AddImageToEnd( static_cast<DicomDirImage *>(si)) ) + { + delete si; + si = NULL; + gdcmErrorMacro( "Add AddImageToEnd failed"); + } + } + else if ( v == "SERIES" ) + { + si = new DicomDirSerie(true); + if ( !AddSerieToEnd( static_cast<DicomDirSerie *>(si)) ) + { + delete si; + si = NULL; + gdcmErrorMacro( "Add AddSerieToEnd failed"); + } + } + else if ( v == "VISIT " ) + { + si = new DicomDirVisit(true); + if ( !AddVisitToEnd( static_cast<DicomDirVisit *>(si)) ) + { + delete si; + si = NULL; + gdcmErrorMacro( "Add AddVisitToEnd failed"); + } + } + else if ( v == "STUDY " ) + { + si = new DicomDirStudy(true); + if ( !AddStudyToEnd( static_cast<DicomDirStudy *>(si)) ) + { + delete si; + si = NULL; + gdcmErrorMacro( "Add AddStudyToEnd failed"); + } + } + else if ( v == "PATIENT " ) + { + si = new DicomDirPatient(true); + if ( !AddPatientToEnd( static_cast<DicomDirPatient *>(si)) ) + { + delete si; + si = NULL; + gdcmErrorMacro( "Add PatientToEnd failed"); + } + } + else + { + // It was neither a 'PATIENT', nor a 'STUDY', nor a 'SERIE', + // nor an 'IMAGE' SQItem. Skip to next item. + gdcmDebugMacro( " -------------------------------------------" + << "a non PATIENT/STUDY/SERIE/IMAGE SQItem was found : " + << v); + + // FIXME : deal with other item types ! + tmpSI=s->GetNextSQItem(); // To avoid infinite loop + continue; + } + if ( si ) + //MoveSQItem(si,tmpSI); // Old code : Copies each Entry + // -and then removes the source- + si->MoveObject(tmpSI); // New code : Copies the List + + tmpSI=s->GetNextSQItem(); + } + ClearEntry(); +} + +/** + * \brief AddPatientToEnd + * @param dd SQ Item to enqueue to the DicomPatient chained List + */ +bool DicomDir::AddPatientToEnd(DicomDirPatient *dd) +{ + Patients.push_back(dd); + return true; +} + +/** + * \brief AddStudyToEnd + * @param dd SQ Item to enqueue to the DicomDirStudy chained List + */ +bool DicomDir::AddStudyToEnd(DicomDirStudy *dd) +{ + if ( Patients.size() > 0 ) + { + ListDicomDirPatient::iterator itp = Patients.end(); + itp--; + (*itp)->AddStudy(dd); + return true; + } + return false; +} + +/** + * \brief AddSerieToEnd + * @param dd SQ Item to enqueue to the DicomDirSerie chained List + */ +bool DicomDir::AddSerieToEnd(DicomDirSerie *dd) +{ + if ( Patients.size() > 0 ) + { + ListDicomDirPatient::iterator itp = Patients.end(); + itp--; + + DicomDirStudy *study = (*itp)->GetLastStudy(); + if ( study ) + { + study->AddSerie(dd); + return true; + } + } + return false; +} + +/** + * \brief AddVisitToEnd + * @param dd SQ Item to enqueue to the DicomDirVisit chained List + */ +bool DicomDir::AddVisitToEnd(DicomDirVisit *dd) +{ + if ( Patients.size() > 0 ) + { + ListDicomDirPatient::iterator itp = Patients.end(); + itp--; + + DicomDirStudy *study = (*itp)->GetLastStudy(); + if ( study ) + { + study->AddVisit(dd); + return true; + } + } + return false; +} +/** + * \brief AddImageToEnd + * @param dd SQ Item to enqueue to the DicomDirImage chained List + */ +bool DicomDir::AddImageToEnd(DicomDirImage *dd) +{ + if ( Patients.size() > 0 ) + { + ListDicomDirPatient::iterator itp = Patients.end(); + itp--; + + DicomDirStudy *study = (*itp)->GetLastStudy(); + if ( study ) + { + DicomDirSerie *serie = study->GetLastSerie(); + if ( serie ) + { + serie->AddImage(dd); + return true; + } + } + } + return false; +} + +/** + * \brief for each Header of the chained list, + * add/update the Patient/Study/Serie/Image info + * @param path path of the root directory + * @param list chained list of Headers + */ +void DicomDir::SetElements(std::string const &path, VectDocument const &list) +{ + ClearEntry(); + ClearPatient(); + + std::string patPrevName = "", patPrevID = ""; + std::string studPrevInstanceUID = "", studPrevID = ""; + std::string serPrevInstanceUID = "", serPrevID = ""; + + std::string patCurName, patCurID; + std::string studCurInstanceUID, studCurID; + std::string serCurInstanceUID, serCurID; + + bool first = true; + for( VectDocument::const_iterator it = list.begin(); + it != list.end(); + ++it ) + { + // get the current file characteristics + patCurName = (*it)->GetEntryValue(0x0010,0x0010); + patCurID = (*it)->GetEntryValue(0x0010,0x0011); + studCurInstanceUID = (*it)->GetEntryValue(0x0020,0x000d); + studCurID = (*it)->GetEntryValue(0x0020,0x0010); + serCurInstanceUID = (*it)->GetEntryValue(0x0020,0x000e); + serCurID = (*it)->GetEntryValue(0x0020,0x0011); + + if ( patCurName != patPrevName || patCurID != patPrevID || first ) + { + SetElement(path, GDCM_DICOMDIR_PATIENT, *it); + first = true; + } + + // if new Study, deal with 'STUDY' Elements + if ( studCurInstanceUID != studPrevInstanceUID || studCurID != studPrevID + || first ) + { + SetElement(path, GDCM_DICOMDIR_STUDY, *it); + first = true; + } + + // if new Serie, deal with 'SERIE' Elements + if ( serCurInstanceUID != serPrevInstanceUID || serCurID != serPrevID + || first ) + { + SetElement(path, GDCM_DICOMDIR_SERIE, *it); + } + + // Always Deal with 'IMAGE' Elements + SetElement(path, GDCM_DICOMDIR_IMAGE, *it); + + patPrevName = patCurName; + patPrevID = patCurID; + studPrevInstanceUID = studCurInstanceUID; + studPrevID = studCurID; + serPrevInstanceUID = serCurInstanceUID; + serPrevID = serCurID; + first = false; + } +} + +/** + * \brief adds to the HTable + * the Entries (Dicom Elements) corresponding to the given type + * @param path full path file name (only used when type = GDCM_DICOMDIR_IMAGE + * @param type DicomDirObject type to create (GDCM_DICOMDIR_PATIENT, + * GDCM_DICOMDIR_STUDY, GDCM_DICOMDIR_SERIE ...) + * @param header Header of the current file + */ +void DicomDir::SetElement(std::string const &path, DicomDirType type, + Document *header) +{ + ListDicomDirElem elemList; + ListDicomDirElem::const_iterator it; + uint16_t tmpGr, tmpEl; + DictEntry *dictEntry; + ValEntry *entry; + std::string val; + SQItem *si; + + switch( type ) + { + case GDCM_DICOMDIR_IMAGE: + elemList = Global::GetDicomDirElements()->GetDicomDirImageElements(); + si = new DicomDirImage(true); + if ( !AddImageToEnd(static_cast<DicomDirImage *>(si)) ) + { + delete si; + gdcmErrorMacro( "Add ImageToEnd failed"); + } + break; + case GDCM_DICOMDIR_SERIE: + elemList = Global::GetDicomDirElements()->GetDicomDirSerieElements(); + si = new DicomDirSerie(true); + if ( !AddSerieToEnd(static_cast<DicomDirSerie *>(si)) ) + { + delete si; + gdcmErrorMacro( "Add SerieToEnd failed"); + } + break; + case GDCM_DICOMDIR_STUDY: + elemList = Global::GetDicomDirElements()->GetDicomDirStudyElements(); + si = new DicomDirStudy(true); + if ( !AddStudyToEnd(static_cast<DicomDirStudy *>(si)) ) + { + delete si; + gdcmErrorMacro( "Add StudyToEnd failed"); + } + break; + case GDCM_DICOMDIR_PATIENT: + elemList = Global::GetDicomDirElements()->GetDicomDirPatientElements(); + si = new DicomDirPatient(true); + if ( !AddPatientToEnd(static_cast<DicomDirPatient *>(si)) ) + { + delete si; + gdcmErrorMacro( "Add PatientToEnd failed"); + } + break; + case GDCM_DICOMDIR_META: + elemList = Global::GetDicomDirElements()->GetDicomDirMetaElements(); + si = new DicomDirMeta(true); + if ( MetaElems ) + { + delete MetaElems; + gdcmErrorMacro( "MetaElements already exist, they will be destroyed"); + } + MetaElems = static_cast<DicomDirMeta *>(si); + break; + default: + return; + } + + // FIXME : troubles found when it's a SeqEntry + + // removed all the seems-to-be-useless stuff about Referenced Image Sequence + // to avoid further troubles + // imageElem 0008 1140 "" // Referenced Image Sequence + // imageElem fffe e000 "" // 'no length' item : length to be set to 0xffffffff later + // imageElem 0008 1150 "" // Referenced SOP Class UID : to be set/forged later + // imageElem 0008 1155 "" // Referenced SOP Instance UID : to be set/forged later + // imageElem fffe e00d "" // Item delimitation : length to be set to ZERO later + + // for all the relevant elements found in their own spot of the DicomDir.dic + for( it = elemList.begin(); it != elemList.end(); ++it) + { + tmpGr = it->Group; + tmpEl = it->Elem; + dictEntry = GetPubDict()->GetEntry(tmpGr, tmpEl); + + entry = new ValEntry( dictEntry ); // Be sure it's never a BinEntry ! + + entry->SetOffset(0); // just to avoid further missprinting + + if ( header ) + { + // NULL when we Build Up (ex nihilo) a DICOMDIR + // or when we add the META elems + val = header->GetEntryValue(tmpGr, tmpEl); + } + else + { + val = GDCM_UNFOUND; + } + + if ( val == GDCM_UNFOUND) + { + if ( tmpGr == 0x0004 && tmpEl == 0x1130 ) // File-set ID + { + // force to the *end* File Name + val = Util::GetName( path ); + } + else if ( tmpGr == 0x0004 && tmpEl == 0x1500 ) // Only used for image + { + if ( header->GetFileName().substr(0, path.length()) != path ) + { + gdcmWarningMacro( "The base path of file name is incorrect"); + val = header->GetFileName(); + } + else + { + val = &(header->GetFileName().c_str()[path.length()]); + } + } + else + { + val = it->Value; + } + } + else + { + if ( header->GetEntryLength(tmpGr,tmpEl) == 0 ) + val = it->Value; + } + + entry->SetValue( val ); // troubles expected when vr=SQ ... + + if ( type == GDCM_DICOMDIR_META ) // fusible : should never print ! + { + gdcmDebugMacro("GDCM_DICOMDIR_META ?!? should never print that"); + } + si->AddEntry(entry); + } +} + +/** + * \brief Move the content of the source SQItem to the destination SQItem + * Only DocEntry's are moved + * @param dst destination SQItem + * @param src source SQItem + */ +void DicomDir::MoveSQItem(DocEntrySet *dst, DocEntrySet *src) +{ + DocEntry *entry; +// todo : rewrite the whole stuff, without using RemoveEntry an AddEntry, +// to save time + entry = src->GetFirstEntry(); + while(entry) + { + src->RemoveEntryNoDestroy(entry); + dst->AddEntry(entry); + // we destroyed -> the current iterator is not longer valid + entry = src->GetFirstEntry(); + } +} + +/** + * \brief compares two files + */ +bool DicomDir::HeaderLessThan(Document *header1, Document *header2) +{ + return *header1 < *header2; +} + +//----------------------------------------------------------------------------- +// Print +/** + * \brief Canonical Printer + * @param os ostream we want to print in + * @param indent Indentation string to be prepended during printing + */ +void DicomDir::Print(std::ostream &os, std::string const & ) +{ + if ( MetaElems ) + { + MetaElems->SetPrintLevel(PrintLevel); + MetaElems->Print(os); + } + for(ListDicomDirPatient::iterator cc = Patients.begin(); + cc != Patients.end(); + ++cc) + { + (*cc)->SetPrintLevel(PrintLevel); + (*cc)->Print(os); + } +} + +//----------------------------------------------------------------------------- +} // end namespace gdcm diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmDicomDir.h b/Utilities/ITK/Utilities/gdcm/src/gdcmDicomDir.h new file mode 100644 index 0000000000000000000000000000000000000000..ece08e18fc8ccc54daef5ad80ffa5d539535d862 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmDicomDir.h @@ -0,0 +1,200 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmDicomDir.h,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:38 $ + Version: $Revision: 1.4 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#ifndef GDCMDICOMDIR_H +#define GDCMDICOMDIR_H + +#include "gdcmDocument.h" +#include "gdcmDebug.h" + +#include <list> +#include <vector> + +namespace gdcm +{ +//----------------------------------------------------------------------------- +class DicomDirPatient; +class DicomDirMeta; +class DicomDirElement; +class DicomDirStudy; +class DicomDirSerie; +class DicomDirVisit; +class DicomDirImage; +class SQItem; + +typedef std::list<DicomDirPatient *> ListDicomDirPatient; +typedef std::vector<Document *> VectDocument; + +//----------------------------------------------------------------------------- +/** + * \brief DicomDir defines an object representing a DICOMDIR in memory + * as a tree-like structure DicomDirPatient + * -> DicomDirStudy + * -> DicomDirSerie + * -> DicomDirImage + */ +class GDCM_EXPORT DicomDir: public Document +{ +public: + typedef void Method(void*); + + DicomDir(); + GDCM_LEGACY( DicomDir(std::string const &filename, bool parseDir = false) ); + ~DicomDir(); + + GDCM_LEGACY( bool Load(std::string const &filename) ); + bool Load( ); + void Print(std::ostream &os = std::cout, std::string const &indent = "" ); + + /// Sets the root Directory name to parse, recursively + void SetDirectoryName(std::string const &dirName) + { ParseDir = true; if (Filename != dirName) + Filename = dirName, IsDocumentModified = true; } + /// Accessor to \ref Filename + virtual void SetFileName(std::string const &fileName) + { ParseDir = false; if (Filename != fileName) + Filename = fileName, IsDocumentModified = true;} + + /// DEPRECATED : use SetDirectoryName + GDCM_LEGACY( void SetParseDir(bool parseDir) ); + + // Informations contained in the parser + virtual bool IsReadable(); + + // Meta + DicomDirMeta *NewMeta(); + /// Returns a pointer to the DicomDirMeta for this DICOMDIR. + DicomDirMeta *GetMeta() { return MetaElems; } + + // Patients + DicomDirPatient *NewPatient(); + void ClearPatient(); + + DicomDirPatient *GetFirstPatient(); + DicomDirPatient *GetNextPatient(); + + // Parsing + void ParseDirectory(); + + // Note: the DicomDir:: namespace prefix is needed by Swig in the + // following method declarations. Refer to gdcmPython/gdcm.i + // for the reasons of this unnecessary notation at C++ level. + void SetStartMethod( DicomDir::Method *method, + void *arg = NULL ); + void SetProgressMethod( DicomDir::Method *method, + void *arg = NULL ); + void SetEndMethod( DicomDir::Method *method, + void *arg = NULL ); + // Note: replace DicomDir::Method *method to void(*method)(void *) to + // avoid wrapping problems with the typemap conversions + void SetStartMethod( void(*method)(void *), // DicomDir::Method *method + void *arg, + void(*argDelete)(void *)); + void SetProgressMethod( void(*method)(void *), // DicomDir::Method *method + void *arg, + void(*argDelete)(void *)); + void SetEndMethod( void(*method)(void *), // DicomDir::Method *method + void *arg, + void(*argDelete)(void *)); + void SetStartMethodArgDelete ( DicomDir::Method *method ); + void SetProgressMethodArgDelete( DicomDir::Method *method ); + void SetEndMethodArgDelete ( DicomDir::Method *method ); + + /// GetProgress GetProgress + float GetProgress() const { return Progress; } + /// AbortProgress AbortProgress + void AbortProgress() { Abort = true; } + /// IsAborted IsAborted + bool IsAborted() { return Abort; } + + // Write + bool Write(std::string const &fileName); + + bool Anonymize(); + + /// Types of the DicomDirObject within the DicomDir + typedef enum + { + GDCM_DICOMDIR_NONE, + GDCM_DICOMDIR_META, + GDCM_DICOMDIR_PATIENT, + GDCM_DICOMDIR_STUDY, + GDCM_DICOMDIR_SERIE, + GDCM_DICOMDIR_VISIT, + GDCM_DICOMDIR_IMAGE + } DicomDirType; + +protected: + void CreateDicomDirChainedList(std::string const &path); + void CallStartMethod(); + void CallProgressMethod(); + void CallEndMethod(); + +private: + void Initialize(); + void CreateDicomDir(); + bool DoTheLoadingJob(); + bool AddPatientToEnd(DicomDirPatient *dd); + bool AddStudyToEnd (DicomDirStudy *dd); + bool AddSerieToEnd (DicomDirSerie *dd); + bool AddVisitToEnd (DicomDirVisit *dd); + bool AddImageToEnd (DicomDirImage *dd); + + void SetElements(std::string const &path, VectDocument const &list); + void SetElement (std::string const &path, DicomDirType type, + Document *header); + void MoveSQItem(DocEntrySet *dst, DocEntrySet *src); + + static bool HeaderLessThan(Document *header1, Document *header2); + +// Variables + + /// Pointer on *the* DicomDirObject 'DicomDirMeta Elements' + DicomDirMeta *MetaElems; + + /// Chained list of DicomDirPatient (to be exploited hierarchicaly) + ListDicomDirPatient Patients; + ListDicomDirPatient::iterator ItPatient; + + /// pointer to the initialisation method for any progress bar + Method *StartMethod; + /// pointer to the incrementation method for any progress bar + Method *ProgressMethod; + /// pointer to the termination method for any progress bar + Method *EndMethod; + /// pointer to the ??? method for any progress bar + Method *StartMethodArgDelete; + /// pointer to the ??? method for any progress bar + Method* ProgressMethodArgDelete; + /// pointer to the ??? method for any progress bar + Method *EndMethodArgDelete; + /// pointer to the ??? for any progress bar + void *StartArg; + /// pointer to the ??? for any progress bar + void *ProgressArg; + /// pointer to the ??? for any progress bar + void *EndArg; + /// value of the ??? for any progress bar + float Progress; + /// value of the ??? for any progress bar + bool Abort; + bool ParseDir; +}; +} // end namespace gdcm +//----------------------------------------------------------------------------- +#endif diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmDicomDirElement.cxx b/Utilities/ITK/Utilities/gdcm/src/gdcmDicomDirElement.cxx new file mode 100644 index 0000000000000000000000000000000000000000..06336ab09cc26dee8f594173a502aa2efbe708ad --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmDicomDirElement.cxx @@ -0,0 +1,219 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmDicomDirElement.cxx,v $ + Language: C++ + Date: $Date: 2006/02/20 15:56:57 $ + Version: $Revision: 1.7 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#include "gdcmDicomDirElement.h" +#include "gdcmUtil.h" +#include "gdcmDebug.h" +#include "gdcmDictSet.h" + +#include <fstream> +#include <iostream> + +namespace gdcm +{ +//----------------------------------------------------------------------------- +/// \brief auto generate function, to fill up the default elements for +/// a DICOMDIR, if relevant file is not found on user's disk +void FillDefaultDIRDict(DicomDirElement *dde); + +//----------------------------------------------------------------------------- +// Constructor / Destructor +/** + * \brief constructor : populates the chained lists + * from the file 'Dicts/DicomDir.dic' + */ +DicomDirElement::DicomDirElement() +{ + std::string filename = DictSet::BuildDictPath() + DICT_ELEM; + std::ifstream from(filename.c_str()); + if ( !from ) + { + gdcmWarningMacro( "Can't open DicomDirElement dictionary" + << filename.c_str()); + FillDefaultDIRDict( this ); + } + else + { + char buff[1024]; + std::string strType; + Element elem; + DicomDirType type; + + while (!from.eof()) + { + from >> std::ws; + from.getline(buff, 1024, ' '); + strType = buff; + + if ( strType == "imageElem" ) + type = DD_IMAGE; + else if ( strType == "serieElem" ) + type = DD_SERIE; + else if ( strType == "studyElem" ) + type = DD_STUDY; + else if ( strType == "patientElem" ) + type = DD_PATIENT; + else if ( strType == "metaElem" ) + type = DD_META; + else + { + gdcmWarningMacro("Unknown type (" << strType + << ") found in the file : " + << filename.c_str()); + type = DD_UNKNOWN; + } + + if ( type!=DD_UNKNOWN ) + { + from >> std::hex >> elem.Group >> elem.Elem; + + from >> std::ws; + from.getline(buff, 1024, '"'); + from >> std::ws; + from.getline(buff, 1024, '"'); + elem.Value = buff; + + AddEntry(type, elem); + } + from.getline(buff, 1024, '\n'); + } + from.close(); + } +} + +/** + * \brief canonical destructor + */ +DicomDirElement::~DicomDirElement() +{ + DicomDirMetaList.clear(); + DicomDirPatientList.clear(); + DicomDirStudyList.clear(); + DicomDirSerieList.clear(); + DicomDirImageList.clear(); +} + +//----------------------------------------------------------------------------- +// Public +/** + * \brief Add an entry to one of the DicomDir Elements + * (Patient, Study, Serie, Image) + * @param type Element type (DD_PATIENT, DD_STUDY, DD_SERIE, DD_IMAGE) + * @param elem elem + */ +bool DicomDirElement::AddEntry(DicomDirType type, Element const &elem) +{ + switch( type ) + { + case DD_IMAGE : + DicomDirImageList.push_back(elem); + break; + case DD_SERIE : + DicomDirSerieList.push_back(elem); + break; + case DD_STUDY : + DicomDirStudyList.push_back(elem); + break; + case DD_PATIENT : + DicomDirPatientList.push_back(elem); + break; + case DD_META : + DicomDirMetaList.push_back(elem); + break; + default : + return false; + } + return true; +} + +/** + * \brief Add an entry to one of the DicomDir Elements + * (Patient, Study, Serie, Image) + * @param type Element type (DD_PATIENT, DD_STUDY, DD_SERIE, DD_IMAGE) + * @param group Group number of the entry to be added + * @param elem Element number of the entry to be added + */ +void DicomDirElement::AddDicomDirElement(DicomDirType type, + uint16_t group, uint16_t elem) +{ + Element el; + el.Group = group; + el.Elem = elem; + el.Value = ""; + AddEntry(type, el); +} + +//----------------------------------------------------------------------------- +// Protected + +//----------------------------------------------------------------------------- +// Private + +//----------------------------------------------------------------------------- +// Print +/** + * \brief Print all + * @param os The output stream to be written to. + */ +void DicomDirElement::Print(std::ostream &os,std::string const &) +{ + itksys_ios::ostringstream s; + std::list<Element>::iterator it; + //char greltag[10]; //group element tag + TagKey greltag; + + s << "Meta Elements :"<<std::endl; + for (it = DicomDirMetaList.begin(); it != DicomDirMetaList.end(); ++it) + { + greltag = DictEntry::TranslateToKey(it->Group,it->Elem); + s << " (" << greltag << ") = " << it->Value << std::endl; + } + + s << "Patient Elements :"<<std::endl; + for (it = DicomDirPatientList.begin(); it != DicomDirPatientList.end(); ++it) + { + greltag = DictEntry::TranslateToKey(it->Group,it->Elem); + s << " (" << greltag << ") = " << it->Value << std::endl; + } + + s << "Study Elements :"<<std::endl; + for (it = DicomDirStudyList.begin(); it != DicomDirStudyList.end(); ++it) + { + greltag = DictEntry::TranslateToKey(it->Group, it->Elem); + s << " (" << greltag << ") = " << it->Value << std::endl; + } + + s << "Serie Elements :"<<std::endl; + for (it = DicomDirSerieList.begin(); it != DicomDirSerieList.end(); ++it) + { + greltag = DictEntry::TranslateToKey( it->Group, it->Elem); + s << " (" << greltag << ") = " << it->Value << std::endl; + } + + s << "Image Elements :"<<std::endl; + for (it = DicomDirImageList.begin(); it != DicomDirImageList.end(); ++it) + { + greltag = DictEntry::TranslateToKey(it->Group, it->Elem); + s << " (" << greltag << ") = " << it->Value << std::endl; + } + + os << s.str(); +} + +//----------------------------------------------------------------------------- +} // end namespace gdcm diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmDicomDirElement.h b/Utilities/ITK/Utilities/gdcm/src/gdcmDicomDirElement.h new file mode 100644 index 0000000000000000000000000000000000000000..0870e29a158762a9c6a3929aab8c2c96a2fae09e --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmDicomDirElement.h @@ -0,0 +1,145 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmDicomDirElement.h,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:38 $ + Version: $Revision: 1.4 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#ifndef GDCMDICOMDIRELEMENT_H +#define GDCMDICOMDIRELEMENT_H + +#include "gdcmCommon.h" + +#include <list> +#include <iostream> + +namespace gdcm +{ + +//----------------------------------------------------------------------------- + +typedef std::list<Element> ListDicomDirElem; +typedef std::list<Element> ListDicomDirMetaElem; +typedef std::list<Element> ListDicomDirPatientElem; +typedef std::list<Element> ListDicomDirStudyElem; +typedef std::list<Element> ListDicomDirVisitElem; +typedef std::list<Element> ListDicomDirSerieElem; +typedef std::list<Element> ListDicomDirImageElem; + +// For future use (Full DICOMDIR) + +/* +typedef std::list<Element> ListDicomDirResultElem; +typedef std::list<Element> ListDicomDirStudyComponentElem; + +typedef std::list<Element> ListDicomDirOverlayElem; +typedef std::list<Element> ListDicomDirModalityLutElem; +typedef std::list<Element> ListDicomDirModalityLutElem; +typedef std::list<Element> ListDicomDirCurveElem; +typedef std::list<Element> ListDicomDirStoredPrintElem; +typedef std::list<Element> ListDicomDirRtDoseElem; +typedef std::list<Element> ListDicomDirRtStructureSetElem; +typedef std::list<Element> ListDicomDirRtPlanElem; +typedef std::list<Element> ListDicomDirRtTreatRecordElem; +typedef std::list<Element> ListDicomDirPresentationElem; +typedef std::list<Element> ListDicomDirSrDocumentElem; +typedef std::list<Element> ListDicomDirKeyObjectDocElem; +typedef std::list<Element> ListDicomDirSpectroscopyElem; +typedef std::list<Element> ListDicomDirRawDataElem; +typedef std::list<Element> ListDicomDirRegistrationElem; +typedef std::list<Element> ListDicomDirFiducialElem; +*/ + +//----------------------------------------------------------------------------- +/** + * \brief Represents elements contained in a DicomDir class + * for the chained lists from the file 'Dicts/DicomDir.dic' + */ +class GDCM_EXPORT DicomDirElement +{ +public: + DicomDirElement(); + ~DicomDirElement(); + + /** + * \brief canonical Printer + */ + void Print(std::ostream &os = std::cout, + std::string const &indent = "" ); + + /** + * \brief returns a reference to the chained List + * related to the META Elements of a DICOMDIR. + */ + ListDicomDirMetaElem const &GetDicomDirMetaElements() const + { return DicomDirMetaList; } + + /** + * \brief returns a reference to the chained List + * related to the PATIENT Elements of a DICOMDIR. + */ + ListDicomDirPatientElem const &GetDicomDirPatientElements() const + { return DicomDirPatientList; } + + /** + * \brief returns a reference to the chained List + * related to the STUDY Elements of a DICOMDIR. + */ + ListDicomDirStudyElem const &GetDicomDirStudyElements() const + { return DicomDirStudyList; } + + /** + * \brief returns a reference to the chained List + * related to the VISIT Elements of a DICOMDIR. + */ + ListDicomDirVisitElem const &GetDicomDirVisitElements() const + { return DicomDirVisitList; } + /** + * \brief returns a reference to the chained List + * related to the SERIE Elements of a DICOMDIR. + */ + ListDicomDirSerieElem const &GetDicomDirSerieElements() const + { return DicomDirSerieList; } + + /** + * \brief returns a reference to the chained List + * related to the IMAGE Elements of a DICOMDIR. + */ + ListDicomDirImageElem const &GetDicomDirImageElements() const + { return DicomDirImageList; } + + // Public method to add an element + bool AddEntry(DicomDirType type, Element const &elem); + + // Only one instance of ddElem + void AddDicomDirElement(DicomDirType type, + uint16_t group, uint16_t elem); + +private: + /// Elements chained list, related to the MetaElements of DICOMDIR + ListDicomDirMetaElem DicomDirMetaList; + /// Elements chained list, related to the PatientElements of DICOMDIR + ListDicomDirPatientElem DicomDirPatientList; + /// Elements chained list, related to the StudyElements of DICOMDIR + ListDicomDirStudyElem DicomDirStudyList; + /// Elements chained list, related to the VisitElements of DICOMDIR + ListDicomDirVisitElem DicomDirVisitList; + /// Elements chained list, related to the SerieElements of DICOMDIR + ListDicomDirSerieElem DicomDirSerieList; + /// Elements chained list, related to the ImageElements of DICOMDIR + ListDicomDirImageElem DicomDirImageList; +}; +} // end namespace gdcm +//----------------------------------------------------------------------------- +#endif diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmDicomDirImage.cxx b/Utilities/ITK/Utilities/gdcm/src/gdcmDicomDirImage.cxx new file mode 100644 index 0000000000000000000000000000000000000000..df550efb8d42fa630ce2403e8caa45aee5d221cd --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmDicomDirImage.cxx @@ -0,0 +1,86 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmDicomDirImage.cxx,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:38 $ + Version: $Revision: 1.4 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#include "gdcmDicomDirImage.h" +#include "gdcmValEntry.h" +#include "gdcmGlobal.h" + +namespace gdcm +{ +//----------------------------------------------------------------------------- +// Constructor / Destructor +/** + * \brief Constructor + * \note End user must use : DicomDirSerie::NewImage() + */ +DicomDirImage::DicomDirImage(bool empty): + DicomDirObject() +{ + if ( !empty ) + { + ListDicomDirImageElem const &elemList = + Global::GetDicomDirElements()->GetDicomDirImageElements(); + FillObject(elemList); + } +} + +/** + * \brief Canonical destructor. + */ +DicomDirImage::~DicomDirImage() +{ +} + +//----------------------------------------------------------------------------- +// Public + +//----------------------------------------------------------------------------- +// Protected + +//----------------------------------------------------------------------------- +// Private + +//----------------------------------------------------------------------------- +// Print +/** + * \brief Prints the Object + * @param os ostream to write to + * @param indent Indentation string to be prepended during printing + * @return + */ +void DicomDirImage::Print(std::ostream &os, std::string const & ) +{ + os << "IMAGE : "; + for(ListDocEntry::iterator i = DocEntries.begin(); + i!= DocEntries.end(); + ++i) + { + if ( (*i)->GetGroup() == 0x0004 && (*i)->GetElement() == 0x1500 ) + { + if( dynamic_cast<ValEntry *>(*i) ) + os << (dynamic_cast<ValEntry *>(*i))->GetValue(); + } + } + os << std::endl; + + DicomDirObject::Print(os); +} + +//----------------------------------------------------------------------------- +} // end namespace gdcm + diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmDicomDirImage.h b/Utilities/ITK/Utilities/gdcm/src/gdcmDicomDirImage.h new file mode 100644 index 0000000000000000000000000000000000000000..148e1d1eeccb8e2eea3d7c28726ddd492f82a06b --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmDicomDirImage.h @@ -0,0 +1,41 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmDicomDirImage.h,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:38 $ + Version: $Revision: 1.4 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#ifndef GDCMDICOMIMAGE_H +#define GDCMDICOMIMAGE_H + +#include "gdcmDicomDirObject.h" + +namespace gdcm +{ +//----------------------------------------------------------------------------- +/** + * \brief describes an IMAGE within a SERIE + * (DicomDirSerie) of a given DICOMDIR (DicomDir) + */ + class GDCM_EXPORT DicomDirImage : public DicomDirObject +{ +public: + DicomDirImage(bool empty=false); + ~DicomDirImage(); + + void Print(std::ostream &os = std::cout, std::string const &indent = "" ); +}; +} // end namespace gdcm +//----------------------------------------------------------------------------- +#endif diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmDicomDirMeta.cxx b/Utilities/ITK/Utilities/gdcm/src/gdcmDicomDirMeta.cxx new file mode 100644 index 0000000000000000000000000000000000000000..965f4920c90355834bfcaf24d6ed3a782d813e91 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmDicomDirMeta.cxx @@ -0,0 +1,95 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmDicomDirMeta.cxx,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:38 $ + Version: $Revision: 1.4 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#include "gdcmDicomDirMeta.h" +#include "gdcmDocument.h" +#include "gdcmDocEntry.h" +#include "gdcmGlobal.h" + +namespace gdcm +{ +//----------------------------------------------------------------------------- +// Constructor / Destructor +/** + * \brief Constructor + */ +DicomDirMeta::DicomDirMeta(bool empty): + DicomDirObject() +{ + if ( !empty ) + { + ListDicomDirStudyElem const &elemList = + Global::GetDicomDirElements()->GetDicomDirMetaElements(); + FillObject(elemList); + } +} + +/** + * \brief Canonical destructor. + */ +DicomDirMeta::~DicomDirMeta() +{ +} + +//----------------------------------------------------------------------------- +// Public +/** + * \brief Writes the Meta Elements + * @param fp ofstream to write to + * @param filetype type of the file (ACR, ImplicitVR, ExplicitVR, ...) + * @return + */ +void DicomDirMeta::WriteContent(std::ofstream *fp, FileType filetype) +{ + for (ListDocEntry::iterator i = DocEntries.begin(); + i != DocEntries.end(); + ++i) + { + (*i)->WriteContent(fp, filetype); + } +} + +//----------------------------------------------------------------------------- +// Protected + +//----------------------------------------------------------------------------- +// Private + +//----------------------------------------------------------------------------- +// Print +/** + * \brief Prints the Meta Elements + * @param os ostream to write to + * @param indent Indentation string to be prepended during printing + */ +void DicomDirMeta::Print(std::ostream &os, std::string const & ) +{ + os << "META" << std::endl; + // warning : META doesn't behave exactly like a Objet + for (ListDocEntry::iterator i = DocEntries.begin(); + i != DocEntries.end(); + ++i) + { + (*i)->SetPrintLevel(PrintLevel); + (*i)->Print(); + os << std::endl; + } +} + +//----------------------------------------------------------------------------- +} // end namespace gdcm diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmDicomDirMeta.h b/Utilities/ITK/Utilities/gdcm/src/gdcmDicomDirMeta.h new file mode 100644 index 0000000000000000000000000000000000000000..7b62c02185f6ba9bbc24ff61af040f024ad66f2d --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmDicomDirMeta.h @@ -0,0 +1,42 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmDicomDirMeta.h,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:38 $ + Version: $Revision: 1.4 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#ifndef GDCMDICOMDIRMETA_H +#define GDCMDICOMDIRMETA_H + +#include "gdcmDicomDirObject.h" + +namespace gdcm +{ + +//----------------------------------------------------------------------------- +/** + * \brief Meta Elements (group 0002) of a DicomDir + */ +class GDCM_EXPORT DicomDirMeta : public DicomDirObject +{ +public: + DicomDirMeta(bool empty=false); + ~DicomDirMeta(); + + virtual void Print(std::ostream &os = std::cout, std::string const &indent = "" ); + virtual void WriteContent(std::ofstream *fp, FileType t); +}; +} // end namespace gdcm +//----------------------------------------------------------------------------- +#endif diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmDicomDirObject.cxx b/Utilities/ITK/Utilities/gdcm/src/gdcmDicomDirObject.cxx new file mode 100644 index 0000000000000000000000000000000000000000..ce751cb0a0fe9c125406275ff83d028204740a0f --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmDicomDirObject.cxx @@ -0,0 +1,85 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmDicomDirObject.cxx,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:38 $ + Version: $Revision: 1.4 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#include "gdcmDicomDirObject.h" +#include "gdcmGlobal.h" +#include "gdcmDebug.h" +#include "gdcmValEntry.h" +#include "gdcmDictSet.h" + +namespace gdcm +{ +//----------------------------------------------------------------------------- +/** + * \brief Constructor + * + * @param depth Sequence depth level + */ + +DicomDirObject::DicomDirObject(int depth) + : SQItem (depth) +{ +} + +/** + * \brief Canonical destructor. + */ +DicomDirObject::~DicomDirObject() +{ +} + +//----------------------------------------------------------------------------- +// Public + +//----------------------------------------------------------------------------- +// Protected +/** + * \brief add the 'Object' related Dicom Elements to the listEntries + * of a partially created DICOMDIR + * @param elemList Element List to add at the right place + */ +void DicomDirObject::FillObject(ListDicomDirMetaElem const &elemList) +{ + // FillObject fills up the SQItem that will be connected to the right place + ListDicomDirMetaElem::const_iterator it; + uint16_t tmpGr,tmpEl; + DictEntry *dictEntry; + ValEntry *entry; + + // for all the Elements found in they own part of the DicomDir dict. + for(it = elemList.begin(); it != elemList.end(); ++it) + { + tmpGr = it->Group; + tmpEl = it->Elem; + dictEntry = Global::GetDicts()->GetDefaultPubDict()->GetEntry(tmpGr,tmpEl); + entry = new ValEntry(dictEntry); + entry->SetOffset(0); // just to avoid further missprinting + entry->SetValue(it->Value); + + AddEntry(entry); + } +} + +//----------------------------------------------------------------------------- +// Private + +//----------------------------------------------------------------------------- +// Print + +//----------------------------------------------------------------------------- +} // end namespace gdcm diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmDicomDirObject.h b/Utilities/ITK/Utilities/gdcm/src/gdcmDicomDirObject.h new file mode 100644 index 0000000000000000000000000000000000000000..42c0870ed566710e656e3d06d5c608c1cb14fe82 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmDicomDirObject.h @@ -0,0 +1,56 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmDicomDirObject.h,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:38 $ + Version: $Revision: 1.4 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#ifndef GDCMDICOMDIROBJECT_H +#define GDCMDICOMDIROBJECT_H + +#include "gdcmSQItem.h" +#include "gdcmDicomDirElement.h" + +#include <string> +#include <list> + +namespace gdcm +{ +//----------------------------------------------------------------------------- +class DicomDirObject; + +//----------------------------------------------------------------------------- +typedef std::list<DicomDirObject *> ListContent; +//----------------------------------------------------------------------------- +/** + * \brief Parent object for DicomDirPatient, DicomDirStudy, + * DicomDirSerie, DicomDirImage, of a DicomDir + */ +class GDCM_EXPORT DicomDirObject : public SQItem +{ +public: + +protected: + // Constructor and destructor are protected to avoid end user to + // instanciate from this class. + DicomDirObject(int depth = 1); + ~DicomDirObject(); + + void FillObject(ListDicomDirMetaElem const &elemList); + +}; +} // end namespace gdcm + +//----------------------------------------------------------------------------- +#endif diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmDicomDirPatient.cxx b/Utilities/ITK/Utilities/gdcm/src/gdcmDicomDirPatient.cxx new file mode 100644 index 0000000000000000000000000000000000000000..73521cb699c1f534ed070d39a6e0fbbf6f97bc7b --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmDicomDirPatient.cxx @@ -0,0 +1,167 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmDicomDirPatient.cxx,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:38 $ + Version: $Revision: 1.4 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#include "gdcmDicomDirPatient.h" +#include "gdcmDicomDirElement.h" +#include "gdcmGlobal.h" +#include "gdcmDicomDirStudy.h" +#include "gdcmSQItem.h" +#include "gdcmDebug.h" + +namespace gdcm +{ +//----------------------------------------------------------------------------- +// Constructor / Destructor +/** + * \brief Constructor + * \note End user must use : DicomDir::NewPatient() + */ +DicomDirPatient::DicomDirPatient(bool empty) + :DicomDirObject() +{ + if ( !empty ) + { + ListDicomDirStudyElem const &elemList = + Global::GetDicomDirElements()->GetDicomDirPatientElements(); + FillObject(elemList); + } +} + +/** + * \brief Canonical destructor. + */ +DicomDirPatient::~DicomDirPatient() +{ + ClearStudy(); +} + +//----------------------------------------------------------------------------- +// Public +/** + * \brief Writes the Object + * @param fp ofstream to write to + * @param t Type of the File (explicit VR, implicitVR, ...) + */ +void DicomDirPatient::WriteContent(std::ofstream *fp, FileType t) +{ + DicomDirObject::WriteContent(fp, t); + + for(ListDicomDirStudy::iterator cc = Studies.begin(); + cc!= Studies.end(); + ++cc ) + { + (*cc)->WriteContent( fp, t ); + } +} + +/** + * \brief adds a new Patient at the beginning of the PatientList + * of a partially created DICOMDIR + */ +DicomDirStudy* DicomDirPatient::NewStudy() +{ + DicomDirStudy *st = new DicomDirStudy(); + Studies.push_back(st); + return st; +} + +/** + * \brief Remove all studies in the patient + */ +void DicomDirPatient::ClearStudy() +{ + for(ListDicomDirStudy::const_iterator cc = Studies.begin(); + cc != Studies.end(); + ++cc ) + { + delete *cc; + } + Studies.clear(); +} + +/** + * \brief Get the first entry while visiting the DicomDirStudy + * \return The first DicomDirStudy if found, otherwhise NULL + */ +DicomDirStudy *DicomDirPatient::GetFirstStudy() +{ + ItStudy = Studies.begin(); + if (ItStudy != Studies.end()) + return *ItStudy; + return NULL; +} + +/** + * \brief Get the next entry while visiting the DicomDirStudies + * \note : meaningfull only if GetFirstEntry already called + * \return The next DicomDirStudies if found, otherwhise NULL + */ +DicomDirStudy *DicomDirPatient::GetNextStudy() +{ + gdcmAssertMacro (ItStudy != Studies.end()) + + ++ItStudy; + if (ItStudy != Studies.end()) + return *ItStudy; + return NULL; +} + +/** + * \brief Get the first entry while visiting the DicomDirStudy + * \return The first DicomDirStudy if found, otherwhise NULL + */ +DicomDirStudy *DicomDirPatient::GetLastStudy() +{ + ItStudy = Studies.end(); + if (ItStudy != Studies.begin()) + { + --ItStudy; + return *ItStudy; + } + return NULL; +} + +//----------------------------------------------------------------------------- +// Protected + +//----------------------------------------------------------------------------- +// Private + +//----------------------------------------------------------------------------- +// Print +/** + * \brief Prints the Object + * @param os ostream to write to + * @param indent Indentation string to be prepended during printing + */ +void DicomDirPatient::Print(std::ostream &os, std::string const & ) +{ + os << "PATIENT" << std::endl; + DicomDirObject::Print(os); + + for(ListDicomDirStudy::const_iterator cc = Studies.begin(); + cc != Studies.end(); + ++cc ) + { + (*cc)->SetPrintLevel(PrintLevel); + (*cc)->Print(os); + } +} + +//----------------------------------------------------------------------------- +} // end namespace gdcm diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmDicomDirPatient.h b/Utilities/ITK/Utilities/gdcm/src/gdcmDicomDirPatient.h new file mode 100644 index 0000000000000000000000000000000000000000..318f718c407532d6a7ea4ebc6eecec29ffdb04dc --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmDicomDirPatient.h @@ -0,0 +1,65 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmDicomDirPatient.h,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:38 $ + Version: $Revision: 1.4 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#ifndef GDCMPATIENT_H +#define GDCMPATIENT_H + +#include "gdcmDicomDirObject.h" + +namespace gdcm +{ +class DicomDirStudy; + +//----------------------------------------------------------------------------- +typedef std::list<DicomDirStudy*> ListDicomDirStudy; + +//----------------------------------------------------------------------------- +/** + * \brief describes a PATIENT within a DICOMDIR (DicomDir) + */ + +class GDCM_EXPORT DicomDirPatient : public DicomDirObject +{ +public: + DicomDirPatient(bool empty=false); + ~DicomDirPatient(); + + void Print(std::ostream &os = std::cout, std::string const &indent = "" ); + void WriteContent(std::ofstream *fp, FileType t); + + // Patient methods + /// \brief Adds a new gdcmDicomDirStudy to the Patient + void AddStudy(DicomDirStudy *obj) { Studies.push_back(obj); } + DicomDirStudy *NewStudy(); + void ClearStudy(); + + DicomDirStudy *GetFirstStudy(); + DicomDirStudy *GetNextStudy(); + DicomDirStudy *GetLastStudy(); + +private: + + /// chained list of DicomDirStudy (to be exploited hierarchicaly) + ListDicomDirStudy Studies; + /// iterator on the DicomDirStudies of the current DicomDirPatient + ListDicomDirStudy::iterator ItStudy; +}; +} // end namespace gdcm + +//----------------------------------------------------------------------------- +#endif diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmDicomDirSerie.cxx b/Utilities/ITK/Utilities/gdcm/src/gdcmDicomDirSerie.cxx new file mode 100644 index 0000000000000000000000000000000000000000..cada8bde6917129aeaf978dd48deae572beaa095 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmDicomDirSerie.cxx @@ -0,0 +1,151 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmDicomDirSerie.cxx,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:38 $ + Version: $Revision: 1.4 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#include "gdcmDicomDirSerie.h" +#include "gdcmDicomDirElement.h" +#include "gdcmDicomDirImage.h" +#include "gdcmGlobal.h" +#include "gdcmDebug.h" + +namespace gdcm +{ +//----------------------------------------------------------------------------- +// Constructor / Destructor +/** + * \brief Constructor + * \note End user must use : DicomDirStudy::NewSerie() + */ +DicomDirSerie::DicomDirSerie(bool empty): + DicomDirObject() +{ + if ( !empty ) + { + ListDicomDirSerieElem const &elemList = + Global::GetDicomDirElements()->GetDicomDirSerieElements(); + FillObject(elemList); + } +} + +/** + * \brief Canonical destructor. + */ +DicomDirSerie::~DicomDirSerie() +{ + ClearImage(); +} + +//----------------------------------------------------------------------------- +// Public +/** + * \brief Writes the Object + * @param fp ofstream to write to + * @param t Type of the File (explicit VR, implicitVR, ...) + */ +void DicomDirSerie::WriteContent(std::ofstream *fp, FileType t) +{ + DicomDirObject::WriteContent(fp, t); + + for(ListDicomDirImage::iterator cc = Images.begin(); + cc!= Images.end(); + ++cc ) + { + (*cc)->WriteContent( fp, t ); + } +} + +/** + * \brief adds a new Image (with the basic elements) to a partially created + * DICOMDIR + */ +DicomDirImage *DicomDirSerie::NewImage() +{ + DicomDirImage *st = new DicomDirImage(); + Images.push_back(st); + return st; +} + +/** + * \brief Remove all images in the serie + */ +void DicomDirSerie::ClearImage() +{ + for(ListDicomDirImage::iterator cc = Images.begin(); + cc != Images.end(); + ++cc) + { + delete *cc; + } + Images.clear(); +} + +/** + * \brief Get the first entry while visiting the DicomDirImage + * \return The first DicomDirImage if DicomDirserie not empty, otherwhise NULL + */ +DicomDirImage *DicomDirSerie::GetFirstImage() +{ + ItImage = Images.begin(); + if (ItImage != Images.end()) + return *ItImage; + return NULL; +} + +/** + * \brief Get the next entry while visiting the DicomDirImages + * \note : meaningfull only if GetFirstEntry already called + * \return The next DicomDirImages if found, otherwhise NULL + */ +DicomDirImage *DicomDirSerie::GetNextImage() +{ + gdcmAssertMacro (ItImage != Images.end()); + + ++ItImage; + if (ItImage != Images.end()) + return *ItImage; + return NULL; +} + +//----------------------------------------------------------------------------- +// Protected + +//----------------------------------------------------------------------------- +// Private + +//----------------------------------------------------------------------------- +// Print +/** + * \brief Prints the Object + * @param os ostream to write to + * @param indent Indentation string to be prepended during printing + */ +void DicomDirSerie::Print(std::ostream &os, std::string const &) +{ + os << "SERIE" << std::endl; + DicomDirObject::Print(os); + + for(ListDicomDirImage::iterator cc = Images.begin(); + cc != Images.end(); + ++cc) + { + (*cc)->SetPrintLevel(PrintLevel); + (*cc)->Print(os); + } +} + +//----------------------------------------------------------------------------- +} // end namespace gdcm diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmDicomDirSerie.h b/Utilities/ITK/Utilities/gdcm/src/gdcmDicomDirSerie.h new file mode 100644 index 0000000000000000000000000000000000000000..00b2a75228325f625bc48d72c929d42d30d4b5f1 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmDicomDirSerie.h @@ -0,0 +1,152 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmDicomDirSerie.h,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:38 $ + Version: $Revision: 1.4 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#ifndef GDCMDICOMDIRSERIE_H +#define GDCMDICOMDIRSERIE_H + +#include "gdcmDicomDirObject.h" + +namespace gdcm +{ +class DicomDirImage; +//----------------------------------------------------------------------------- +typedef std::list<DicomDirImage *> ListDicomDirImage; + +//----------------------------------------------------------------------------- +/** + * \brief describes a SERIE within a within a STUDY + * (DicomDirStudy) of a given DICOMDIR (DicomDir) + */ +class GDCM_EXPORT DicomDirSerie : public DicomDirObject +{ +public: + DicomDirSerie(bool empty=false); + ~DicomDirSerie(); + + void Print( std::ostream &os = std::cout, std::string const &indent = "" ); + void WriteContent( std::ofstream *fp, FileType t ); + + // Image methods + DicomDirImage *NewImage(); + /// Add a new gdcm::DicomDirImage to the Serie + void AddImage(DicomDirImage *obj) { Images.push_back(obj); } + void ClearImage(); + + DicomDirImage *GetFirstImage(); + DicomDirImage *GetNextImage(); + +private: + + ///chained list of DicomDirImages (to be exploited recursively) + ListDicomDirImage Images; + /// iterator on the DicomDirImages of the current DicomDirSerie + ListDicomDirImage::iterator ItImage; + +/* +// for future use : + + /// chained list of DicomDirOverlays(single level) + ListDicomDirOverlay Overlays; + /// iterator on the DicomDirOverlays of the current DicomDirSerie + ListDicomDirOverlay::iterator ItOverlay; + + /// chained list of DicomDirModalityLuts(single level) + ListDicomDirModalityLut ModalityLuts; + /// iterator on the DicomDirModalityLuts of the current DicomDirSerie + ListDicomDirModalityLut::iterator ItModalityLut; + + /// chained list of DicomDirModalityLuts(single level) + ListDicomDirModalityLut ModalityLuts; + /// iterator on the DicomDirModalityLuts of the current DicomDirSerie + ListDicomDirModalityLut::iterator ItModalityLuts; + + /// chained list of DicomDirCurves(single level) + ListDicomDirCurve Curves; + /// iterator on the DicomDirCurves of the current DicomDirSerie + ListDicomDirCurve::iterator ItCurves; + + /// chained list of DicomDirStoredPrints(single level) + ListDicomDirStoredPrint StoredPrints; + /// iterator on the DicomDirStoredPrints of the current DicomDirSerie + ListDicomDirStoredPrint::iterator ItStoredPrints; + + /// chained list of DicomDirRtDoses(single level) + ListDicomDirRtDose RtDoses; + /// iterator on the DicomDirRtDoses of the current DicomDirSerie + ListDicomDirRtDose::iterator ItRtDoses; + + /// chained list of DicomDirRtStructureSets(single level) + ListDicomDirRtStructureSet RtStructureSets; + /// iterator on the DicomDirRtStructureSets of the current DicomDirSerie + ListDicomDirRtStructureSet::iterator ItRtStructureSets; + + /// chained list of DicomDirRtPlans(single level) + ListDicomDirRtPlan RtPlans; + /// iterator on the DicomDirRtPlans of the current DicomDirSerie + ListDicomDirPlan::iterator ItRtPlans; + + /// chained list of DicomDirRtTreatRecords(single level) + ListDicomDirRtTreatRecord RtTreatRecords; + /// iterator on the DicomDirRtTreatRecords of the current DicomDirSerie + ListDicomDirRtTreatRecord::iterator ItRtTreatRecords; + + /// chained list of DicomDirPresentations(single level) + ListDicomDirPresentation Presentations; + /// iterator on the DicomDirPresentations of the current DicomDirSerie + ListDicomDirPresentation::iterator ItPresentations; + + /// chained list of DicomDirWaveForms(single level) + ListDicomDirWaveForm WaveForms; + /// iterator on the DicomDirWaveForms of the current DicomDirSerie + ListDicomDirWaveForm::iterator ItWaveForms; + + /// chained list of DicomDirSrDocuments(single level) + ListDicomDirSrDocument SrDocuments; + /// iterator on the DicomDirSrDocuments of the current DicomDirSerie + ListDicomDirSrDocument::iterator ItSrDocuments; + + /// chained list of DicomDirKeyObjectDocs(single level) + ListDicomDirKeyObjectDoc KeyObjectDocs; + /// iterator on the DicomDirKeyObjectDocs of the current DicomDirSerie + ListDicomDirKeyObjectDoc::iterator ItKeyObjectDocs; + + /// chained list of DicomDirSpectroscopys(single level) + ListDicomDirSpectroscopy Spectroscopys; + /// iterator on the DicomDirSpectroscopys of the current DicomDirSerie + ListDicomDirSpectroscopy::iterator ItSpectroscopys; + + /// chained list of DicomDirRawDatas(single level) + ListDicomDirRawData RawDatas; + /// iterator on the DicomDirRawDatas of the current DicomDirSerie + ListDicomDirRawData::iterator ItRawDatas; + + /// chained list of DicomDirRegistrations(single level) + ListDicomDirRegistration Registrations; + /// iterator on the DicomDirRegistrations of the current DicomDirSerie + ListDicomDirRegistration::iterator ItRegistrations; + + /// chained list of DicomDirFiducials(single level) + ListDicomDirFiducial Fiducials; + /// iterator on the DicomDirFiducials of the current DicomDirSerie + ListDicomDirFiducial::iterator ItFiducials; +*/ + +}; +} // end namespace gdcm +//----------------------------------------------------------------------------- +#endif diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmDicomDirStudy.cxx b/Utilities/ITK/Utilities/gdcm/src/gdcmDicomDirStudy.cxx new file mode 100644 index 0000000000000000000000000000000000000000..88ec946f261a0aa4ae8a60c44f69e3024e018675 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmDicomDirStudy.cxx @@ -0,0 +1,253 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmDicomDirStudy.cxx,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:38 $ + Version: $Revision: 1.4 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#include "gdcmDicomDirStudy.h" +#include "gdcmDicomDirElement.h" +#include "gdcmGlobal.h" +#include "gdcmDicomDirSerie.h" +#include "gdcmDicomDirVisit.h" +#include "gdcmDebug.h" + +namespace gdcm +{ +//----------------------------------------------------------------------------- +// Constructor / Destructor +/** + * \brief Constructor + * \note End user must use : DicomDirPatient::NewStudy() + */ +DicomDirStudy::DicomDirStudy(bool empty) + :DicomDirObject() +{ + if ( !empty ) + { + ListDicomDirStudyElem const &elemList = + Global::GetDicomDirElements()->GetDicomDirStudyElements(); + FillObject(elemList); + } +} + +/** + * \brief Canonical destructor. + */ +DicomDirStudy::~DicomDirStudy() +{ + ClearSerie(); +} + +//----------------------------------------------------------------------------- +// Public +/** + * \brief Writes the Object + * @param fp ofstream to write to + * @param t Type of the File (explicit VR, implicitVR, ...) + * @return + */ +void DicomDirStudy::WriteContent(std::ofstream *fp, FileType t) +{ + DicomDirObject::WriteContent(fp, t); + + for(ListDicomDirSerie::iterator cc = Series.begin(); + cc!= Series.end(); + ++cc ) + { + (*cc)->WriteContent( fp, t ); + } + + for(ListDicomDirVisit::iterator icc = Visits.begin(); + icc!= Visits.end(); + ++icc ) + { + (*icc)->WriteContent( fp, t ); + } +} + +/** + * \brief adds a new Serie at the beginning of the SerieList + * of a partially created DICOMDIR + */ +DicomDirSerie *DicomDirStudy::NewSerie() +{ + DicomDirSerie *st = new DicomDirSerie(); + Series.push_back(st); + return st; +} + +/** + * \brief Remove all series in the study + */ +void DicomDirStudy::ClearSerie() +{ + for(ListDicomDirSerie::iterator cc = Series.begin(); + cc != Series.end(); + ++cc ) + { + delete *cc; + } + Series.clear(); +} + +/** + * \brief Get the first entry while visiting the DicomDirSeries + * \return The first DicomDirSerie if found, otherwhise NULL + */ +DicomDirSerie *DicomDirStudy::GetFirstSerie() +{ + ItSerie = Series.begin(); + if (ItSerie != Series.end()) + return *ItSerie; + return NULL; +} + +/** + * \brief Get the next entry while visiting the DicomDirSeries + * \note : meaningfull only if GetFirstEntry already called + * \return The next DicomDirSerie if found, otherwhise NULL + */ +DicomDirSerie *DicomDirStudy::GetNextSerie() +{ + gdcmAssertMacro (ItSerie != Series.end()); + + ++ItSerie; + if (ItSerie != Series.end()) + return *ItSerie; + return NULL; +} + +/** + * \brief Get the last entry while visiting the DicomDirSeries + * \return The last DicomDirSerie if found, otherwhise NULL + */ +DicomDirSerie *DicomDirStudy::GetLastSerie() +{ + ItSerie = Series.end(); + if (ItSerie != Series.begin()) + { + --ItSerie; + return *ItSerie; + } + return NULL; +} + + +/** + * \brief adds a new Visit at the beginning of the VisitList + * of a partially created DICOMDIR + */ +DicomDirVisit *DicomDirStudy::NewVisit() +{ + DicomDirVisit *st = new DicomDirVisit(); + Visits.push_back(st); + return st; +} + +/** + * \brief Remove all visits in the study + */ +void DicomDirStudy::ClearVisit() +{ + for(ListDicomDirVisit::iterator cc = Visits.begin(); + cc != Visits.end(); + ++cc ) + { + delete *cc; + } + Visits.clear(); +} + +/** + * \brief Get the first entry while visiting the DicomDirVisit + * \return The first DicomDirVisit if found, otherwhise NULL + */ +DicomDirVisit *DicomDirStudy::GetFirstVisit() +{ + ItVisit = Visits.begin(); + if (ItVisit != Visits.end()) + return *ItVisit; + return NULL; +} + +/** + * \brief Get the next entry while visiting the DicomDirVisit + * \note : meaningfull only if GetFirstEntry already called + * \return The next DicomDirVisit if found, otherwhise NULL + */ +DicomDirVisit *DicomDirStudy::GetNextVisit() +{ + gdcmAssertMacro (ItVisit != Visits.end()); + + ++ItVisit; + if (ItVisit != Visits.end()) + return *ItVisit; + return NULL; +} + +/** + * \brief Get the last entry while visiting the DicomDirVisit + * \return The last DicomDirVisit if found, otherwhise NULL + */ +DicomDirVisit *DicomDirStudy::GetLastVisit() +{ + ItVisit = Visits.end(); + if (ItVisit != Visits.begin()) + { + --ItVisit; + return *ItVisit; + } + return NULL; +} + +//----------------------------------------------------------------------------- +// Protected + +//----------------------------------------------------------------------------- +// Private + +//----------------------------------------------------------------------------- +// Print +/** + * \brief Prints the Object + * @param os ostream to write to + * @param indent Indentation string to be prepended during printing + * @return + */ +void DicomDirStudy::Print(std::ostream &os, std::string const & ) +{ + os << "STUDY" << std::endl; + DicomDirObject::Print(os); + + for(ListDicomDirSerie::iterator cc = Series.begin(); + cc != Series.end(); + ++cc) + { + (*cc)->SetPrintLevel(PrintLevel); + (*cc)->Print(os); + } + + for(ListDicomDirVisit::iterator cc2 = Visits.begin(); + cc2 != Visits.end(); + ++cc2) + { + (*cc2)->SetPrintLevel(PrintLevel); + (*cc2)->Print(os); + } + +} + +//----------------------------------------------------------------------------- +} // end namespace gdcm diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmDicomDirStudy.h b/Utilities/ITK/Utilities/gdcm/src/gdcmDicomDirStudy.h new file mode 100644 index 0000000000000000000000000000000000000000..3c4a175adb9060f72ff5dccf311efb9c91030b0d --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmDicomDirStudy.h @@ -0,0 +1,109 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmDicomDirStudy.h,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:38 $ + Version: $Revision: 1.4 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#ifndef GDCMDICOMDIRSTUDY_H +#define GDCMDICOMDIRSTUDY_H + +#include "gdcmDicomDirObject.h" + +namespace gdcm +{ +class DicomDirSerie; +class DicomDirVisit; +//----------------------------------------------------------------------------- +typedef std::list<DicomDirSerie *> ListDicomDirSerie; + + +// For future use (Full DICOMDIR) +typedef std::list<DicomDirVisit *> ListDicomDirVisit; +/* +typedef std::list<DicomDirResult *> ListDicomDirResult; +typedef std::list<DicomDirStudyComponent *> ListDicomDirStudyComponent; +*/ +//----------------------------------------------------------------------------- +/** + * \brief describes a STUDY within a within a PATIENT + * (DicomDirPatient) of a given DICOMDIR (DicomDir) + */ +class GDCM_EXPORT DicomDirStudy : public DicomDirObject +{ +public: + DicomDirStudy(bool empty=false); + ~DicomDirStudy(); + + void Print(std::ostream &os = std::cout, std::string const &indent = "" ); + void WriteContent(std::ofstream *fp, FileType t); + + // 'Serie' methods + DicomDirSerie *NewSerie(); + /// Adds a gdcm::DicomDirSerie to a gdcm::DicomDirStudy + void AddSerie(DicomDirSerie *obj) { Series.push_back(obj); } + void ClearSerie(); + DicomDirSerie *GetFirstSerie(); + DicomDirSerie *GetNextSerie(); + DicomDirSerie *GetLastSerie(); + + // 'Visit' methods + DicomDirVisit *NewVisit(); + /// Adds a gdcm::DicomDirVisit to a gdcm::DicomDirStudy + void AddVisit(DicomDirVisit *obj) { Visits.push_back(obj); } + void ClearVisit(); + DicomDirVisit *GetFirstVisit(); + DicomDirVisit *GetNextVisit(); + DicomDirVisit *GetLastVisit(); + + // for future use (Full DICOMDIR) +/* + DicomDirResult *GetFirstResult(); + DicomDirResult *GetNextResult(); + DicomDirResult *GetLastResult(); + + DicomDirStudyComponent *GetFirstStudyComponent(); + DicomDirStudyComponent *GetNextStudyComponent(); + DicomDirStudyComponent *GetLastStudyComponent(); +*/ +private: + + /// chained list of DicomDirSeries (to be exploited hierarchicaly) + ListDicomDirSerie Series; + /// iterator on the DicomDirSeries of the current DicomDirStudy + ListDicomDirSerie::iterator ItSerie; + + /// chained list of DicomDirVisits(single level) + ListDicomDirVisit Visits; + /// iterator on the DicomDirVisits of the current DicomDirStudy + ListDicomDirVisit::iterator ItVisit; + + + // for future use (Full DICOMDIR) +/* + /// chained list of DicomDirResults(single level) + ListDicomDirResult Results; + /// iterator on the DicomDirResults of the current DicomDirStudy + ListDicomDirResult::iterator ItResult; + + /// chained list of DicomDirStudyComponents(single level) + ListDicomDirStudyComponent StudyComponents; + /// iterator on the DicomDirStudyComponents of the current DicomDirStudy + ListDicomDirStudyComponent::iterator ItStudyComponents; +*/ +}; +} // end namespace gdcm + +//----------------------------------------------------------------------------- +#endif diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmDicomDirVisit.cxx b/Utilities/ITK/Utilities/gdcm/src/gdcmDicomDirVisit.cxx new file mode 100644 index 0000000000000000000000000000000000000000..60f288070c41df4c8edc943010536af147f229f4 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmDicomDirVisit.cxx @@ -0,0 +1,86 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmDicomDirVisit.cxx,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:38 $ + Version: $Revision: 1.2 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#include "gdcmDicomDirVisit.h" +#include "gdcmValEntry.h" +#include "gdcmGlobal.h" + +namespace gdcm +{ +//----------------------------------------------------------------------------- +// Constructor / Destructor +/** + * \brief Constructor + * \note End user must use : DicomDirStudy::NewVisit() + */ +DicomDirVisit::DicomDirVisit(bool empty): + DicomDirObject() +{ + if ( !empty ) + { + ListDicomDirVisitElem const &elemList = + Global::GetDicomDirElements()->GetDicomDirVisitElements(); + FillObject(elemList); + } +} + +/** + * \brief Canonical destructor. + */ +DicomDirVisit::~DicomDirVisit() +{ +} + +//----------------------------------------------------------------------------- +// Public + +//----------------------------------------------------------------------------- +// Protected + +//----------------------------------------------------------------------------- +// Private + +//----------------------------------------------------------------------------- +// Print +/** + * \brief Prints the Object + * @param os ostream to write to + * @param indent Indentation string to be prepended during printing + * @return + */ +void DicomDirVisit::Print(std::ostream &os, std::string const & ) +{ + os << "VISIT : "; + for(ListDocEntry::iterator i = DocEntries.begin(); + i!= DocEntries.end(); + ++i) + { + if ( (*i)->GetGroup() == 0x0004 && (*i)->GetElement() == 0x1500 ) + { + if( dynamic_cast<ValEntry *>(*i) ) + os << (dynamic_cast<ValEntry *>(*i))->GetValue(); + } + } + os << std::endl; + + DicomDirObject::Print(os); +} + +//----------------------------------------------------------------------------- +} // end namespace gdcm + diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmDicomDirVisit.h b/Utilities/ITK/Utilities/gdcm/src/gdcmDicomDirVisit.h new file mode 100644 index 0000000000000000000000000000000000000000..fdb34ecd8e8732669d648e1869726f82fda52ddc --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmDicomDirVisit.h @@ -0,0 +1,43 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmDicomDirVisit.h,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:38 $ + Version: $Revision: 1.2 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#ifndef GDCMDICOMDIRVISIT_H +#define GDCMDICOMDIRVISIT_H + +#include "gdcmDicomDirObject.h" + +namespace gdcm +{ + +/** + * \brief describes a VISIT within a within a STUDY + * (DicomDirStudy) of a given DICOMDIR (DicomDir) + */ +class GDCM_EXPORT DicomDirVisit : public DicomDirObject +{ +public: + DicomDirVisit(bool empty=false); + ~DicomDirVisit(); + + void Print( std::ostream &os = std::cout, std::string const &indent = "" ); + // void WriteContent( std::ofstream *fp, FileType t ); + +}; +} // end namespace gdcm +//----------------------------------------------------------------------------- +#endif diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmDict.cxx b/Utilities/ITK/Utilities/gdcm/src/gdcmDict.cxx new file mode 100644 index 0000000000000000000000000000000000000000..16a2017662b8d92e886f413394e36989331a5f62 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmDict.cxx @@ -0,0 +1,334 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmDict.cxx,v $ + Language: C++ + Date: $Date: 2006/02/20 15:56:57 $ + Version: $Revision: 1.8 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#include "gdcmDict.h" +#include "gdcmUtil.h" +#include "gdcmDebug.h" + +#include <fstream> +#include <iostream> +#include <iomanip> + +namespace gdcm +{ +//----------------------------------------------------------------------------- +/// \brief auto generated function, to fill up the Dicom Dictionnary, +/// if relevant file is not found on user's disk +void FillDefaultDataDict(Dict *d); + +//----------------------------------------------------------------------------- +// Constructor / Destructor +/** + * \brief Constructor + */ +Dict::Dict( ) +{ + Filename=""; +} + +/** + * \brief Constructor + * @param filename from which to build the dictionary. + */ +Dict::Dict(std::string const &filename) +{ + + std::ifstream from( filename.c_str() ); + if ( !from ) + { + gdcmWarningMacro( "Can't open dictionary" << filename.c_str()); + // Using default embeded one: + FillDefaultDataDict( this ); + } + else + { + DoTheLoadingJob(from); + Filename = filename; + } +} + +/** + * \brief Destructor + */ +Dict::~Dict() +{ + ClearEntry(); +} + +//----------------------------------------------------------------------------- +// Public + +/** + * \brief Add a all the entries held in a source dictionary + * \note it concerns only Private Dictionnary + * @param filename from which to build the dictionary. + */ +bool Dict::AddDict(std::string const &filename) +{ + + std::ifstream from( filename.c_str() ); + if ( !from ) + { + gdcmWarningMacro( "Can't open dictionary" << filename.c_str()); + return false; + } + else + { + DoTheLoadingJob(from); + return true; + } +} + + +/** + * \brief Removes from the current Dicom Dict all the entries held in a source dictionary + * \note it concerns only Private Dictionnary + * @param filename from which we read the entries to remove. + */ +bool Dict::RemoveDict(std::string const &filename) +{ + std::ifstream from( filename.c_str() ); + if ( !from ) + { + gdcmWarningMacro( "Can't open dictionary" << filename.c_str()); + return false; + } + else + { + uint16_t group; + uint16_t elem; + TagName vr; + TagName vm; + TagName name; + + while (!from.eof() && from) + { + from >> std::hex; + from >> group; + from >> elem; + from >> vr; + from >> vm; + // from >> std::ws; //remove white space + std::getline(from, name); + + RemoveEntry(DictEntry::TranslateToKey(group, elem)); + } + from.close(); + return true; + } +} + +/** + * \brief adds a new Dicom Dictionary Entry + * @param newEntry entry to add + * @return false if Dicom Element already exists + */ +bool Dict::AddEntry(DictEntry const &newEntry) +{ + const TagKey &key = newEntry.GetKey(); + + if ( KeyHt.count(key) == 1 ) + { + gdcmErrorMacro( "Already present:" << key ); + return false; + } + else + { + KeyHt.insert( TagKeyHT::value_type(newEntry.GetKey(), newEntry)); + return true; + } +} + +/** + * \brief replaces an already existing Dicom Element by a new one + * @param newEntry new entry (overwrites any previous one with same tag) + * @return false if Dicom Element doesn't exist + */ +bool Dict::ReplaceEntry(DictEntry const &newEntry) +{ + if ( RemoveEntry(newEntry.GetKey()) ) + { + KeyHt.insert( TagKeyHT::value_type(newEntry.GetKey(), newEntry)); + return true; + } + return false; +} + +/** + * \brief removes an already existing Dicom Dictionary Entry, + * identified by its Tag + * @param key (group|element) + * @return false if Dicom Dictionary Entry doesn't exist + */ +bool Dict::RemoveEntry(TagKey const &key) +{ + TagKeyHT::const_iterator it = KeyHt.find(key); + if ( it != KeyHt.end() ) + { + KeyHt.erase(key); + + return true; + } + else + { + gdcmWarningMacro( "Unfound entry" << key ); + return false; + } +} + +/** + * \brief removes an already existing Dicom Dictionary Entry, + * identified by its group,element number + * @param group Dicom group number of the Dicom Element + * @param elem Dicom element number of the Dicom Element + * @return false if Dicom Dictionary Entry doesn't exist + */ +bool Dict::RemoveEntry(uint16_t group, uint16_t elem) +{ + return RemoveEntry(DictEntry::TranslateToKey(group, elem)); +} + +/** + * \brief Remove all Dicom Dictionary Entries + */ +void Dict::ClearEntry() +{ + // we assume all the pointed DictEntries are already cleaned-up + // when we clean KeyHt. + KeyHt.clear(); +} + +/** + * \brief Get the dictionary entry identified by a given tag ("group|element") + * @param key tag of the searched entry + * @return the corresponding dictionary entry when existing, NULL otherwise + */ +DictEntry *Dict::GetEntry(TagKey const &key) +{ + TagKeyHT::iterator it = KeyHt.find(key); + if ( it == KeyHt.end() ) + { + return 0; + } + return &(it->second); +} + +/** + * \brief Get the dictionary entry identified by it's "group" and "element") + * @param group Group number of the searched entry. + * @param elem Element number of the searched entry. + * @return the corresponding dictionary entry when existing, NULL otherwise + */ +DictEntry *Dict::GetEntry(uint16_t group, uint16_t elem) +{ + TagKey key = DictEntry::TranslateToKey(group, elem); + TagKeyHT::iterator it = KeyHt.find(key); + if ( it == KeyHt.end() ) + { + return 0; + } + return &(it->second); +} + +/** + * \brief Get the first entry while visiting the Dict entries + * \return The first DicEntry if found, otherwhise NULL + */ +DictEntry *Dict::GetFirstEntry() +{ + ItKeyHt = KeyHt.begin(); + if ( ItKeyHt != KeyHt.end() ) + return &(ItKeyHt->second); + return NULL; +} + +/** + * \brief Get the next entry while visiting the Hash table (KeyHt) + * \note : meaningfull only if GetFirstEntry already called + * \return The next DictEntry if found, otherwhise NULL + */ +DictEntry *Dict::GetNextEntry() +{ + gdcmAssertMacro (ItKeyHt != KeyHt.end()); + + ++ItKeyHt; + if (ItKeyHt != KeyHt.end()) + return &(ItKeyHt->second); + return NULL; +} + +//----------------------------------------------------------------------------- +// Protected + +//----------------------------------------------------------------------------- +// Private +/** + * \brief Add all the dictionary entries from an already open source file + * @param from input stream to read from. + */ +void Dict::DoTheLoadingJob(std::ifstream &from) +{ + uint16_t group; + uint16_t elem; + TagName vr; + TagName vm; + TagName name; + + while (!from.eof() && from) + { + from >> std::hex; + from >> group; + from >> elem; + from >> vr; + from >> vm; + from >> std::ws; //remove white space + std::getline(from, name); + + const DictEntry newEntry(group, elem, vr, vm, name); + AddEntry(newEntry); + } + from.close(); +} +//----------------------------------------------------------------------------- +// Print +/** + * \brief Print all the dictionary entries contained in this dictionary. + * Entries will be sorted by tag i.e. the couple (group, element). + * @param os The output stream to be written to. + * @param indent Indentation string to be prepended during printing + */ +void Dict::Print(std::ostream &os, std::string const & ) +{ + os << "Dict file name : " << Filename << std::endl; + itksys_ios::ostringstream s; + + for (TagKeyHT::iterator tag = KeyHt.begin(); tag != KeyHt.end(); ++tag) + { + s << "Entry : "; + s << "(" << std::hex << std::setw(4) << tag->second.GetGroup() << ','; + s << std::hex << std::setw(4) << tag->second.GetElement() << ") = " + << std::dec; + s << tag->second.GetVR() << ", "; + s << tag->second.GetVM() << ", "; + s << tag->second.GetName() << "." << std::endl; + } + os << s.str(); +} + +//----------------------------------------------------------------------------- +} // end namespace gdcm diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmDict.h b/Utilities/ITK/Utilities/gdcm/src/gdcmDict.h new file mode 100644 index 0000000000000000000000000000000000000000..33d0935f5041bcc0aa3659348e9e6136cd6dbd01 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmDict.h @@ -0,0 +1,86 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmDict.h,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:38 $ + Version: $Revision: 1.4 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#ifndef GDCMDICT_H +#define GDCMDICT_H + +#include "gdcmBase.h" +#include "gdcmDictEntry.h" + +#include <iostream> +#include <fstream> // for ifstream +#include <list> +#include <map> + +namespace gdcm +{ + +//----------------------------------------------------------------------------- +typedef std::string DictKey; +typedef std::map<TagKey, DictEntry> TagKeyHT; +//----------------------------------------------------------------------------- +/** + * \brief Dict acts a memory representation of a dicom dictionary i.e. + * it is a container for a collection of dictionary entries. + * The dictionary is loaded from in an ascii file. + * There should be a single public dictionary (THE dictionary of + * the actual DICOM v3) but as many shadow dictionaries as imagers + * combined with all software versions... + * \see DictSet + */ +class GDCM_EXPORT Dict : public Base +{ +public: + Dict(); + Dict(std::string const &filename); + ~Dict(); + + bool AddDict(std::string const &filename); + bool RemoveDict(std::string const &filename); +// Print + void Print(std::ostream &os = std::cout, std::string const &indent = ""); + +// Entries + bool AddEntry(DictEntry const &newEntry); + bool ReplaceEntry(DictEntry const &newEntry); + bool RemoveEntry (TagKey const &key); + bool RemoveEntry (uint16_t group, uint16_t elem); + void ClearEntry(); + +// Tag + DictEntry *GetEntry(uint16_t group, uint16_t elem); + DictEntry *GetEntry(TagKey const &key); + + DictEntry *GetFirstEntry(); + DictEntry *GetNextEntry(); + +private: + void DoTheLoadingJob(std::ifstream &ifs); + + /// ASCII file holding the Dictionnary + std::string Filename; + + /// Access through TagKey + TagKeyHT KeyHt; + /// Iterator for the entries + TagKeyHT::iterator ItKeyHt; +}; +} // end namespace gdcm + +//----------------------------------------------------------------------------- +#endif diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmDictEntry.cxx b/Utilities/ITK/Utilities/gdcm/src/gdcmDictEntry.cxx new file mode 100644 index 0000000000000000000000000000000000000000..e4af35dbf00fc6558df7d42e0cd92e413967a890 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmDictEntry.cxx @@ -0,0 +1,152 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmDictEntry.cxx,v $ + Language: C++ + Date: $Date: 2006/02/20 15:56:57 $ + Version: $Revision: 1.6 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#include "gdcmDictEntry.h" +#include "gdcmDebug.h" +#include "gdcmUtil.h" + +#include <iomanip> // for std::ios::left, ... +#include <fstream> +#include <stdio.h> // for sprintf + +namespace gdcm +{ +//----------------------------------------------------------------------------- +// Constructor / Destructor +/** + * \brief Constructor + * @param group DICOM-Group Number + * @param elem DICOM-Element Number + * @param vr Value Representation + * @param vm Value Multiplicity + * @param name description of the element +*/ + +DictEntry::DictEntry(uint16_t group, uint16_t elem, + TagName const &vr, + TagName const &vm, + TagName const &name) +{ + Group = group; + Element = elem; + VR = vr; + VM = vm; + Name = name; + Key = TranslateToKey(group, elem); +} + +//----------------------------------------------------------------------------- +// Public +/** + * \brief If-and only if-the V(alue) R(epresentation) + * \ is unset then overwrite it. + * @param vr New V(alue) R(epresentation) to be set. + */ +void DictEntry::SetVR(TagName const &vr) +{ + if ( IsVRUnknown() ) + { + VR = vr; + } + else + { + gdcmErrorMacro( "Overwriting VR might compromise a dictionary"); + } +} + +/** + * \brief If-and only if-the V(alue) M(ultiplicity) + * \ is unset then overwrite it. + * @param vm New V(alue) M(ultiplicity) to be set. + */ +void DictEntry::SetVM(TagName const &vm) +{ + if ( IsVMUnknown() ) + { + VM = vm; + } + else + { + gdcmErrorMacro( "Overwriting VM might compromise a dictionary"); + } +} + +/** + * \brief concatenates 2 uint16_t (supposed to be a Dicom group number + * and a Dicom element number) + * @param group the Dicom group number used to build the tag + * @param elem the Dicom element number used to build the tag + * @return the built tag + */ +TagKey DictEntry::TranslateToKey(uint16_t group, uint16_t elem) +{ + // according to 'Purify', TranslateToKey is one of the most + // time consuming methods. + // Let's try to shorten it ! + + //return Util::Format("%04x|%04x", group, elem); // too much time ! +#if FASTTAGKEY + TagKey r; + r.tab[0] = group; + r.tab[1] = elem; + return r; +#else + char res[10]; + sprintf(res,"%04x|%04x", group, elem); + return res; +#endif +} + +//----------------------------------------------------------------------------- +// Protected + +//----------------------------------------------------------------------------- +// Private + +//----------------------------------------------------------------------------- +// Print +/** + * \brief Prints an entry of the Dicom DictionaryEntry + * @param os ostream we want to print in + * @param indent Indentation string to be prepended during printing + */ +void DictEntry::Print(std::ostream &os, std::string const & ) +{ + std::string vr; + itksys_ios::ostringstream s; + + vr = GetVR(); + if ( vr==GDCM_UNKNOWN ) + vr=" "; + + s << DictEntry::TranslateToKey(GetGroup(),GetElement()); + s << " [" << vr << "] "; + + if ( PrintLevel >= 1 ) + { + s.setf(std::ios::left); + s << std::setw(66-GetName().length()) << " "; + } + + s << "[" << GetName()<< "]"; + os << s.str() << std::endl; +} + +//----------------------------------------------------------------------------- +} // end namespace gdcm + diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmDictEntry.h b/Utilities/ITK/Utilities/gdcm/src/gdcmDictEntry.h new file mode 100644 index 0000000000000000000000000000000000000000..24bb9f8963f84fcc333d3c519ad19a77f5ada179 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmDictEntry.h @@ -0,0 +1,175 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmDictEntry.h,v $ + Language: C++ + Date: $Date: 2006/02/20 17:53:28 $ + Version: $Revision: 1.5 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#ifndef GDCMDICTENTRY_H +#define GDCMDICTENTRY_H + +#include "gdcmBase.h" + +namespace gdcm +{ +//----------------------------------------------------------------------------- +/** + * \brief + * the DictEntry in an element contained by the Dict. + * It contains : + * - the key referenced by the DICOM norm or the constructor (for private keys) + * i.e. the Group number + * the Element number + * - the VR (Value Representation) + * - the VM (Value Multiplicity) + * - the corresponding name in english + */ +class GDCM_EXPORT DictEntry : public Base +{ +public: + DictEntry(uint16_t group, + uint16_t elem, + TagName const &vr = GDCM_UNKNOWN, + TagName const &vm = GDCM_UNKNOWN, + TagName const &name = GDCM_UNKNOWN); + +// Print + void Print(std::ostream &os = std::cout, std::string const &indent = ""); + +// Content of DictEntry + void SetVR(TagName const &vr); + void SetVM(TagName const &vm); + + /// \brief tells if the V(alue) R(epresentation) is known (?!) + /// @return + bool IsVRUnknown() { return VR == GDCM_UNKNOWN; } + + /// \brief tells if the V(alue) M(ultiplicity) is known (?!) + /// @return + bool IsVMUnknown() { return VM == GDCM_UNKNOWN; } + + /// \brief Returns the Dicom Group Number of the current DictEntry + /// @return the Dicom Group Number + uint16_t GetGroup() const { return Group; } + + /// \brief Returns the Dicom Element Number of the current DictEntry + /// @return the Dicom Element Number + uint16_t GetElement() const { return Element; } + + /// \brief Returns the Dicom Value Representation of the current + /// DictEntry + /// @return the Dicom Value Representation + const TagName &GetVR() const { return VR; } + + /// \brief sets the key of the current DictEntry + /// @param k New key to be set. + void SetKey(TagKey const &k) { Key = k; } + + /// \brief returns the VM field of the current DictEntry + /// @return The 'Value Multiplicity' field + const TagName &GetVM() const { return VM; } + + /// \brief Returns the Dicom Name of the current DictEntry + /// e.g. "Patient Name" for Dicom Tag (0x0010, 0x0010) + /// @return the Dicom Name + const TagName &GetName() const { return Name; } + + /// \brief Gets the key of the current DictEntry + /// @return the key. + const TagKey &GetKey() const { return Key; } + +// Key creation + static TagKey TranslateToKey(uint16_t group, uint16_t elem); + +private: + /// \todo FIXME + /// where are the group and elem used except from building up + /// a TagKey. If the answer is nowhere then there is no need + /// to store the group and elem independently. + /// + /// --> EVERYWHERE ! The alternate question would be : + /// What's TagKey used for ? + + /// DicomGroup number + uint16_t Group; // e.g. 0x0010 + + /// DicomElement number + uint16_t Element; // e.g. 0x0103 + + /// \brief Value Representation i.e. some clue about the nature + /// of the data represented e.g. + /// "FD" short for "Floating Point Double"(see \ref VR) + /// "PN" short for "Person Name" + TagName VR; + + /* + * . + * Formerly 'Group name abbreviations' + * Here is a small dictionary we encountered in "nature": + * - CMD Command + * - META Meta Information + * - DIR Directory + * - ID ??? + * - PAT Patient + * - ACQ Acquisition + * - REL Related + * - IMG Image + * - SDY Study + * - VIS Visit + * - WAV Waveform + * - PRC ??? + * - DEV Device + * - NMI Nuclear Medicine + * - MED ??? + * - BFS Basic Film Session + * - BFB Basic Film Box + * - BIB Basic Image Box + * - BAB + * - IOB + * - PJ + * - PRINTER + * - RT Radio Therapy + * - DVH + * - SSET + * - RES Results + * - CRV Curve + * - OLY Overlays + * - PXL Pixels + * - DL Delimiters + * . + * + * Other usefull abreviations used for Radiographic view associated with + * Patient Position (0018,5100): + * - AP = Anterior/Posterior + * - PA = Posterior/Anterior + * - LL = Left Lateral + * - RL = Right Lateral + * - RLD = Right Lateral Decubitus + * - LLD = Left Lateral Decubitus + * - RLO = Right Lateral Oblique + * - LLO = Left Lateral Oblique + * . + */ + /// \brief Value Multiplicity (e.g. "1", "1-n", "6") + TagName VM; + + /// \brief English name of the entry (e.g. "Patient's Name") + TagName Name; + + /// Redundant with (group, elem) but we add it for efficiency purpose. + TagKey Key; +}; +} // end namespace gdcm +//----------------------------------------------------------------------------- +#endif diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmDictGroupName.cxx b/Utilities/ITK/Utilities/gdcm/src/gdcmDictGroupName.cxx new file mode 100644 index 0000000000000000000000000000000000000000..784ce9842902365d08b019627491f5aa946ecd87 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmDictGroupName.cxx @@ -0,0 +1,119 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmDictGroupName.cxx,v $ + Language: C++ + Date: $Date: 2006/02/20 15:56:57 $ + Version: $Revision: 1.3 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#include "gdcmDictGroupName.h" +#include "gdcmUtil.h" +#include "gdcmDictSet.h" +#include "gdcmDebug.h" + +#include <fstream> +#include <iostream> +#include <iomanip> + +namespace gdcm +{ +//----------------------------------------------------------------------------- +/// \brief auto generated function, to fill up the 'Group Name' +/// Dictionnary, if relevant file is not found on user's disk +void FillDefaultDictGroupName(DictGroupNameHT &groupName); + +//----------------------------------------------------------------------------- +// Constructor / Destructor +/** + * \brief Constructor + */ +DictGroupName::DictGroupName() +{ + std::string filename = DictSet::BuildDictPath() + DICT_GROUP_NAME; + std::ifstream from(filename.c_str()); + if ( !from ) + { + gdcmWarningMacro("Can't open dictionary" << filename.c_str()); + FillDefaultDictGroupName(groupName); + } + else + { + char buff[1024]; + uint16_t key; + TagName value; + + while (!from.eof()) + { + from >> std::ws; + from >> std::hex; + from >> key; + from >> std::ws; + from.getline(buff, 1024, '"'); + from.getline(buff, 1024, '"'); + value = buff; + if ( !from.eof() ) + groupName[key] = value; + + from.getline(buff, 1024, '\n'); + } + from.close(); + } +} + +/** + * \brief Destructor + */ +DictGroupName::~DictGroupName() +{ + groupName.clear(); +} + +//----------------------------------------------------------------------------- +// Public +/// \returns the formerly NIH defined ACR-NEMA group name +const TagName &DictGroupName::GetName(uint16_t group) +{ + DictGroupNameHT::const_iterator it = groupName.find(group); + if ( it == groupName.end() ) + { + return GDCM_UNFOUND; + } + return it->second; +} + +//----------------------------------------------------------------------------- +// Protected + +//----------------------------------------------------------------------------- +// Private + +//----------------------------------------------------------------------------- +// Print +/** + * \brief Print all + * @param os The output stream to be written to. + */ +void DictGroupName::Print(std::ostream &os,std::string const &) +{ + itksys_ios::ostringstream s; + + for (DictGroupNameHT::iterator it = groupName.begin(); it != groupName.end(); ++it) + { + s << "DictGroupName : 0x" << std::hex << std::setw(4) << it->first + << std::dec << " = " << it->second << std::endl; + } + os << s.str(); +} + +//----------------------------------------------------------------------------- +} // end namespace gdcm diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmDictGroupName.h b/Utilities/ITK/Utilities/gdcm/src/gdcmDictGroupName.h new file mode 100644 index 0000000000000000000000000000000000000000..00a82f63ca8ac8055dcd3ac1f071c1236bb4d35f --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmDictGroupName.h @@ -0,0 +1,57 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmDictGroupName.h,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:38 $ + Version: $Revision: 1.2 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#ifndef GDCMDICTGROUPNAME_H +#define GDCMDICTGROUPNAME_H + +#include "gdcmCommon.h" +#include <map> +#include <string> +#include <iostream> + +namespace gdcm +{ + +//----------------------------------------------------------------------------- +/// Group Name Hash Table +typedef std::map<uint16_t, TagName> DictGroupNameHT; + +//----------------------------------------------------------------------------- +/** + * \brief Container for dicom 'Group Name' Hash Table. + * (formerly NIH defined ACR-NEMA group name) + * \note This is a singleton + */ +class GDCM_EXPORT DictGroupName +{ +public: + DictGroupName(void); + ~DictGroupName(); + + void Print(std::ostream &os = std::cout, + std::string const &indent = "" ); + + const TagName &GetName(uint16_t group); + +private: + DictGroupNameHT groupName; +}; +} // end namespace gdcm + +//----------------------------------------------------------------------------- +#endif diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmDictSet.cxx b/Utilities/ITK/Utilities/gdcm/src/gdcmDictSet.cxx new file mode 100644 index 0000000000000000000000000000000000000000..aff47d49c31a3acc2298302db6a30112b99b2fa6 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmDictSet.cxx @@ -0,0 +1,240 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmDictSet.cxx,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:38 $ + Version: $Revision: 1.6 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#include "gdcmDictSet.h" +#include "gdcmDebug.h" +#include <fstream> +#include <stdlib.h> // For getenv +#include <stdio.h> // For sprintf + +namespace gdcm +{ + +//----------------------------------------------------------------------------- +// Constructor / Destructor +/** + * \brief The Dictionary Set obtained with this constructor simply + * contains the Default Public dictionary. + */ +DictSet::DictSet() +{ + DictPath = BuildDictPath(); + std::string pubDictFile(DictPath); + pubDictFile += PUB_DICT_FILENAME; + Dicts[PUB_DICT_NAME] = new Dict(pubDictFile); +} + +/** + * \brief Destructor + */ +DictSet::~DictSet() +{ + // Remove dictionaries + for (DictSetHT::iterator tag = Dicts.begin(); tag != Dicts.end(); ++tag) + { + Dict *entryToDelete = tag->second; + if ( entryToDelete ) + { + delete entryToDelete; + } + tag->second = NULL; + } + Dicts.clear(); + + // Remove virtual dictionary entries + VirtualEntries.clear(); +} + +//----------------------------------------------------------------------------- +// Public +/** + * \brief Loads a dictionary from a specified file, and add it + * to already the existing ones contained in this DictSet. + * @param filename Absolute or relative filename containing the + * dictionary to load. + * @param name Symbolic name that be used as identifier of the newly + * created dictionary. + */ +Dict *DictSet::LoadDictFromFile(std::string const &filename, + DictKey const &name) +{ + Dict *newDict = new Dict(filename); + AppendDict(newDict, name); + + return newDict; +} + +/** + * \brief Retrieve the specified dictionary (when existing) from this + * DictSet. + * @param dictName The symbolic name of the searched dictionary. + * \result The retrieved dictionary. + */ +Dict *DictSet::GetDict(DictKey const &dictName) +{ + DictSetHT::iterator dict = Dicts.find(dictName); + if ( dict != Dicts.end() ) + { + return dict->second; + } + return NULL; +} + +/** + * \brief Create a DictEntry which will be referenced in no dictionary + * @param group Group number of the Entry + * @param elem Element number of the Entry + * @param vr Value Representation of the Entry + * @param vm Value Multiplicity of the Entry + * @param name English name of the Entry + * @return virtual entry + */ +DictEntry *DictSet::NewVirtualDictEntry( uint16_t group, + uint16_t elem, + TagName vr, + TagName vm, + TagName name) +{ + DictEntry *entry; + + // Let's follow 'Purify' advice + // + // const std::string tag = DictEntry::TranslateToKey(group,elem) + // + "#" + vr + "#" + vm + "#" + name; +#if FASTTAGKEY && 0 + // FIXME + TagKey tag; + tag.tab[0] = group; + tag.tab[1] = elem; +#else + char res[10]; + sprintf(res,"%04x|%04x", group, elem); + ExtendedTagKey tag = res; + tag += "#" + vr + "#" + vm + "#" + name; +#endif + + ExtendedTagKeyHT::iterator it; + + it = VirtualEntries.find(tag); + if ( it != VirtualEntries.end() ) + { + entry = &(it->second); + } + else + { + DictEntry ent(group, elem, vr, vm, name); + VirtualEntries.insert( + ExtendedTagKeyHT::value_type(tag, ent) ); + entry = &(VirtualEntries.find(tag)->second); + } + + return entry; +} + +/** + * \brief Get the first entry while visiting the DictSet + * \return The first Dict if found, otherwhise NULL + */ +Dict *DictSet::GetFirstEntry() +{ + ItDictHt = Dicts.begin(); + if ( ItDictHt != Dicts.end() ) + return ItDictHt->second; + return NULL; +} + +/** + * \brief Get the next entry while visiting the Hash table (DictSetHT) + * \note : meaningfull only if GetFirstEntry already called + * \return The next Dict if found, otherwhise NULL + */ +Dict *DictSet::GetNextEntry() +{ + gdcmAssertMacro (ItDictHt != Dicts.end()); + + ++ItDictHt; + if ( ItDictHt != Dicts.end() ) + return ItDictHt->second; + return NULL; +} + +/** + * \brief Obtain from the GDCM_DICT_PATH environnement variable the + * path to directory containing the dictionaries. When + * the environnement variable is absent the path is defaulted + * to "../Dicts/". + * @return path to directory containing the dictionaries + */ +std::string DictSet::BuildDictPath() +{ + std::string resultPath; + const char *envPath; + envPath = getenv("GDCM_DICT_PATH"); + + if (envPath && (strlen(envPath) != 0)) + { + resultPath = envPath; + gdcmWarningMacro( "Dictionary path set from environnement"); + } + else + { + resultPath = PUB_DICT_PATH; + } + if ( resultPath[resultPath.length()-1] != '/' ) + { + resultPath += '/'; + } + + return resultPath; +} + +//----------------------------------------------------------------------------- +// Protected +/** + * \brief Adds a Dictionary to a DictSet + * \return always true + */ +bool DictSet::AppendDict(Dict *newDict, DictKey const &name) +{ + Dicts[name] = newDict; + + return true; +} + +//----------------------------------------------------------------------------- +// Private + +//----------------------------------------------------------------------------- +// Print +/** + * \brief Print, in an informal fashion, the list of all the dictionaries + * contained is this DictSet, along with their respective content. + * @param os Output stream used for printing. + * @param indent Indentation string to be prepended during printing + */ +void DictSet::Print(std::ostream &os, std::string const & ) +{ + for (DictSetHT::iterator dict = Dicts.begin(); dict != Dicts.end(); ++dict) + { + os << "Printing dictionary " << dict->first << std::endl; + dict->second->Print(os); + } +} + +//----------------------------------------------------------------------------- +} // end namespace gdcm diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmDictSet.h b/Utilities/ITK/Utilities/gdcm/src/gdcmDictSet.h new file mode 100644 index 0000000000000000000000000000000000000000..fcaadf5c20e40285fcda1391c0e9368dbcba94dd --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmDictSet.h @@ -0,0 +1,94 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmDictSet.h,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:38 $ + Version: $Revision: 1.4 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#ifndef GDCMDICTSET_H +#define GDCMDICTSET_H + +#include "gdcmBase.h" +#include "gdcmDict.h" + +#include <map> +#include <list> + +namespace gdcm +{ +//----------------------------------------------------------------------------- +typedef std::map<DictKey, Dict*> DictSetHT; +typedef std::string ExtendedTagKey; +typedef std::map<ExtendedTagKey, DictEntry> ExtendedTagKeyHT; + +//----------------------------------------------------------------------------- +/** + * \brief Container for managing a set of loaded dictionaries (Dict). + * \note Hopefully, sharing dictionaries should avoid + * - reloading an already loaded dictionary (saving time) + * - having many in memory representations of the same dictionary + * (saving memory). + */ +class GDCM_EXPORT DictSet : public Base +{ +public: + DictSet(); + ~DictSet(); + + void Print(std::ostream &os = std::cout, std::string const &indent = "" ); + + // Probabely useless ! + //EntryNamesList *GetPubDictEntryNames(); + //EntryNamesByCatMap *GetPubDictEntryNamesByCategory(); + + Dict *LoadDictFromFile( std::string const &fileName, + DictKey const &name ); + + Dict *GetDict( DictKey const &DictName ); + + /// \brief Returns the default reference DICOM V3 public dictionary. + Dict* GetDefaultPubDict() { return GetDict(PUB_DICT_NAME); } + + // \ brief Returns the virtual references DICOM dictionary. + // \ warning : not end user intended + // Dict *GetVirtualDict() { return &VirtualEntries; } + + DictEntry *NewVirtualDictEntry(uint16_t group, uint16_t elem, + TagName vr = GDCM_UNKNOWN, + TagName vm = GDCM_UNKNOWN, + TagName name = GDCM_UNKNOWN); + + Dict *GetFirstEntry(); + Dict *GetNextEntry(); + + static std::string BuildDictPath(); + +protected: + bool AppendDict(Dict *NewDict, DictKey const &name); + +private: + /// Hash table of all dictionaries contained in this DictSet + DictSetHT Dicts; + DictSetHT::iterator ItDictHt; + + /// Directory path to dictionaries + std::string DictPath; + + /// H table for the on the fly created DictEntries + ExtendedTagKeyHT VirtualEntries; +}; +} // end namespace gdcm + +//----------------------------------------------------------------------------- +#endif diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmDirList.cxx b/Utilities/ITK/Utilities/gdcm/src/gdcmDirList.cxx new file mode 100644 index 0000000000000000000000000000000000000000..5dedd89ea349cf15d8e7be37fb8472b9885d7127 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmDirList.cxx @@ -0,0 +1,208 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmDirList.cxx,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:38 $ + Version: $Revision: 1.7 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#include "gdcmDirList.h" +#include "gdcmUtil.h" +#include "gdcmDebug.h" + +#include <iterator> +#include <assert.h> +#include <errno.h> +#include <sys/stat.h> //stat function + +#ifdef _MSC_VER + #include <windows.h> + #include <direct.h> +#else + #include <dirent.h> + #include <sys/types.h> +#endif + +namespace gdcm +{ +//----------------------------------------------------------------------------- +// Constructor / Destructor +/** + * \brief Constructor + * @param dirName root directory name + * @param recursive whether we want to explore recursively or not + */ +DirList::DirList(std::string const &dirName, bool recursive) +{ + DirName = dirName; + Explore(dirName, recursive); +} + +/** + * \brief Destructor + */ +DirList::~DirList() +{ +} + +//----------------------------------------------------------------------------- +// Public +/** + * \brief Tells us if file name corresponds to a Directory + * @param dirName file name to check + * @return true if the file IS a Directory + */ +bool DirList::IsDirectory(std::string const &dirName) +{ + struct stat fs; + assert( dirName[dirName.size()-1] != '/' ); + if ( stat(dirName.c_str(), &fs) == 0 ) + { +#if _WIN32 + return ((fs.st_mode & _S_IFDIR) != 0); +#else + return S_ISDIR(fs.st_mode); +#endif + } + else + { + const char *str = strerror(errno); + gdcmErrorMacro( str ); + return false; + } +} + +//----------------------------------------------------------------------------- +// Protected + +//----------------------------------------------------------------------------- +// Private +/** + * \brief Explore a directory with possibility of recursion + * return number of files read + * @param dirpath directory to explore + * @param recursive whether we want recursion or not + */ +int DirList::Explore(std::string const &dirpath, bool recursive) +{ + int numberOfFiles = 0; + std::string fileName; + std::string dirName = Util::NormalizePath(dirpath); +#ifdef _MSC_VER + WIN32_FIND_DATA fileData; + //assert( dirName[dirName.size()-1] == '' ); + HANDLE hFile = FindFirstFile((dirName+"*").c_str(), &fileData); + + for(BOOL b = (hFile != INVALID_HANDLE_VALUE); b; + b = FindNextFile(hFile, &fileData)) + { + fileName = fileData.cFileName; + if ( fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) + { + // Need to check for . and .. to avoid infinite loop + if ( fileName != "." && fileName != ".." && recursive ) + { + numberOfFiles += Explore(dirName+fileName,recursive); + } + } + else + { + Filenames.push_back(dirName+fileName); + numberOfFiles++; + } + } + DWORD dwError = GetLastError(); + if (hFile != INVALID_HANDLE_VALUE) + FindClose(hFile); + if (dwError != ERROR_NO_MORE_FILES) + { + LPVOID lpMsgBuf; + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER| + FORMAT_MESSAGE_FROM_SYSTEM| + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL,GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPTSTR) &lpMsgBuf,0,NULL); + + gdcmErrorMacro("FindNextFile error. Error is " << (char *)lpMsgBuf + <<" for the directory : "<<dirName); + return -1; + } + +#else + // Real POSIX implementation: scandir is a BSD extension only, and doesn't + // work on debian for example + + DIR* dir = opendir(dirName.c_str()); + if (!dir) + { + return 0; + } + + // According to POSIX, the dirent structure contains a field char d_name[] + // of unspecified size, with at most NAME_MAX characters preceeding the + // terminating null character. Use of other fields will harm the porta- + // bility of your programs. + + struct stat buf; + dirent *d; + for (d = readdir(dir); d; d = readdir(dir)) + { + fileName = dirName + d->d_name; + if( stat(fileName.c_str(), &buf) != 0 ) + { + const char *str = strerror(errno); + gdcmErrorMacro( str ); + } + if ( S_ISREG(buf.st_mode) ) //is it a regular file? + { + Filenames.push_back( fileName ); + numberOfFiles++; + } + else if ( S_ISDIR(buf.st_mode) ) //directory? + { + if ( d->d_name[0] != '.' && recursive ) //we also skip hidden files + { + numberOfFiles += Explore( fileName, recursive); + } + } + else + { + gdcmErrorMacro( "Unexpected error" ); + return -1; + } + } + if( closedir(dir) != 0 ) + { + const char *str = strerror(errno); + gdcmErrorMacro( str ); + } +#endif + + return numberOfFiles; +} + +//----------------------------------------------------------------------------- +// Print +/** + * \brief Print method + * @param os ostream to write to + */ +void DirList::Print(std::ostream &os, std::string const &) +{ + std::copy(Filenames.begin(), Filenames.end(), + std::ostream_iterator<std::string>(os, "\n")); +} + +//----------------------------------------------------------------------------- +} // end namespace gdcm diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmDirList.h b/Utilities/ITK/Utilities/gdcm/src/gdcmDirList.h new file mode 100644 index 0000000000000000000000000000000000000000..0069e889e1ba8ce268b094e79c8fcf6ca56ef16e --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmDirList.h @@ -0,0 +1,68 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmDirList.h,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:38 $ + Version: $Revision: 1.4 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#ifndef GDCMDIRLIST_H +#define GDCMDIRLIST_H + +#include "gdcmCommon.h" + +#include <string> +#include <vector> +#include <iostream> + +namespace gdcm +{ + +typedef std::vector<std::string> DirListType; + +//----------------------------------------------------------------------------- + +// NOTE: Due to a M$VC6 'feature' we cannot export a std::list in a dll, +// so GDCM_EXPORT keyword was removed for this class only + +/** + * \brief List containing the file headers of all the 'gdcm readable' files + * found by exploring (possibly recursively) a root directory. + */ +class GDCM_EXPORT DirList +{ +public : + DirList(std::string const &dirName, bool recursive=false); + ~DirList(); + + void Print(std::ostream &os = std::cout, std::string const &indent = "" ); + + /// Return the name of the directory + std::string const &GetDirName() const { return DirName; } + + /// Return the file names + DirListType const &GetFilenames() const { return Filenames; } + + static bool IsDirectory(std::string const &dirName); + +private : + int Explore(std::string const &dirName, bool recursive=false); + + /// List of file names + DirListType Filenames; + /// name of the root directory to explore + std::string DirName; +}; +} // end namespace gdcm +//----------------------------------------------------------------------------- +#endif diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmDocEntry.cxx b/Utilities/ITK/Utilities/gdcm/src/gdcmDocEntry.cxx new file mode 100644 index 0000000000000000000000000000000000000000..6a2db24de6440ce628e6bbbe1801346075b3e598 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmDocEntry.cxx @@ -0,0 +1,298 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmDocEntry.cxx,v $ + Language: C++ + Date: $Date: 2006/02/20 15:56:57 $ + Version: $Revision: 1.8 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#include "gdcmDocEntry.h" +#include "gdcmTS.h" +#include "gdcmVR.h" +#include "gdcmGlobal.h" +#include "gdcmUtil.h" +#include "gdcmDebug.h" + +#include <iomanip> // for std::ios::left, ... +#include <fstream> + +namespace gdcm +{ +//----------------------------------------------------------------------------- + +// Constructor / Destructor +/** + * \brief Constructor from a given DictEntry + * @param in Pointer to existing dictionary entry + */ +DocEntry::DocEntry(DictEntry *in) +{ + ImplicitVR = false; + DicomDict = in; + SetKey( in->GetKey( ) ); + Offset = 0 ; // To avoid further missprinting + + // init some variables + ReadLength = 0; + Length = 0; +} + +//----------------------------------------------------------------------------- +// Public +/** + * \brief Writes the common part of any ValEntry, BinEntry, SeqEntry + * @param fp already open ofstream pointer + * @param filetype type of the file (ACR, ImplicitVR, ExplicitVR, ...) + */ +void DocEntry::WriteContent(std::ofstream *fp, FileType filetype) +{ + uint32_t ffff = 0xffffffff; + uint16_t group = GetGroup(); + + ///\todo allow skipping Shadow groups + + VRKey vr = GetVR(); + uint16_t elem = GetElement(); + uint32_t lgth = GetLength(); + + if ( group == 0xfffe && elem == 0x0000 ) + { + // Fix in order to make some MR PHILIPS images e-film readable + // see gdcmData/gdcm-MR-PHILIPS-16-Multi-Seq.dcm: + // we just *always* ignore spurious fffe|0000 tag ! + return; + } + + // + // ----------- Writes the common part + // + binary_write( *fp, group); //group number + binary_write( *fp, elem); //element number + + // Dicom V3 group 0x0002 is *always* Explicit VR ! + if ( filetype == ExplicitVR || filetype == JPEG || group == 0x0002 ) + { +// ----------- Writes the common part : the VR + the length + + // Special case of delimiters: + if (group == 0xfffe) + { + // Delimiters have NO Value Representation + // Hence we skip writing the VR. + // + // In order to avoid further troubles, we choose to write them + // as 'no-length' Item Delimitors (we pad by writing 0xffffffff) + // We shall force the end of a given SeqItem by writting + // a Item Delimitation Item (fffe, e00d) + + uint32_t ff = 0xffffffff; + binary_write(*fp, ff); + return; + } + + uint16_t zero = 0; + uint16_t shortLgr = (uint16_t)lgth; + + if (vr == GDCM_UNKNOWN) + { + // GDCM_UNKNOWN was stored in the Entry VR; + // deal with Entry as if TS were Implicit VR + + binary_write(*fp, lgth); + } + else + { + binary_write(*fp, vr); + gdcmAssertMacro( vr.size() == 2 ); + + // See PS 3.5-2004 page 33, 36 + if ( (vr == "SQ") || (vr == "OB") || (vr == "OW") || (vr == "OF") + || (vr == "UN") || (vr == "UT") ) + { + binary_write(*fp, zero); + if (vr == "SQ") + { + // we set SQ length to ffffffff + // and we shall write a Sequence Delimitor Item + // at the end of the Sequence! + binary_write(*fp, ffff); + } + else + { + binary_write(*fp, lgth); + } + } + else + { + binary_write(*fp, shortLgr); + } + } + } + else // IMPLICIT VR + { +// ----------- Writes the common part : the VR + if (vr == "SQ") + { + binary_write(*fp, ffff); + } + else + { + binary_write(*fp, lgth); + } + } +} + +/** + * \brief Gets the full length of the elementary DocEntry (not only value + * length) depending on the VR. + */ +uint32_t DocEntry::GetFullLength() +{ + uint32_t l = GetReadLength(); + if ( IsImplicitVR() ) + { + l = l + 8; // 2 (gr) + 2 (el) + 4 (lgth) + } + else + { + if ( GetVR()=="OB" || GetVR()=="OW" || GetVR()=="SQ" ) + { + l = l + 12; // 2 (gr) + 2 (el) + 2 (vr) + 2 (unused) + 4 (lgth) + } + else + { + l = l + 8; // 2 (gr) + 2 (el) + 2 (vr) + 2 (lgth) + } + } + return l; +} + +/** + * \brief tells us if entry is the last one of a 'no length' SequenceItem + * (fffe,e00d) + */ +bool DocEntry::IsItemDelimitor() +{ + return (GetGroup() == 0xfffe && GetElement() == 0xe00d); +} + +/** + * \brief tells us if entry is the first one of an Item + * (fffe,e000) + */ +bool DocEntry::IsItemStarter() +{ + return (GetGroup() == 0xfffe && GetElement() == 0xe000); +} + +/** + * \brief tells us if entry is the last one of a 'no length' Sequence + * (fffe,e0dd) + */ +bool DocEntry::IsSequenceDelimitor() +{ + return (GetGroup() == 0xfffe && GetElement() == 0xe0dd); +} + +/** + * \brief Copies all the attributes from an other DocEntry + * @param doc entry to copy from + */ +void DocEntry::Copy(DocEntry *doc) +{ + Length = doc->Length; + ReadLength = doc->ReadLength; + ImplicitVR = doc->ImplicitVR; + Offset = doc->Offset; +} + +//----------------------------------------------------------------------------- +// Protected + +//----------------------------------------------------------------------------- +// Private + +//----------------------------------------------------------------------------- +// Print +/** + * \brief Prints the common part of ValEntry, BinEntry, SeqEntry + * @param os ostream we want to print in + * @param indent Indentation string to be prepended during printing + */ +void DocEntry::Print(std::ostream &os, std::string const & ) +{ + size_t o; + std::string st; + TSKey v; + std::string d2, vr; + itksys_ios::ostringstream s; + uint32_t lgth; + + o = GetOffset(); + vr = GetVR(); + if ( vr==GDCM_UNKNOWN ) + vr = " "; + + s << DictEntry::TranslateToKey(GetGroup(),GetElement()); + + if (PrintLevel >= 2) + { + s << " lg : "; + lgth = GetReadLength(); // ReadLength, as opposed to (usable) Length + if (lgth == 0xffffffff) + { + st = " ffff "; + s.setf(std::ios::left); + s << std::setw(4); + s << " x(ffff) "; + s.setf(std::ios::left); + s << std::setw(8) << "-1"; + } + else + { + st = Util::Format("x(%x)",lgth); // we may keep it + s.setf(std::ios::left); + s << std::setw(11-st.size()) << " "; + s << st << " "; + s.setf(std::ios::left); + s << std::setw(8) << lgth; + } + s << " Off.: "; + st = Util::Format("x(%x)",o); // we may keep it + s << std::setw(11-st.size()) << " "; + s << st << " "; + s << std::setw(8) << o; + } + if (PrintLevel >= 1) + s << " "; + + s << "[" << vr << "] "; + + std::string name; + if ( GetElement() == 0x0000 ) + name = "Group Length"; + else + name = GetName(); + + if (PrintLevel >= 1) + { + s.setf(std::ios::left); + s << std::setw(66-name.length()) << " "; + } + + s << "[" << name << "]"; + os << s.str(); +} + +//----------------------------------------------------------------------------- +} // end namespace gdcm diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmDocEntry.h b/Utilities/ITK/Utilities/gdcm/src/gdcmDocEntry.h new file mode 100644 index 0000000000000000000000000000000000000000..f43c74be764fb24727f7cebce038a7bb9aba3775 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmDocEntry.h @@ -0,0 +1,162 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmDocEntry.h,v $ + Language: C++ + Date: $Date: 2006/02/20 17:53:28 $ + Version: $Revision: 1.6 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#ifndef GDCMDOCENTRY_H +#define GDCMDOCENTRY_H + +#include "gdcmBase.h" +#include "gdcmDictEntry.h" + +#include <iostream> +#include <fstream> + +namespace gdcm +{ +class File; +class ValEntry; +class BinEntry; +class SeqEntry; + +//----------------------------------------------------------------------------- +/** + * \brief The dicom header of a Dicom file contains a set of such entries + * (when successfuly parsed against a given Dicom dictionary) + */ +class GDCM_EXPORT DocEntry : public Base +{ +public: + DocEntry(DictEntry*); + /// \brief Canonical Destructor + virtual ~DocEntry() {} + + virtual void Print (std::ostream &os = std::cout, std::string const &indent = ""); + virtual void WriteContent(std::ofstream *fp, FileType filetype); + + /// \brief Gets the DicEntry of the current Dicom entry + /// @return The DicEntry of the current Dicom entry + DictEntry * GetDictEntry() { return DicomDict; } + + /// Returns the Dicom Group number of the current Dicom entry + uint16_t GetGroup() const { return DicomDict->GetGroup(); } + + /// Returns the Dicom Element number of the current Dicom entry + uint16_t GetElement() const { return DicomDict->GetElement();} + + /// Set the 'key' of the current Dicom entry + void SetKey( TagKey const &key ) { Key = key; } + + /// Returns the 'key' of the current Dicom entry + TagKey const &GetKey() const { return Key; } + + /// \brief Returns the 'Name' '(e.g. "Patient's Name") found in the Dicom + /// Dictionnary of the current Dicom Header Entry + std::string const &GetName() const { return DicomDict->GetName(); } + + /// \brief Returns the 'Value Representation' (e.g. "PN" : Person Name, + /// "SL" : Signed Long), found in the Dicom header or in the Dicom + /// Dictionnary, of the current Dicom entry + std::string const &GetVR() const { return DicomDict->GetVR(); } + + /// \brief Returns the 'Value Multiplicity' (e.g. "1", "6", "1-n", "3-n"), + /// found in the Dicom entry or in the Dicom Dictionnary + /// of the current Dicom entry + std::string const &GetVM() const { return DicomDict->GetVM(); } + + /// Sets the 'Value Multiplicity' of the current Dicom entry + void SetVM( TagName const &v) { DicomDict->SetVM(v); } + + /// \brief Returns offset (since the beginning of the file, including + /// the File Preamble, if any) of the value of the current Dicom entry + /// \warning offset of the *value*, not of the Dicom entry + const size_t &GetOffset() const { return Offset; } + + /// \brief Sets only 'Read Length' (*not* 'Usable Length') of the current + /// Dicom entry + void SetReadLength(uint32_t l) { ReadLength = l; } + /// \brief Returns the 'read length' of the current Dicom entry + /// \warning this value is the one stored in the Dicom header but not + /// mandatoryly the one thats's used (in case on SQ, or delimiters, + /// the usable length is set to zero) + const uint32_t &GetReadLength() const { return ReadLength; } + + /// \brief Sets both 'Read Length' and 'Usable Length' of the current + /// Dicom entry + virtual void SetLength(uint32_t l) { Length = l; } + /// \brief Returns the actual value length of the current Dicom entry + /// \warning this value is not *always* the one stored in the Dicom header + /// in case of well known bugs + const uint32_t &GetLength() const { return Length; } + + uint32_t GetFullLength(); + virtual uint32_t ComputeFullLength() = 0; + +// The following 3 members, for internal use only ! + /// \brief Sets the offset of the Dicom entry + /// \warning use with caution ! + /// @param of offset to be set + void SetOffset(size_t of) { Offset = of; } + + /// Sets to TRUE the ImplicitVr flag of the current Dicom entry + void SetImplicitVR() { ImplicitVR = true; } + + /// \brief Tells us if the current Dicom entry was checked as ImplicitVr + /// @return true if the current Dicom entry was checked as ImplicitVr + bool IsImplicitVR() const { return ImplicitVR; } + + /// \brief Tells us if the VR of the current Dicom entry is Unknown + /// @return true if the VR is unknown + bool IsVRUnknown() const { return DicomDict->IsVRUnknown(); } + + /// \brief Tells us if the VM of the current Dicom entry is Unknown + /// @return true if the VM is unknown + bool IsVMUnknown() const { return DicomDict->IsVMUnknown(); } + + bool IsItemDelimitor(); + bool IsItemStarter(); + bool IsSequenceDelimitor(); + + virtual void Copy(DocEntry *e); + +protected: + /// \brief pointer to the underlying Dicom dictionary element + DictEntry *DicomDict; + + /// \brief Correspond to the real length of the data + /// This length might always be even + uint32_t Length; + + /// \brief Length to read in the file to obtain data + uint32_t ReadLength; + + /// \brief Even when reading explicit vr files, some elements happen to + /// be implicit. Flag them here since we can't use the entry->vr without + /// breaking the underlying dictionary. + bool ImplicitVR; + + /// Offset from the beginning of file for direct user access + size_t Offset; + + /// \brief Generalized key of this DocEntry (for details on + /// the generalized key refer to \ref TagKey documentation). + TagKey Key; + +private: +}; +} // end namespace gdcm +//----------------------------------------------------------------------------- +#endif diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmDocEntryArchive.cxx b/Utilities/ITK/Utilities/gdcm/src/gdcmDocEntryArchive.cxx new file mode 100644 index 0000000000000000000000000000000000000000..3a5e0738918fa115ee663fd4c717fd1e8d4fd340 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmDocEntryArchive.cxx @@ -0,0 +1,175 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmDocEntryArchive.cxx,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:38 $ + Version: $Revision: 1.3 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#include "gdcmDocEntryArchive.h" +#include "gdcmDebug.h" +#include "gdcmDocEntry.h" + +#include <string> + +namespace gdcm +{ +//----------------------------------------------------------------------------- +// Constructor / Destructor +/** + * \brief Constructor + */ +DocEntryArchive::DocEntryArchive(File *file) +{ + ArchFile = file; +} + +/** + * \brief Destructor + */ +DocEntryArchive::~DocEntryArchive() +{ + ClearArchive(); +} + +//----------------------------------------------------------------------------- +// Public +/** + * \brief Replaces in the Header a DocEntry by the new DocEntry. + * The initial DocEntry is kept in archive. + * @param newEntry New entry to substitute to an other entry of the Header + * @return FALSE when an other DocEntry is already archived with the same key + * TRUE otherwise + */ +bool DocEntryArchive::Push(DocEntry *newEntry) +{ + if ( !newEntry ) + return false; + + uint16_t group = newEntry->GetDictEntry()->GetGroup(); + uint16_t elem = newEntry->GetDictEntry()->GetElement(); + TagKey key = DictEntry::TranslateToKey(group,elem); + + if ( Archive.find(key) == Archive.end() ) + { + // Save the old DocEntry if any + DocEntry *old = ArchFile->GetDocEntry(group, elem); + Archive[key] = old; + if ( old ) + ArchFile->RemoveEntryNoDestroy(old); + + // Set the new DocEntry + ArchFile->AddEntry(newEntry); + + return true; + } + return false; +} + +/** + * \brief Removes out of the Header a DocEntry. + * (it's kept in archive). + * @param group Group number of the Entry to remove + * @param elem Element number of the Entry to remove + * @return FALSE when an other DocEntry is already archived with the same key + * TRUE otherwise + */ +bool DocEntryArchive::Push(uint16_t group, uint16_t elem) +{ + TagKey key = DictEntry::TranslateToKey(group, elem); + + if ( Archive.find(key)==Archive.end() ) + { + // Save the old DocEntry if any + DocEntry *old = ArchFile->GetDocEntry(group, elem); + Archive[key] = old; + if ( old ) + ArchFile->RemoveEntryNoDestroy(old); + + return true; + } + return false; +} + +/** + * \brief Restore in the Header the DocEntry specified by (group,element). + * The archive entry is destroyed. + * @param group Group number of the Entry to restore + * @param elem Element number of the Entry to restore + * @return FALSE when the key isn't in the archive, + * TRUE otherwise + */ +bool DocEntryArchive::Restore(uint16_t group, uint16_t elem) +{ + TagKey key=DictEntry::TranslateToKey(group, elem); + + TagDocEntryHT::iterator restoreIt=Archive.find(key); + if ( restoreIt!=Archive.end() ) + { + // Delete the new value + DocEntry *rem = ArchFile->GetDocEntry(group, elem); + if ( rem ) + ArchFile->RemoveEntry(rem); + + // Restore the old value + if ( Archive[key] ) + ArchFile->AddEntry(Archive[key]); + + Archive.erase(restoreIt); + + return true; + } + return false; +} + +/** + * \brief Removes all DocEntry from the archive, and destroy them. + * The archives entries aren't restored. + */ +void DocEntryArchive::ClearArchive( ) +{ + for(TagDocEntryHT::iterator it = Archive.begin(); + it!=Archive.end(); + ++it) + { + delete it->second; + } + Archive.clear(); +} + +//----------------------------------------------------------------------------- +// Protected + +//----------------------------------------------------------------------------- +// Private + +//----------------------------------------------------------------------------- +// Print +/** + * \brief Print all + * @param os The output stream to be written to. + */ +void DocEntryArchive::Print(std::ostream &os) +{ + os << "Elements in archives :" << std::endl; + for(TagDocEntryHT::iterator it = Archive.begin(); + it!=Archive.end(); + ++it) + { + if ( it->second ) + it->second->Print(os); + } +} + +//----------------------------------------------------------------------------- +} // end namespace gdcm diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmDocEntryArchive.h b/Utilities/ITK/Utilities/gdcm/src/gdcmDocEntryArchive.h new file mode 100644 index 0000000000000000000000000000000000000000..547bd1abcf36629e9bb954f107107ba3c0dc4da4 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmDocEntryArchive.h @@ -0,0 +1,62 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmDocEntryArchive.h,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:38 $ + Version: $Revision: 1.3 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#ifndef GDCMDOCENTRYARCHIVE_H +#define GDCMDOCENTRYARCHIVE_H + +#include "gdcmFile.h" + +namespace gdcm +{ + +//----------------------------------------------------------------------------- +/** + * \brief Container + * It's goal is to change the File header correctly. At this time, the change is + * only made for the first level of the Document. In the future, it might + * consider Dicom Sequences (SeqEntry, within any SQItem). + * The change is made by replacing a DocEntry by an other that is created + * outside the class. The old value is kept. When we restore the File + * status, the added DocEntry is deleted and replaced by the old value. + */ +class GDCM_EXPORT DocEntryArchive +{ + +friend class FileHelper; + +private: + DocEntryArchive(File *file); + ~DocEntryArchive(); + + void Print(std::ostream &os = std::cout); + + bool Push(DocEntry *newEntry); + bool Push(uint16_t group,uint16_t elem); + bool Restore(uint16_t group,uint16_t elem); + + void ClearArchive(void); + + /// pointer to the gdcm::File pointer we want to save values from + File *ArchFile; + /// H table to save values. + TagDocEntryHT Archive; +}; +} // end namespace gdcm + +//----------------------------------------------------------------------------- +#endif diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmDocEntrySet.cxx b/Utilities/ITK/Utilities/gdcm/src/gdcmDocEntrySet.cxx new file mode 100644 index 0000000000000000000000000000000000000000..156ad47ef18050086ab1c6f8b3798c2b122cc723 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmDocEntrySet.cxx @@ -0,0 +1,639 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmDocEntrySet.cxx,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:38 $ + Version: $Revision: 1.4 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ +#include "gdcmDocEntrySet.h" + +#include "gdcmDebug.h" +#include "gdcmCommon.h" +#include "gdcmDictSet.h" +#include "gdcmGlobal.h" +#include "gdcmDocEntry.h" +#include "gdcmSeqEntry.h" +#include "gdcmValEntry.h" +#include "gdcmBinEntry.h" +#include "gdcmUtil.h" +#if defined(__BORLANDC__) + #include <mem.h> // for memset +#endif + +namespace gdcm +{ +//----------------------------------------------------------------------------- +// Constructor / Destructor +DocEntrySet::DocEntrySet() +{ + PreviousDocEntry = 0; +} +//----------------------------------------------------------------------------- +// Public +/** + * \brief Get the "std::string representable" value of the Dicom entry + * @param group Group number of the searched tag. + * @param elem Element number of the searched tag. + * @return Corresponding element value when it exists, + * and the string GDCM_UNFOUND otherwise. + */ +std::string DocEntrySet::GetEntryValue(uint16_t group, uint16_t elem) +{ + ContentEntry *entry = dynamic_cast<ContentEntry *>(GetDocEntry(group,elem)); + if ( entry ) + return entry->GetValue(); + return GDCM_UNFOUND; +} + +/** + * \brief Gets (from Header) a 'non string' element value + * @param group group number of the Entry + * @param elem element number of the Entry + * @return Pointer to the 'non string' area + */ +void *DocEntrySet::GetEntryBinArea(uint16_t group, uint16_t elem) +{ + BinEntry *entry = GetBinEntry(group, elem); + if ( entry ) + return entry->GetBinArea(); + return 0; +} + +/** + * \brief Return the value of the BinEntry if it's "std::string representable" + * @param group Group number of the searched tag. + * @param elem Element number of the searched tag. + * @return Corresponding element value when it's "std::string representable" + * and the string GDCM_NOTASCII otherwise. + */ +std::string DocEntrySet::GetEntryForcedAsciiValue(uint16_t group, uint16_t elem) +{ + DocEntry *d = GetDocEntry(group,elem); + if ( !d ) + return GDCM_UNFOUND; + + if (ValEntry *v = dynamic_cast<ValEntry *>(d)) + return v->GetValue(); + + if (BinEntry *b = dynamic_cast<BinEntry *>(d)) + { + uint8_t *a = b->GetBinArea(); + if (!b) + return GDCM_NOTLOADED; + // TODO : unify those two methods. + if (Util::IsCleanArea(a, b->GetLength()) ) + return Util::CreateCleanString(a, b->GetLength()); + } + return GDCM_NOTASCII; +} + +/** + * \brief Searches within Header Entries (Dicom Elements) parsed with + * the public and private dictionaries + * for the value length of a given tag.. + * @param group Group number of the searched tag. + * @param elem Element number of the searched tag. + * @return Corresponding element length; -1 if not found + */ +int DocEntrySet::GetEntryLength(uint16_t group, uint16_t elem) +{ + DocEntry *entry = GetDocEntry(group, elem); + if ( entry ) + return entry->GetLength(); + return -1; +} + +/** + * \brief Searches within Header Entries (Dicom Elements) parsed with + * the public [and private dictionaries] + * for the element value representation of a given tag.. + * Obtaining the VR (Value Representation) might be needed by caller + * to convert the string typed content to caller's native type + * (think of C++ vs Python). The VR is actually of a higher level + * of semantics than just the native C++ type. + * @param group Group number of the searched tag. + * @param elem Element number of the searched tag. + * @return Corresponding element value representation when it exists, + * and the string GDCM_UNFOUND ("gdcm::Unfound") otherwise. + */ +std::string DocEntrySet::GetEntryVR(uint16_t group, uint16_t elem) +{ + DocEntry *entry = GetDocEntry(group, elem); + if ( entry ) + return entry->GetVR(); + return GDCM_UNFOUND; +} + +/** + * \brief Same as \ref Document::GetDocEntry except it only + * returns a result when the corresponding entry is of type + * ValEntry. + * @param group Group number of the searched Dicom Element + * @param elem Element number of the searched Dicom Element + * @return When present, the corresponding ValEntry. + */ +ValEntry *DocEntrySet::GetValEntry(uint16_t group, uint16_t elem) +{ + DocEntry *currentEntry = GetDocEntry(group, elem); + if ( !currentEntry ) + return NULL; + + return dynamic_cast<ValEntry*>(currentEntry); +} + +/** + * \brief Same as \ref Document::GetDocEntry except it only + * returns a result when the corresponding entry is of type + * BinEntry. + * @param group Group number of the searched Dicom Element + * @param elem Element number of the searched Dicom Element + * @return When present, the corresponding BinEntry. + */ +BinEntry *DocEntrySet::GetBinEntry(uint16_t group, uint16_t elem) +{ + DocEntry *currentEntry = GetDocEntry(group, elem); + if ( !currentEntry ) + { + gdcmWarningMacro( "No corresponding BinEntry " << std::hex << group << + "," << elem); + return NULL; + } + + return dynamic_cast<BinEntry*>(currentEntry); +} + +/** + * \brief Same as \ref Document::GetDocEntry except it only + * returns a result when the corresponding entry is of type + * SeqEntry. + * @param group Group number of the searched Dicom Element + * @param elem Element number of the searched Dicom Element + * @return When present, the corresponding SeqEntry. + */ +SeqEntry *DocEntrySet::GetSeqEntry(uint16_t group, uint16_t elem) +{ + DocEntry *currentEntry = GetDocEntry(group, elem); + if ( !currentEntry ) + { + gdcmWarningMacro( "No corresponding SeqEntry " << std::hex << group << + "," << elem); + return NULL; + } + + return dynamic_cast<SeqEntry*>(currentEntry); +} + +/** + * \brief Accesses an existing DocEntry (i.e. a Dicom Element) + * through it's (group, element) and modifies it's content with + * the given value. + * @param content new value (string) to substitute with + * @param group group number of the Dicom Element to modify + * @param elem element number of the Dicom Element to modify + */ +bool DocEntrySet::SetValEntry(std::string const &content, + uint16_t group, uint16_t elem) +{ + ValEntry *entry = GetValEntry(group, elem); + if (!entry ) + { + gdcmWarningMacro( "No corresponding ValEntry " << std::hex << group << + "," << elem << " element (try promotion first)."); + return false; + } + return SetValEntry(content,entry); +} + +/** + * \brief Accesses an existing DocEntry (i.e. a Dicom Element) + * through it's (group, element) and modifies it's content with + * the given value. + * @param content new value (void* -> uint8_t*) to substitute with + * @param lgth new value length + * @param group group number of the Dicom Element to modify + * @param elem element number of the Dicom Element to modify + */ +bool DocEntrySet::SetBinEntry(uint8_t *content, int lgth, + uint16_t group, uint16_t elem) +{ + BinEntry *entry = GetBinEntry(group, elem); + if (!entry ) + { + gdcmWarningMacro( "No corresponding ValEntry " << std::hex << group << + "," << elem << " element (try promotion first)."); + return false; + } + + return SetBinEntry(content,lgth,entry); +} + +/** + * \brief Accesses an existing DocEntry (i.e. a Dicom Element) + * and modifies it's content with the given value. + * @param content new value (string) to substitute with + * @param entry Entry to be modified + */ +bool DocEntrySet::SetValEntry(std::string const &content, ValEntry *entry) +{ + if (entry) + { + entry->SetValue(content); + return true; + } + return false; +} + +/** + * \brief Accesses an existing BinEntry (i.e. a Dicom Element) + * and modifies it's content with the given value. + * @param content new value (void* -> uint8_t*) to substitute with + * @param entry Entry to be modified + * @param lgth new value length + */ +bool DocEntrySet::SetBinEntry(uint8_t *content, int lgth, BinEntry *entry) +{ + if (entry) + { + entry->SetBinArea(content); + entry->SetLength(lgth); + entry->SetValue(GDCM_BINLOADED); + return true; + } + return false; +} + +/** + * \brief Modifies the value of a given Doc Entry (Dicom Element) + * when it exists. Create it with the given value when unexistant. + * @param value (string) Value to be set + * @param group Group number of the Entry + * @param elem Element number of the Entry + * @param vr V(alue) R(epresentation) of the Entry -if private Entry- + * \return pointer to the modified/created Header Entry (NULL when creation + * failed). + */ +ValEntry *DocEntrySet::InsertValEntry(std::string const &value, + uint16_t group, uint16_t elem, + TagName const &vr ) +{ + ValEntry *valEntry = 0; + DocEntry *currentEntry = GetDocEntry( group, elem ); + + if (currentEntry) + { + valEntry = dynamic_cast<ValEntry *>(currentEntry); + + // Verify the VR + if ( valEntry ) + if ( valEntry->GetVR()!=vr ) + valEntry = NULL; + + // if currentEntry doesn't correspond to the requested valEntry + if ( !valEntry) + { + if ( !RemoveEntry(currentEntry) ) + { + gdcmWarningMacro( "Removal of previous DocEntry failed."); + return NULL; + } + } + } + + // Create a new valEntry if necessary + if ( !valEntry ) + { + valEntry = NewValEntry( group, elem, vr ); + + if ( !AddEntry(valEntry) ) + { + gdcmWarningMacro("AddEntry failed although this is a creation."); + delete valEntry; + return NULL; + } + } + + // Set the binEntry value + SetValEntry(value, valEntry); // The std::string value + return valEntry; +} + +/** + * \brief Modifies the value of a given Header Entry (Dicom Element) + * when it exists. Create it with the given value when unexistant. + * A copy of the binArea is made to be kept in the Document. + * @param binArea (binary) value to be set + * @param lgth length of the Bin Area we want to set + * @param group Group number of the Entry + * @param elem Element number of the Entry + * @param vr V(alue) R(epresentation) of the Entry -if private Entry- + * \return pointer to the modified/created Header Entry (NULL when creation + * failed). + */ +BinEntry *DocEntrySet::InsertBinEntry(uint8_t *binArea, int lgth, + uint16_t group, uint16_t elem, + TagName const &vr ) +{ + BinEntry *binEntry = 0; + DocEntry *currentEntry = GetDocEntry( group, elem ); + + // Verify the currentEntry + if (currentEntry) + { + binEntry = dynamic_cast<BinEntry *>(currentEntry); + + // Verify the VR + if ( binEntry ) + if ( binEntry->GetVR()!=vr ) + binEntry = NULL; + + // if currentEntry doesn't correspond to the requested valEntry + if ( !binEntry) + { + if ( !RemoveEntry(currentEntry) ) + { + gdcmWarningMacro( "Removal of previous DocEntry failed."); + return NULL; + } + } + } + + // Create a new binEntry if necessary + if ( !binEntry) + { + binEntry = NewBinEntry(group, elem, vr); + + if ( !AddEntry(binEntry) ) + { + gdcmWarningMacro( "AddEntry failed although this is a creation."); + delete binEntry; + return NULL; + } + } + + // Set the binEntry value + uint8_t *tmpArea; + if ( lgth>0 && binArea ) + { + tmpArea = new uint8_t[lgth]; + memcpy(tmpArea,binArea,lgth); + } + else + { + tmpArea = 0; + } + if ( !SetBinEntry(tmpArea,lgth,binEntry) ) + { + if ( tmpArea ) + { + delete[] tmpArea; + } + } + return binEntry; +} + +/** + * \brief Creates a new gdcm::SeqEntry and adds it to the current DocEntrySet. + * (remove any existing entry with same group,elem) + * @param group Group number of the Entry + * @param elem Element number of the Entry + * \return pointer to the created SeqEntry (NULL when creation + * failed). + */ +SeqEntry *DocEntrySet::InsertSeqEntry(uint16_t group, uint16_t elem) +{ + SeqEntry *seqEntry = 0; + DocEntry *currentEntry = GetDocEntry( group, elem ); + + // Verify the currentEntry + if ( currentEntry ) + { + seqEntry = dynamic_cast<SeqEntry *>(currentEntry); + + // Verify the VR + if ( seqEntry ) + seqEntry = NULL; + + // if currentEntry doesn't correspond to the requested seqEntry + if ( !seqEntry ) + { + if (!RemoveEntry(currentEntry)) + { + gdcmWarningMacro( "Removal of previous DocEntry failed."); + + return NULL; + } + } + } + // Create a new seqEntry if necessary + if ( !seqEntry ) + { + seqEntry = NewSeqEntry(group, elem); + + if ( !AddEntry(seqEntry) ) + { + gdcmWarningMacro( "AddEntry failed although this is a creation."); + + delete seqEntry; + return NULL; + } + } + + // TODO : Find a trick to insert a SequenceDelimitationItem + // in the SeqEntry, at the end. + return seqEntry; +} + +/** + * \brief Checks if a given Dicom Element exists within the DocEntrySet + * @param group Group number of the searched Dicom Element + * @param elem Element number of the searched Dicom Element + * @return true is found + */ +bool DocEntrySet::CheckIfEntryExist(uint16_t group, uint16_t elem ) +{ + return GetDocEntry(group,elem)!=NULL; +} + +/** + * \brief Build a new Val Entry from all the low level arguments. + * Check for existence of dictionary entry, and build + * a default one when absent. + * @param group Group number of the new Entry + * @param elem Element number of the new Entry + * @param vr V(alue) R(epresentation) of the new Entry + */ +ValEntry *DocEntrySet::NewValEntry(uint16_t group,uint16_t elem, + TagName const &vr) +{ + DictEntry *dictEntry = GetDictEntry(group, elem, vr); + gdcmAssertMacro(dictEntry); + + ValEntry *newEntry = new ValEntry(dictEntry); + if (!newEntry) + { + gdcmWarningMacro( "Failed to allocate ValEntry"); + return 0; + } + return newEntry; +} + + +/** + * \brief Build a new Bin Entry from all the low level arguments. + * Check for existence of dictionary entry, and build + * a default one when absent. + * @param group Group number of the new Entry + * @param elem Element number of the new Entry + * @param vr V(alue) R(epresentation) of the new Entry + */ +BinEntry *DocEntrySet::NewBinEntry(uint16_t group, uint16_t elem, + TagName const &vr) +{ + DictEntry *dictEntry = GetDictEntry(group, elem, vr); + gdcmAssertMacro(dictEntry); + + BinEntry *newEntry = new BinEntry(dictEntry); + if (!newEntry) + { + gdcmWarningMacro( "Failed to allocate BinEntry"); + return 0; + } + return newEntry; +} + +/** + * \brief Build a new SeqEntry from all the low level arguments. + * Check for existence of dictionary entry, and build + * a default one when absent. + * @param group Group number of the new Entry + * @param elem Element number of the new Entry + */ +SeqEntry* DocEntrySet::NewSeqEntry(uint16_t group, uint16_t elem) +{ + DictEntry *dictEntry = GetDictEntry(group, elem, "SQ"); + gdcmAssertMacro(dictEntry); + + SeqEntry *newEntry = new SeqEntry( dictEntry ); + if (!newEntry) + { + gdcmWarningMacro( "Failed to allocate SeqEntry"); + return 0; + } + return newEntry; +} + +/** + * \brief Request a new virtual dict entry to the dict set + * @param group Group number of the underlying DictEntry + * @param elem Element number of the underlying DictEntry + * @param vr V(alue) R(epresentation) of the underlying DictEntry + * @param vm V(alue) M(ultiplicity) of the underlying DictEntry + * @param name english name + */ +DictEntry* DocEntrySet::NewVirtualDictEntry( uint16_t group, uint16_t elem, + TagName const &vr, + TagName const &vm, + TagName const &name ) +{ + return Global::GetDicts()->NewVirtualDictEntry(group,elem,vr,vm,name); +} + +//----------------------------------------------------------------------------- +// Protected +/** + * \brief Searches [both] the public [and the shadow dictionary (when they + * exist)] for the presence of the DictEntry with given + * group and element. The public dictionary has precedence on the + * shadow one(s), if any. + * @param group Group number of the searched DictEntry + * @param elem Element number of the searched DictEntry + * @return Corresponding DictEntry when it exists, NULL otherwise. + */ +DictEntry *DocEntrySet::GetDictEntry(uint16_t group,uint16_t elem) +{ + DictEntry *found = 0; + Dict *pubDict = Global::GetDicts()->GetDefaultPubDict(); + if (!pubDict) + { + gdcmWarningMacro( "We SHOULD have a default dictionary"); + } + else + { + found = pubDict->GetEntry(group, elem); + } + return found; +} + +/** + * \brief Searches [both] the public [and the shadow dictionary (when they + * exist)] for the presence of the DictEntry with given + * group and element, and create a new virtual DictEntry if necessary + * @param group group number of the searched DictEntry + * @param elem element number of the searched DictEntry + * @param vr V(alue) R(epresentation) to use, if necessary + * @return Corresponding DictEntry when it exists, NULL otherwise. + * \remarks The returned DictEntry is registered + */ +DictEntry *DocEntrySet::GetDictEntry(uint16_t group, uint16_t elem, + TagName const &vr) +{ + DictEntry *dictEntry = GetDictEntry(group,elem); + DictEntry *goodEntry = dictEntry; + std::string goodVR = vr; + TagName vm; + if (elem == 0x0000) + goodVR="UL"; + + if ( goodEntry ) + { + if ( goodVR != goodEntry->GetVR() + && goodVR != GDCM_UNKNOWN ) + { + gdcmWarningMacro("For (" << std::hex << group << "|" + << elem << "), found VR : [" << vr << "]" + << " expected: [" << goodEntry->GetVR() << "]" ) ; + // avoid confusing further validator with "FIXME" VM + // when possible + vm = dictEntry->GetVM(); + goodEntry = NULL; + } + } + else + { + vm = "FIXME"; + } + + // Create a new virtual DictEntry if necessary + if (!goodEntry) + { + if (dictEntry) + { + goodEntry = NewVirtualDictEntry(group, elem, goodVR, vm, + dictEntry->GetName() ); + } + else + { + goodEntry = NewVirtualDictEntry(group, elem, goodVR); + } + } + return goodEntry; +} + +//----------------------------------------------------------------------------- +// Private + +//----------------------------------------------------------------------------- +// Print + +//----------------------------------------------------------------------------- +} // end namespace gdcm diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmDocEntrySet.h b/Utilities/ITK/Utilities/gdcm/src/gdcmDocEntrySet.h new file mode 100644 index 0000000000000000000000000000000000000000..db90f259131abdab32a85048a24473574d021d39 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmDocEntrySet.h @@ -0,0 +1,145 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmDocEntrySet.h,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:38 $ + Version: $Revision: 1.5 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#ifndef GDCMDOCENTRYSET_H +#define GDCMDOCENTRYSET_H + +#include "gdcmBase.h" +#include <fstream> + +namespace gdcm +{ +//----------------------------------------------------------------------------- +class DocEntry; +class ValEntry; +class BinEntry; +class SeqEntry; +class DictEntry; + +typedef TagKey BaseTagKey; + +//----------------------------------------------------------------------------- +/** + * \brief + * \ref DocEntrySet is an abstract base class for \ref ElementSet + * and \ref SQItem which are both containers for DocEntries. + * - \ref ElementSet is based on the STL map<> container + * (see \ref ElementSet::TagHT) + * - \ref SQItem is based on an STL list container (see \ref ListDocEntry). + * + * Since the syntax for adding a new element to a map<> or a list<> + * differ, \ref DocEntrySet is designed as an adapter to unify the + * interfaces of \ref DocEntrySet and \ref ElementSet. + * + * As an illustration of this design, please refer to the implementation + * of \ref AddEntry (or any pure virtual method) in both derived classes. + * This adapter unification of interfaces enables the parsing of a + * DICOM header containing (optionaly heavily nested) sequences to be + * written recursively [see \ref Document::ParseDES + * which calls \ref Document::ParseSQ, which in turn calls + * \ref Document::ParseDES ]. + * + * \note Developpers should strongly resist to the temptation of adding + * members to this class since this class is designed as an adapter + * in the form of an abstract base class. + */ +class GDCM_EXPORT DocEntrySet : public Base +{ +public: + /// Canonical Constructor + DocEntrySet(); + /// Canonical Destructor + virtual ~DocEntrySet() {} + + /// \brief write any type of entry to the entry set + virtual void WriteContent (std::ofstream *fp, FileType filetype) = 0; + + /// \brief Remove all Entry of the current set + virtual void ClearEntry() = 0; + /// \brief adds any type of entry to the current set + virtual bool AddEntry(DocEntry *entry) = 0; + /// \brief Removes any type of entry out of the entry set, and destroys it + virtual bool RemoveEntry(DocEntry *entryToRemove) = 0; + /// \brief Removes any type of entry out of the entry set, DOESN'T destroy it + virtual bool RemoveEntryNoDestroy(DocEntry *entryToRemove) = 0; + /// \brief Gets the first entry (of any type) of the current set + virtual DocEntry *GetFirstEntry()=0; + /// \brief Gets the next entry (of any type) of the current set + virtual DocEntry *GetNextEntry()=0; + + virtual std::string GetEntryValue(uint16_t group, uint16_t elem); + virtual void *GetEntryBinArea(uint16_t group, uint16_t elem); + + virtual int GetEntryLength(uint16_t group, uint16_t elem); + virtual std::string GetEntryVR(uint16_t group, uint16_t elem); + virtual std::string GetEntryForcedAsciiValue(uint16_t group, uint16_t elem); + /// \brief Gets any type of DocEntry, identified by its (group,elem) + virtual DocEntry *GetDocEntry(uint16_t group, uint16_t elem) = 0; + /// \brief Gets a ValEntry, identified by its (group, elem) + ValEntry *GetValEntry(uint16_t group, uint16_t elem); + /// \brief Gets a BinEntry, identified by its (group,elem) + BinEntry *GetBinEntry(uint16_t group, uint16_t elem); + /// \brief Gets a SeqEntry, identified by its (group,elem) + SeqEntry *GetSeqEntry(uint16_t group, uint16_t elem); + + bool SetValEntry(std::string const &content, + uint16_t group, uint16_t elem); + bool SetBinEntry(uint8_t *content, int lgth, + uint16_t group, uint16_t elem); + bool SetValEntry(std::string const &content, ValEntry *entry); + bool SetBinEntry(uint8_t *content, int lgth, BinEntry *entry); + + ValEntry *InsertValEntry(std::string const &value, + uint16_t group, uint16_t elem, + TagName const &vr = GDCM_UNKNOWN); + BinEntry *InsertBinEntry(uint8_t *binArea, int lgth, + uint16_t group, uint16_t elem, + TagName const &vr = GDCM_UNKNOWN); + SeqEntry *InsertSeqEntry(uint16_t group, uint16_t elem); + /// \brief Tells us if the set contains no entry + virtual bool IsEmpty() = 0; + virtual bool CheckIfEntryExist(uint16_t group, uint16_t elem); + +// DocEntry related utilities + ValEntry *NewValEntry(uint16_t group,uint16_t elem, + TagName const &vr = GDCM_UNKNOWN); + BinEntry *NewBinEntry(uint16_t group, uint16_t elem, + TagName const &vr = GDCM_UNKNOWN); + SeqEntry *NewSeqEntry(uint16_t group, uint16_t elem); + +// DictEntry related utilities + DictEntry *NewVirtualDictEntry(uint16_t group,uint16_t elem, + TagName const &vr = GDCM_UNKNOWN, + TagName const &vm = GDCM_UNKNOWN, + TagName const &name = GDCM_UNKNOWN ); + +protected: +// DictEntry related utilities + DictEntry *GetDictEntry(uint16_t group, uint16_t elem); + DictEntry *GetDictEntry(uint16_t group, uint16_t elem, + TagName const &vr); + /// To be able to backtrack (Private Sequence, Implicit VR related pb) + DocEntry *PreviousDocEntry; + +private: +}; + +} // end namespace gdcm +//----------------------------------------------------------------------------- +#endif + diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmDocument.cxx b/Utilities/ITK/Utilities/gdcm/src/gdcmDocument.cxx new file mode 100644 index 0000000000000000000000000000000000000000..ae5cb6a893abc497cf0ad9730cba1ae8358a767b --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmDocument.cxx @@ -0,0 +1,2462 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmDocument.cxx,v $ + Language: C++ + Date: $Date: 2006/02/20 15:56:57 $ + Version: $Revision: 1.19 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#include "gdcmDocument.h" +#include "gdcmValEntry.h" +#include "gdcmBinEntry.h" +#include "gdcmSeqEntry.h" +#include "gdcmGlobal.h" +#include "gdcmUtil.h" +#include "gdcmDebug.h" +#include "gdcmTS.h" +#include "gdcmDictSet.h" +#include "gdcmDocEntrySet.h" +#include "gdcmSQItem.h" + +#include <vector> +#include <iomanip> +#include <fstream> +#include <ctype.h> // for isdigit +#include <stdlib.h> // for atoi + +#if defined(__BORLANDC__) + #include <mem.h> // for memset +#endif + +namespace gdcm +{ +//----------------------------------------------------------------------------- + +// Refer to Document::SetMaxSizeLoadEntry() +const unsigned int Document::MAX_SIZE_LOAD_ELEMENT_VALUE = 0xfff; // 4096 + +//----------------------------------------------------------------------------- +// Constructor / Destructor +// Constructors and destructors are protected to avoid user to invoke directly + +/** + * \brief This default constructor neither loads nor parses the file. + * You should then invoke \ref Document::Load. + * + */ +Document::Document() + :ElementSet(-1) +{ + Fp = 0; + + SetMaxSizeLoadEntry(MAX_SIZE_LOAD_ELEMENT_VALUE); + Initialize(); + SwapCode = 1234; + Filetype = ExplicitVR; + // Load will set it to true if sucessfull + Group0002Parsed = false; + IsDocumentAlreadyLoaded = false; + IsDocumentModified = true; + LoadMode = LD_ALL; // default : load everything, later + SetFileName(""); +} + +#ifndef GDCM_LEGACY_REMOVE +/** + * \brief Constructor (DEPRECATED : not to break the API) + * @param fileName 'Document' (File or DicomDir) to be open for parsing + */ +Document::Document( std::string const &fileName ) + :ElementSet(-1) +{ + Fp = 0; + + SetMaxSizeLoadEntry(MAX_SIZE_LOAD_ELEMENT_VALUE); + Initialize(); + SwapCode = 1234; + Filetype = ExplicitVR; + Group0002Parsed = false; + LoadMode = LD_ALL; // Load everything, later + + // Load will set it to true if sucessfull + IsDocumentAlreadyLoaded = false; + IsDocumentModified = true; + + SetFileName(fileName); + Load( ); +} +#endif +/** + * \brief Canonical destructor. + */ +Document::~Document () +{ + CloseFile(); +} + +//----------------------------------------------------------------------------- +// Public +/** + * \brief Loader. use SetLoadMode(), SetFileName() before ! + * @return false if file cannot be open or no swap info was found, + * or no tag was found. + */ +bool Document::Load( ) +{ + if ( GetFileName() == "" ) + { + gdcmWarningMacro( "Use SetFileName, before !" ); + return false; + } + return DoTheLoadingDocumentJob( ); +} + +#ifndef GDCM_LEGACY_REMOVE +/** + * \brief Loader. (DEPRECATED : not to break the API) + * @param fileName 'Document' (File or DicomDir) to be open for parsing + * @return false if file cannot be open or no swap info was found, + * or no tag was found. + */ +bool Document::Load( std::string const &fileName ) +{ + Filename = fileName; + return DoTheLoadingDocumentJob( ); +} +#endif + +/** + * \brief Performs the Loading Job (internal use only) + * @return false if file cannot be open or no swap info was found, + * or no tag was found. + */ +bool Document::DoTheLoadingDocumentJob( ) +{ + if ( ! IsDocumentModified ) // Nothing to do ! + return true; + + ClearEntry(); + + Fp = 0; + if ( !OpenFile() ) + { + // warning already performed in OpenFile() + Filetype = Unknown; + return false; + } + + Group0002Parsed = false; + + gdcmDebugMacro( "Starting parsing of file: " << Filename.c_str()); + + // Computes the total length of the file + Fp->seekg(0, std::ios::end); // Once per Document ! + long lgt = Fp->tellg(); // Once per Document ! + Fp->seekg(0, std::ios::beg); // Once per Document ! + + // CheckSwap returns a boolean + // (false if no swap info of any kind was found) + if (! CheckSwap() ) + { + gdcmWarningMacro( "Neither a DICOM V3 nor an ACR-NEMA file: " + << Filename.c_str()); + CloseFile(); + return false; + } + + long beg = Fp->tellg(); // just after DICOM preamble (if any) + + lgt -= beg; // remaining length to parse + + // Recursive call. + // Loading is done during parsing + ParseDES( this, beg, lgt, false); // delim_mode is first defaulted to false + + if ( IsEmpty() ) + { + gdcmErrorMacro( "No tag in internal hash table for: " + << Filename.c_str()); + CloseFile(); + return false; + } + IsDocumentAlreadyLoaded = true; + + //Fp->seekg(0, std::ios::beg); // Once per Document! + + // Load 'non string' values + + std::string PhotometricInterpretation = GetEntryValue(0x0028,0x0004); + if ( PhotometricInterpretation == "PALETTE COLOR " ) + { + // FIXME + // Probabely this line should be outside the 'if' + // Try to find an image sample holding a 'gray LUT' + LoadEntryBinArea(0x0028,0x1200); // gray LUT + + /// FIXME + /// The tags refered by the three following lines used to be CORRECTLY + /// defined as having an US Value Representation in the public + /// dictionary. BUT the semantics implied by the three following + /// lines state that the corresponding tag contents are in fact + /// the ones of a BinEntry. + /// In order to fix things "Quick and Dirty" the dictionary was + /// altered on PURPOSE but now contains a WRONG value. + /// In order to fix things and restore the dictionary to its + /// correct value, one needs to decide of the semantics by deciding + /// whether the following tags are either : + /// - multivaluated US, and hence loaded as ValEntry, but afterwards + /// also used as BinEntry, which requires the proper conversion, + /// - OW, and hence loaded as BinEntry, but afterwards also used + /// as ValEntry, which requires the proper conversion. + // --> OB (byte aray) or OW (short int aray) + // The actual VR has to be deduced from other entries. + // Our way of loading them may fail in some cases : + // We must or not SwapByte depending on other field values. + + LoadEntryBinArea(0x0028,0x1201); // R LUT + LoadEntryBinArea(0x0028,0x1202); // G LUT + LoadEntryBinArea(0x0028,0x1203); // B LUT + + // Segmented Red Palette Color LUT Data + LoadEntryBinArea(0x0028,0x1221); + // Segmented Green Palette Color LUT Data + LoadEntryBinArea(0x0028,0x1222); + // Segmented Blue Palette Color LUT Data + LoadEntryBinArea(0x0028,0x1223); + } + + //FIXME later : how to use it? + SeqEntry *modLutSeq = GetSeqEntry(0x0028,0x3000); // Modality LUT Sequence + if ( modLutSeq !=0 ) + { + SQItem *sqi= modLutSeq->GetFirstSQItem(); + if ( sqi != 0 ) + { + BinEntry *b = sqi->GetBinEntry(0x0028,0x3006); + if ( b != 0 ) + { + if ( b->GetLength() != 0 ) + { + // FIXME : CTX dependent means : contexted dependant. + // see upper comment. + LoadEntryBinArea(b); //LUT Data (CTX dependent) + } + } + } + } + + // Force Loading some more elements if user asked to. + + gdcm::DocEntry *d; + for (ListElements::iterator it = UserForceLoadList.begin(); + it != UserForceLoadList.end(); + ++it) + { + gdcmDebugMacro( "Force Load " << std::hex + << (*it).Group << "|" <<(*it).Elem ); + + d = GetDocEntry( (*it).Group, (*it).Elem); + + if ( d == NULL) + { + gdcmWarningMacro( "You asked to ForceLoad " << std::hex + << (*it).Group <<"|"<< (*it).Elem + << " that doesn't exist" ); + continue; + } + + if ( dynamic_cast<ValEntry *>(d) ) + { + LoadDocEntry(d, true); + continue; + } + + BinEntry *b = dynamic_cast<BinEntry *>(d); + if ( b ) + { + LoadEntryBinArea(b); + b->SetValue(GDCM_BINLOADED); + continue; + } + + if ( dynamic_cast<SeqEntry *>(d) ) + { + gdcmWarningMacro( "You cannot 'ForceLoad' a SeqEntry :" << std::hex + << (*it).Group <<"|"<< (*it).Elem ); + continue; + } + } + + CloseFile(); + + // ---------------------------- + // Specific code to allow gdcm to read ACR-LibIDO formated images + // Note: ACR-LibIDO is an extension of the ACR standard that was + // used at CREATIS. For the time being (say a couple of years) + // we keep this kludge to allow CREATIS users + // reading their old images. + // + // if recognition code tells us we deal with a LibIDO image + // we switch lineNumber and columnNumber + // + std::string RecCode; + RecCode = GetEntryValue(0x0008, 0x0010); // recognition code (RET) + if (RecCode == "ACRNEMA_LIBIDO_1.1" || + RecCode == "CANRME_AILIBOD1_1." ) // for brain-damaged softwares + // with "little-endian strings" + { + Filetype = ACR_LIBIDO; + std::string rows = GetEntryValue(0x0028, 0x0010); + std::string columns = GetEntryValue(0x0028, 0x0011); + SetValEntry(columns, 0x0028, 0x0010); + SetValEntry(rows , 0x0028, 0x0011); + } + // --- End of ACR-LibIDO kludge --- + return true; +} + + +/** + * \brief Adds a new element we want to load anyway + * @param group Group number of the target tag. + * @param elem Element number of the target tag. + */ +void Document::AddForceLoadElement (uint16_t group, uint16_t elem) +{ + Element el; + el.Group = group; + el.Elem = elem; + UserForceLoadList.push_back(el); +} +/** + * \brief Get the public dictionary used + */ +Dict *Document::GetPubDict() +{ + return RefPubDict; +} + +/** + * \brief Get the shadow dictionary used + */ +Dict *Document::GetShaDict() +{ + return RefShaDict; +} + +/** + * \brief Set the shadow dictionary used + * @param dict dictionary to use in shadow + */ +bool Document::SetShaDict(Dict *dict) +{ + RefShaDict = dict; + return !RefShaDict; +} + +/** + * \brief Set the shadow dictionary used + * @param dictName name of the dictionary to use in shadow + */ +bool Document::SetShaDict(DictKey const &dictName) +{ + RefShaDict = Global::GetDicts()->GetDict(dictName); + return !RefShaDict; +} + +/** + * \brief This predicate tells us whether or not the current Document + * was properly parsed and contains at least *one* Dicom Element + * (and nothing more, sorry). + * @return false when we're 150 % sure it's NOT a Dicom/Acr file, + * true otherwise. + */ +bool Document::IsParsable() +{ + if ( Filetype == Unknown ) + { + gdcmWarningMacro( "Wrong filetype for " << GetFileName()); + return false; + } + + if ( IsEmpty() ) + { + gdcmWarningMacro( "No tag in internal hash table."); + return false; + } + + return true; +} +/** + * \brief This predicate tells us whether or not the current Document + * was properly parsed and contains at least *one* Dicom Element + * (and nothing more, sorry). + * @return false when we're 150 % sure it's NOT a Dicom/Acr file, + * true otherwise. + */ +bool Document::IsReadable() +{ + return IsParsable(); +} + + +/** + * \brief Predicate for dicom version 3 file. + * @return True when the file is a dicom version 3. + */ +bool Document::IsDicomV3() +{ + // Checking if Transfer Syntax exists is enough + // Anyway, it's too late check if the 'Preamble' was found ... + // And ... would it be a rich idea to check ? + // (some 'no Preamble' DICOM images exist !) + return GetDocEntry(0x0002, 0x0010) != NULL; +} + +/** + * \brief Predicate for Papyrus file + * Dedicated to whomsoever it may concern + * @return True when the file is a Papyrus file. + */ +bool Document::IsPapyrus() +{ + // check for Papyrus private Sequence + DocEntry *e = GetDocEntry(0x0041, 0x1050); + if ( !e ) + return false; + // check if it's actually a Sequence + if ( !dynamic_cast<SeqEntry*>(e) ) + return false; + return true; +} + +/** + * \brief returns the File Type + * (ACR, ACR_LIBIDO, ExplicitVR, ImplicitVR, Unknown) + * @return the FileType code + */ +FileType Document::GetFileType() +{ + return Filetype; +} + +/** + * \brief Accessor to the Transfer Syntax (when present) of the + * current document (it internally handles reading the + * value from disk when only parsing occured). + * @return The encountered Transfer Syntax of the current document, if DICOM. + * GDCM_UNKNOWN for ACR-NEMA files (or broken headers ...) + */ +std::string Document::GetTransferSyntax() +{ + DocEntry *entry = GetDocEntry(0x0002, 0x0010); + if ( !entry ) + { + return GDCM_UNKNOWN; + } + + // The entry might be present but not loaded (parsing and loading + // happen at different stages): try loading and proceed with check... + LoadDocEntrySafe(entry); + if (ValEntry *valEntry = dynamic_cast< ValEntry* >(entry) ) + { + std::string transfer = valEntry->GetValue(); + // The actual transfer (as read from disk) might be padded. We + // first need to remove the potential padding. We can make the + // weak assumption that padding was not executed with digits... + if ( transfer.length() == 0 ) + { + // for brain damaged headers + return GDCM_UNKNOWN; + } + while ( !isdigit((unsigned char)transfer[transfer.length()-1]) ) + { + transfer.erase(transfer.length()-1, 1); + if ( transfer.length() == 0 ) + { + // for brain damaged headers + gdcmWarningMacro( "Transfer Syntax contains no valid character."); + return GDCM_UNKNOWN; + } + } + return transfer; + } + return GDCM_UNKNOWN; +} + +/** + * \brief Accesses the info from 0002,0010 : Transfer Syntax and TS + * @return The full Transfer Syntax Name (as opposed to Transfer Syntax UID) + */ +std::string Document::GetTransferSyntaxName() +{ + // use the TS (TS : Transfer Syntax) + std::string transferSyntax = GetEntryValue(0x0002,0x0010); + + if ( (transferSyntax.find(GDCM_NOTLOADED) < transferSyntax.length()) ) + { + gdcmErrorMacro( "Transfer Syntax not loaded. " << std::endl + << "Better you increase MAX_SIZE_LOAD_ELEMENT_VALUE" ); + return "Uncompressed ACR-NEMA"; + } + if ( transferSyntax == GDCM_UNFOUND ) + { + gdcmDebugMacro( "Unfound Transfer Syntax (0002,0010)"); + return "Uncompressed ACR-NEMA"; + } + + // we do it only when we need it + const TSKey &tsName = Global::GetTS()->GetValue( transferSyntax ); + + // Global::GetTS() is a global static you shall never try to delete it! + return tsName; +} +// +// --------------- Swap Code ------------------ +/** + * \brief Swaps the bytes so they agree with the processor order + * @return The properly swaped 16 bits integer. + */ +uint16_t Document::SwapShort(uint16_t a) +{ + if ( SwapCode == 4321 || SwapCode == 2143 ) + { + //a = ((( a << 8 ) & 0xff00 ) | (( a >> 8 ) & 0x00ff ) ); + // Save CPU time + a = ( a << 8 ) | ( a >> 8 ); + } + return a; +} + +/** + * \brief Swaps back the bytes of 4-byte long integer accordingly to + * processor order. + * @return The properly swaped 32 bits integer. + */ +uint32_t Document::SwapLong(uint32_t a) +{ + switch (SwapCode) + { + case 1234 : + break; + case 4321 : +// a=( ((a<<24) & 0xff000000) | ((a<<8) & 0x00ff0000) | +// ((a>>8) & 0x0000ff00) | ((a>>24) & 0x000000ff) ); +// save CPU time + a=( ( a<<24) | ((a<<8) & 0x00ff0000) | + ((a>>8) & 0x0000ff00) | (a>>24) ); + break; + case 3412 : +// a=( ((a<<16) & 0xffff0000) | ((a>>16) & 0x0000ffff) ); + a=( (a<<16) | (a>>16) ); + break; + case 2143 : + a=( ((a<< 8) & 0xff00ff00) | ((a>>8) & 0x00ff00ff) ); + break; + default : + gdcmErrorMacro( "Unexpected swap code:" << SwapCode ); + a = 0; + } + return a; +} + +// +// -----------------File I/O --------------- +/** + * \brief Tries to open the file \ref Document::Filename and + * checks the preamble when existing. + * @return The FILE pointer on success. + */ +std::ifstream *Document::OpenFile() +{ + HasDCMPreamble = false; + if (Filename.length() == 0) + { + return 0; + } + + if ( Fp ) + { + gdcmDebugMacro( "File already open: " << Filename.c_str()); + CloseFile(); + } + + Fp = new std::ifstream(Filename.c_str(), std::ios::in | std::ios::binary); + if ( ! *Fp ) + { + // Don't user gdcmErrorMacro : + // a spurious message will appear when you use, for instance + // gdcm::FileHelper *fh = new gdcm::FileHelper( outputFileName ); + // to create outputFileName. + + // FIXME : if the upper comment is still usefull + // --> the constructor is not so good ... + + gdcmWarningMacro( "Cannot open file: " << Filename.c_str()); + delete Fp; + Fp = 0; + return 0; + //exit(1); // No function is allowed to leave the application instead + // of warning the caller + } + + uint16_t zero = 0; + Fp->read((char*)&zero, (size_t)2); + if ( Fp->eof() ) + { + CloseFile(); + return 0; + } + + //-- Broken ACR or DICOM with no Preamble; may start with a Shadow Group -- + // FIXME : We cannot be sure the preable is only zeroes.. + // (see ACUSON-24-YBR_FULL-RLE.dcm ) + if ( + zero == 0x0001 || zero == 0x0100 || zero == 0x0002 || zero == 0x0200 || + zero == 0x0003 || zero == 0x0300 || zero == 0x0004 || zero == 0x0400 || + zero == 0x0005 || zero == 0x0500 || zero == 0x0006 || zero == 0x0600 || + zero == 0x0007 || zero == 0x0700 || zero == 0x0008 || zero == 0x0800 ) + { + std::string msg = Util::Format( + "ACR/DICOM starting by 0x(%04x) at the beginning of the file\n", zero); + // FIXME : is it a Warning message, or a Debug message? + gdcmWarningMacro( msg.c_str() ); + return Fp; + } + + //-- DICOM -- + Fp->seekg(126L, std::ios::cur); // Once per Document + char dicm[4]; // = {' ',' ',' ',' '}; + Fp->read(dicm, (size_t)4); + if ( Fp->eof() ) + { + CloseFile(); + return 0; + } + if ( memcmp(dicm, "DICM", 4) == 0 ) + { + HasDCMPreamble = true; + return Fp; + } + + // -- Neither ACR/No Preamble Dicom nor DICOMV3 file + CloseFile(); + // Don't user Warning nor Error, not to pollute the output + // while directory recursive parsing ... + gdcmDebugMacro( "Neither ACR/No Preamble Dicom nor DICOMV3 file: " + << Filename.c_str()); + return 0; +} + +/** + * \brief closes the file + * @return TRUE if the close was successfull + */ +bool Document::CloseFile() +{ + if ( Fp ) + { + Fp->close(); + delete Fp; + Fp = 0; + } + return true; +} + +/** + * \brief Writes in a file all the Entries (Dicom Elements) + * @param fp file pointer on an already open file (actually: Output File Stream) + * @param filetype Type of the File to be written + * (ACR-NEMA, ExplicitVR, ImplicitVR) + */ +void Document::WriteContent(std::ofstream *fp, FileType filetype) +{ + // Skip if user wants to write an ACR-NEMA file + + if ( filetype == ImplicitVR || filetype == ExplicitVR || + filetype == JPEG ) + { + // writing Dicom File Preamble + char filePreamble[128]; + memset(filePreamble, 0, 128); + fp->write(filePreamble, 128); + fp->write("DICM", 4); + } + + /* + * \todo rewrite later, if really usefull + * - 'Group Length' element is optional in DICOM + * - but un-updated odd groups lengthes can causes pb + * (xmedcon breaker) + * + * if ( (filetype == ImplicitVR) || (filetype == ExplicitVR) ) + * UpdateGroupLength(false,filetype); + * if ( filetype == ACR) + * UpdateGroupLength(true,ACR); + * + * --> Computing group length for groups with embeded Sequences + * --> was too much tricky / we were [in a hurry / too lazy] + * --> We don't write the element 0x0000 (group length) + */ + + ElementSet::WriteContent(fp, filetype); // This one is recursive +} + +// ----------------------------------------- +// Content entries +/** + * \brief Loads (from disk) the element content + * when a string is not suitable + * @param group group number of the Entry + * @param elem element number of the Entry + */ +void Document::LoadEntryBinArea(uint16_t group, uint16_t elem) +{ + // Search the corresponding DocEntry + DocEntry *docElement = GetDocEntry(group, elem); + if ( !docElement ) + { + gdcmDebugMacro(std::hex << group << "|" << elem + << " doesn't exist" ); + return; + } + BinEntry *binElement = dynamic_cast<BinEntry *>(docElement); + if ( !binElement ) + { + gdcmWarningMacro(std::hex << group << "|" << elem + << "is NOT a BinEntry"); + return; + } + LoadEntryBinArea(binElement); +} + +/** + * \brief Loads (from disk) the element content + * when a string is not suitable + * @param elem Entry whose binArea is going to be loaded + */ +void Document::LoadEntryBinArea(BinEntry *elem) +{ + if (elem->GetBinArea() ) + return; + + bool openFile = !Fp; + if ( openFile ) + OpenFile(); + + size_t o =(size_t)elem->GetOffset(); + Fp->seekg(o, std::ios::beg); + + size_t l = elem->GetLength(); + uint8_t *a = new uint8_t[l]; + if ( !a ) + { + gdcmWarningMacro( "Cannot allocate BinEntry content for : " + << std::hex << elem->GetGroup() + << "|" << elem->GetElement() ); + return; + } + + // Read the data + Fp->read((char*)a, l); + if ( Fp->fail() || Fp->eof() ) + { + delete[] a; + return; + } + + elem->SetBinArea(a); + + if ( openFile ) + CloseFile(); +} + +/** + * \brief Loads the element while preserving the current + * underlying file position indicator as opposed to + * LoadDocEntry that modifies it. + * @param entry DocEntry whose value will be loaded. + */ +void Document::LoadDocEntrySafe(DocEntry *entry) +{ + if ( Fp ) + { + long PositionOnEntry = Fp->tellg(); + LoadDocEntry(entry); + Fp->seekg(PositionOnEntry, std::ios::beg); + } +} + +/** + * \brief Compares two documents, according to \ref DicomDir rules + * \warning Does NOT work with ACR-NEMA files + * \todo Find a trick to solve the pb (use RET fields ?) + * @param document to compare with current one + * @return true if 'smaller' + */ +bool Document::operator<(Document &document) +{ + // Patient Name + std::string s1 = GetEntryValue(0x0010,0x0010); + std::string s2 = document.GetEntryValue(0x0010,0x0010); + if (s1 < s2) + { + return true; + } + else if ( s1 > s2 ) + { + return false; + } + else + { + // Patient ID + s1 = GetEntryValue(0x0010,0x0020); + s2 = document.GetEntryValue(0x0010,0x0020); + if ( s1 < s2 ) + { + return true; + } + else if ( s1 > s2 ) + { + return false; + } + else + { + // Study Instance UID + s1 = GetEntryValue(0x0020,0x000d); + s2 = document.GetEntryValue(0x0020,0x000d); + if ( s1 < s2 ) + { + return true; + } + else if ( s1 > s2 ) + { + return false; + } + else + { + // Serie Instance UID + s1 = GetEntryValue(0x0020,0x000e); + s2 = document.GetEntryValue(0x0020,0x000e); + if ( s1 < s2 ) + { + return true; + } + else if ( s1 > s2 ) + { + return false; + } + } + } + } + return false; +} + +//----------------------------------------------------------------------------- +// Protected +/** + * \brief Reads a supposed to be 16 Bits integer + * (swaps it depending on processor endianness) + * @return read value + */ +uint16_t Document::ReadInt16() + throw( FormatError ) +{ + uint16_t g; + Fp->read ((char*)&g, (size_t)2); + if ( Fp->fail() ) + { + throw FormatError( "Document::ReadInt16()", " file error." ); + } + if ( Fp->eof() ) + { + throw FormatError( "Document::ReadInt16()", "EOF." ); + } + g = SwapShort(g); + return g; +} + +/** + * \brief Reads a supposed to be 32 Bits integer + * (swaps it depending on processor endianness) + * @return read value + */ +uint32_t Document::ReadInt32() + throw( FormatError ) +{ + uint32_t g; + Fp->read ((char*)&g, (size_t)4); + if ( Fp->fail() ) + { + throw FormatError( "Document::ReadInt32()", " file error." ); + } + if ( Fp->eof() ) + { + throw FormatError( "Document::ReadInt32()", "EOF." ); + } + g = SwapLong(g); + return g; +} + +/** + * \brief skips bytes inside the source file + * \warning NOT end user intended method ! + * @return + */ +void Document::SkipBytes(uint32_t nBytes) +{ + //FIXME don't dump the returned value + Fp->seekg((long)nBytes, std::ios::cur); +} + +/** + * \brief Re-computes the length of a ACR-NEMA/Dicom group from a DcmHeader + */ +int Document::ComputeGroup0002Length( /*FileType filetype*/ ) +{ + uint16_t gr; + std::string vr; + + int groupLength = 0; + bool found0002 = false; + + // for each zero-level Tag in the DCM Header + DocEntry *entry = GetFirstEntry(); + while( entry ) + { + gr = entry->GetGroup(); + + if ( gr == 0x0002 ) + { + found0002 = true; + + if ( entry->GetElement() != 0x0000 ) + { + vr = entry->GetVR(); + + //if ( (vr == "OB")||(vr == "OW")||(vr == "UT")||(vr == "SQ")) + // (no SQ, OW, UT in group 0x0002;) + if ( vr == "OB" ) + { + // explicit VR AND (OB, OW, SQ, UT) : 4 more bytes + groupLength += 4; + } + groupLength += 2 + 2 + 4 + entry->GetLength(); + } + } + else if (found0002 ) + break; + + entry = GetNextEntry(); + } + return groupLength; +} + +//----------------------------------------------------------------------------- +// Private +/** + * \brief Loads all the needed Dictionaries + * \warning NOT end user intended method ! + */ +void Document::Initialize() +{ + RefPubDict = Global::GetDicts()->GetDefaultPubDict(); + RefShaDict = NULL; + Filetype = Unknown; +} + +/** + * \brief Parses a DocEntrySet (Zero-level DocEntries or SQ Item DocEntries) + * @param set DocEntrySet we are going to parse ('zero level' or a SQItem) + * @param offset start of parsing + * @param l_max length to parse (meaningless when we are in 'delimitor mode') + * @param delim_mode : whether we are in 'delimitor mode' (l=0xffffff) or not + */ +void Document::ParseDES(DocEntrySet *set, long offset, + long l_max, bool delim_mode) +{ + DocEntry *newDocEntry; + ValEntry *newValEntry; + BinEntry *newBinEntry; + SeqEntry *newSeqEntry; + VRKey vr; + bool used; // will be set to false when something wrong happens to an Entry. + // (Entry will then be deleted) + bool delim_mode_intern = delim_mode; + bool first = true; + gdcmDebugMacro( "Enter in ParseDES, delim-mode " << delim_mode + << " at offset " << std::hex << "0x(" << offset << ")" ); + while (true) + { + if ( !delim_mode && ((long)(Fp->tellg())-offset) >= l_max) + { + break; + } + + newDocEntry = ReadNextDocEntry( ); + + // FIXME : + // Private tag, in IMplicit VR are defaulted as a BinEntry, + // Very often they are only composed of Printable characters, + // and could be defaulted as a ValEntry. + // It's too late to do the Job + // (we should check the value, but we know it after LoadDocEntry ...) + // --> in next gdcm major release let's unify ValEntry and BinEntry ! + + // Uncoment this printf line to be able to 'follow' the DocEntries + // when something *very* strange happens + + if ( !newDocEntry ) + { + break; + } + + // an Item Starter found elsewhere but the first position + // of a SeqEntry means previous entry was a Sequence + // but we didn't get it (private Sequence + Implicit VR) + // we have to backtrack. + if ( !first && newDocEntry->IsItemStarter() ) + { + // Debug message within the method ! + newDocEntry = Backtrack(newDocEntry); + } + else + { + PreviousDocEntry = newDocEntry; + } + + used = true; + newValEntry = dynamic_cast<ValEntry*>(newDocEntry); + newBinEntry = dynamic_cast<BinEntry*>(newDocEntry); + + if ( newValEntry || newBinEntry ) + { + //////////////////////////// ContentEntry + if ( newBinEntry ) + { + vr = newDocEntry->GetVR(); + if ( Filetype == ExplicitVR && + !Global::GetVR()->IsVROfBinaryRepresentable(vr) ) + { + ////// Neither ValEntry NOR BinEntry: should mean UNKOWN VR + gdcmWarningMacro( std::hex << newDocEntry->GetGroup() + << "|" << newDocEntry->GetElement() + << " : Neither Valentry, nor BinEntry." + "Probably unknown VR."); + } + + //////////////////// BinEntry or UNKOWN VR: + + // When "this" is a Document the Key is simply of the + // form ( group, elem )... + //if ( set == this ) // ( dynamic_cast< Document* > ( set ) ) + //{ + // newBinEntry->SetKey( newBinEntry->GetKey() ); + //} + // but when "this" is a SQItem, we are inserting this new + // valEntry in a sequence item, and the key has the + // generalized form (refer to \ref BaseTagKey): + + // time waste hunting + //if (SQItem *parentSQItem = dynamic_cast< SQItem* > ( set ) ) + //{ + // newBinEntry->SetKey( parentSQItem->GetBaseTagKey() + // + newBinEntry->GetKey() ); + //} + + if ( !set->AddEntry( newBinEntry ) ) + { + gdcmWarningMacro( "in ParseDES : cannot add a BinEntry " + << newBinEntry->GetKey() + << " (at offset : " + << newBinEntry->GetOffset() << " )" ); + used=false; + } + else + { + // Load only if we can add (not a duplicate key) + LoadDocEntry( newBinEntry ); + } + } // end BinEntry + else + { + /////////////////////// ValEntry + + // When "set" is a Document, then we are at the top of the + // hierarchy and the Key is simply of the form ( group, elem )... + //if ( set == this ) // ( dynamic_cast< Document* > ( set ) ) + //{ + // newValEntry->SetKey( newValEntry->GetKey() ); + //} + // ...but when "set" is a SQItem, we are inserting this new + // valEntry in a sequence item. Hence the key has the + // generalized form (refer to \ref BaseTagKey): + + // time waste hunting + //if (SQItem *parentSQItem = dynamic_cast< SQItem* > ( set ) ) + //{ + // newValEntry->SetKey( parentSQItem->GetBaseTagKey() + // + newValEntry->GetKey() ); + //} + + if ( !set->AddEntry( newValEntry ) ) + { + gdcmWarningMacro( "in ParseDES : cannot add a ValEntry " + << newValEntry->GetKey() + << " (at offset : " + << newValEntry->GetOffset() << " )" ); + used=false; + } + else + { + // Load only if we can add (not a duplicate key) + LoadDocEntry( newValEntry ); + } + + if ( newValEntry->GetElement() == 0x0000 ) // if on group length + { + if ( newValEntry->GetGroup()%2 != 0 ) // if Shadow Group + { + if ( LoadMode & LD_NOSHADOW ) // if user asked to skip shad.gr + { + std::string strLgrGroup = newValEntry->GetValue(); + int lgrGroup; + if ( strLgrGroup != GDCM_UNFOUND) + { + lgrGroup = atoi(strLgrGroup.c_str()); + Fp->seekg(lgrGroup, std::ios::cur); + //used = false; // never used + RemoveEntry( newDocEntry ); // Remove and delete + // bcc 5.5 is right "assigned a value that's never used" + // newDocEntry = 0; + continue; + } + } + } + } + + bool delimitor = newValEntry->IsItemDelimitor(); + + if ( (delimitor) || + (!delim_mode && ((long)(Fp->tellg())-offset) >= l_max) ) + { + if ( !used ) + delete newDocEntry; + break; + } + } + + // Just to make sure we are at the beginning of next entry. + SkipToNextDocEntry(newDocEntry); + } + else + { + /////////////////////// SeqEntry : VR = "SQ" + + unsigned long l = newDocEntry->GetReadLength(); + if ( l != 0 ) // don't mess the delim_mode for 'zero-length sequence' + { + if ( l == 0xffffffff ) + { + delim_mode_intern = true; + } + else + { + delim_mode_intern = false; + } + } + + if ( (LoadMode & LD_NOSHADOWSEQ) && ! delim_mode_intern ) + { + // User asked to skip SeQuences *only* if they belong to Shadow Group + if ( newDocEntry->GetGroup()%2 != 0 ) + { + Fp->seekg( l, std::ios::cur); + RemoveEntry( newDocEntry ); // Remove and delete + continue; + } + } + if ( (LoadMode & LD_NOSEQ) && ! delim_mode_intern ) + { + // User asked to skip *any* SeQuence + Fp->seekg( l, std::ios::cur); + RemoveEntry( newDocEntry ); // Remove and delete + continue; + } + // delay the dynamic cast as late as possible + newSeqEntry = dynamic_cast<SeqEntry*>(newDocEntry); + + // no other way to create the Delimitor ... + newSeqEntry->SetDelimitorMode( delim_mode_intern ); + + // At the top of the hierarchy, stands a Document. When "set" + // is a Document, then we are building the first depth level. + // Hence the SeqEntry we are building simply has a depth + // level of one: + if ( set == this ) // ( dynamic_cast< Document* > ( set ) ) + { + newSeqEntry->SetDepthLevel( 1 ); + } + // But when "set" is already a SQItem, we are building a nested + // sequence, and hence the depth level of the new SeqEntry + // we are building, is one level deeper: + + // time waste hunting + else if (SQItem *parentSQItem = dynamic_cast< SQItem* > ( set ) ) + { + newSeqEntry->SetDepthLevel( parentSQItem->GetDepthLevel() + 1 ); + } + + if ( l != 0 ) + { // Don't try to parse zero-length sequences + + gdcmDebugMacro( "Entry in ParseSQ, delim " << delim_mode_intern + << " at offset 0x(" << std::hex + << newDocEntry->GetOffset() << ")"); + + ParseSQ( newSeqEntry, + newDocEntry->GetOffset(), + l, delim_mode_intern); + + gdcmDebugMacro( "Exit from ParseSQ, delim " << delim_mode_intern); + + } + if ( !set->AddEntry( newSeqEntry ) ) + { + gdcmWarningMacro( "in ParseDES : cannot add a SeqEntry " + << newSeqEntry->GetKey() + << " (at offset : 0x(" + << newSeqEntry->GetOffset() << ") )" ); + used = false; + } + + if ( !delim_mode && ((long)(Fp->tellg())-offset) >= l_max) + { + if ( !used ) + delete newDocEntry; + break; + } + } // end SeqEntry : VR = "SQ" + + if ( !used ) + { + delete newDocEntry; + } + first = false; + } // end While + gdcmDebugMacro( "Exit from ParseDES, delim-mode " << delim_mode ); +} + +/** + * \brief Parses a Sequence ( SeqEntry after SeqEntry) + * @return parsed length for this level + */ +void Document::ParseSQ( SeqEntry *seqEntry, + long offset, long l_max, bool delim_mode) +{ + int SQItemNumber = 0; + bool dlm_mod; + long offsetStartCurrentSQItem = offset; + + while (true) + { + // the first time, we read the fff0,e000 of the first SQItem + DocEntry *newDocEntry = ReadNextDocEntry(); + + if ( !newDocEntry ) + { + gdcmWarningMacro("in ParseSQ : should never get here!"); + break; + } + if ( delim_mode ) + { + if ( newDocEntry->IsSequenceDelimitor() ) + { + seqEntry->SetDelimitationItem( newDocEntry ); + break; + } + } + if ( !delim_mode && ((long)(Fp->tellg())-offset) >= l_max) + { + delete newDocEntry; + break; + } + // create the current SQItem + SQItem *itemSQ = new SQItem( seqEntry->GetDepthLevel() ); + unsigned int l = newDocEntry->GetReadLength(); + + if ( l == 0xffffffff ) + { + dlm_mod = true; + } + else + { + dlm_mod = false; + } + + // remove fff0,e000, created out of the SQItem + delete newDocEntry; + // fill up the current SQItem, starting at the beginning of fff0,e000 + + ParseDES(itemSQ, offsetStartCurrentSQItem, l+8, dlm_mod); + + offsetStartCurrentSQItem = Fp->tellg(); + + seqEntry->AddSQItem( itemSQ, SQItemNumber ); + SQItemNumber++; + if ( !delim_mode && ((long)(Fp->tellg())-offset ) >= l_max ) + { + break; + } + } +} + +/** + * \brief When a private Sequence + Implicit VR is encountered + * we cannot guess it's a Sequence till we find the first + * Item Starter. We then backtrack to do the job. + * @param docEntry Item Starter that warned us + */ +DocEntry *Document::Backtrack(DocEntry *docEntry) +{ + // delete the Item Starter, built erroneously out of any Sequence + // it's not yet in the HTable/chained list + delete docEntry; + + // Get all info we can from PreviousDocEntry + uint16_t group = PreviousDocEntry->GetGroup(); + uint16_t elem = PreviousDocEntry->GetElement(); + uint32_t lgt = PreviousDocEntry->GetLength(); + long offset = PreviousDocEntry->GetOffset(); + + gdcmDebugMacro( "Backtrack :" << std::hex << group + << "|" << elem + << " at offset 0x(" <<offset << ")" ); + RemoveEntry( PreviousDocEntry ); + + // forge the Seq Entry + DocEntry *newEntry = NewSeqEntry(group, elem); + newEntry->SetLength(lgt); + newEntry->SetOffset(offset); + + // Move back to the beginning of the Sequence + + Fp->seekg(offset, std::ios::beg); // Only for Shadow Implicit VR SQ + return newEntry; +} + +/** + * \brief Loads (or not) the element content depending if its length exceeds + * or not the value specified with Document::SetMaxSizeLoadEntry() + * @param entry Header Entry (Dicom Element) to be dealt with + * @param forceLoad whether you want to force loading of 'long' elements + */ +void Document::LoadDocEntry(DocEntry *entry, bool forceLoad) +{ + uint16_t group = entry->GetGroup(); + uint16_t elem = entry->GetElement(); + std::string vr = entry->GetVR(); + uint32_t length = entry->GetLength(); + + Fp->seekg((long)entry->GetOffset(), std::ios::beg); + + // A SeQuence "contains" a set of Elements. + // (fffe e000) tells us an Element is beginning + // (fffe e00d) tells us an Element just ended + // (fffe e0dd) tells us the current SeQuence just ended + // (fffe 0000) is an 'impossible' tag value, + // found in MR-PHILIPS-16-Multi-Seq.dcm + if ( (group == 0xfffe && elem != 0x0000 ) || vr == "SQ" ) + { + // NO more value field for SQ ! + return; + } + + // When the length is zero things are easy: + if ( length == 0 ) + { + ((ValEntry *)entry)->SetValue(""); + return; + } + + // The elements whose length is bigger than the specified upper bound + // are not loaded. Instead we leave a short notice on the offset of + // the element content and it's length. + + itksys_ios::ostringstream s; + + if (!forceLoad) + { + if (length > MaxSizeLoadEntry) + { + if (BinEntry *binEntryPtr = dynamic_cast< BinEntry* >(entry) ) + { + s << GDCM_NOTLOADED; + s << " Ad.:" << (long)entry->GetOffset(); + s << " x(" << std::hex << entry->GetOffset() << ")"; + s << std::dec; + s << " Lgt:" << entry->GetLength(); + s << " x(" << std::hex << entry->GetLength() << ")"; + binEntryPtr->SetValue(s.str()); + } + else if (ValEntry *valEntryPtr = dynamic_cast< ValEntry* >(entry) ) + { + s << GDCM_NOTLOADED; + s << " Address:" << (long)entry->GetOffset(); + s << " Length:" << entry->GetLength(); + s << " x(" << std::hex << entry->GetLength() << ")"; + valEntryPtr->SetValue(s.str()); + } + else + { + // fusible + gdcmErrorMacro( "MaxSizeLoadEntry exceeded, neither a BinEntry " + << "nor a ValEntry ?! Should never print that !" ); + } + + // to be sure we are at the end of the value ... + // Fp->seekg((long)entry->GetOffset()+(long)entry->GetLength(), + // std::ios::beg); + return; + } + } + + // When we find a BinEntry not very much can be done : + if (BinEntry *binEntryPtr = dynamic_cast< BinEntry* >(entry) ) + { + s << GDCM_BINLOADED; + binEntryPtr->SetValue(s.str()); + LoadEntryBinArea(binEntryPtr); // last one, not to erase length ! + return; + } + + if ( IsDocEntryAnInteger(entry) ) + { + uint32_t NewInt; + int nbInt; + // When short integer(s) are expected, read and convert the following + // (n * 2) characters properly i.e. consider them as short integers as + // opposed to strings. + // Elements with Value Multiplicity > 1 + // contain a set of integers (not a single one) + if (vr == "US" || vr == "SS") + { + nbInt = length / 2; + NewInt = ReadInt16(); + s << NewInt; + if (nbInt > 1) + { + for (int i=1; i < nbInt; i++) + { + s << '\\'; + NewInt = ReadInt16(); + s << NewInt; + } + } + } + // See above comment on multiple integers (mutatis mutandis). + else if (vr == "UL" || vr == "SL") + { + nbInt = length / 4; + NewInt = ReadInt32(); + s << NewInt; + if (nbInt > 1) + { + for (int i=1; i < nbInt; i++) + { + s << '\\'; + NewInt = ReadInt32(); + s << NewInt; + } + } + } +#ifdef GDCM_NO_ANSI_STRING_STREAM + s << std::ends; // to avoid oddities on Solaris +#endif //GDCM_NO_ANSI_STRING_STREAM + + ((ValEntry *)entry)->SetValue(s.str()); + return; + } + + // FIXME: We need an additional byte for storing \0 that is not on disk + char *str = new char[length+1]; + Fp->read(str, (size_t)length); + str[length] = '\0'; //this is only useful when length is odd + // Special DicomString call to properly handle \0 and even length + std::string newValue; + if ( length % 2 ) + { + newValue = Util::DicomString(str, length+1); + gdcmWarningMacro("Warning: bad length: " << length << + " For string :" << newValue.c_str()); + // Since we change the length of string update it length + //entry->SetReadLength(length+1); + } + else + { + newValue = Util::DicomString(str, length); + } + delete[] str; + + if ( ValEntry *valEntry = dynamic_cast<ValEntry* >(entry) ) + { + if ( Fp->fail() || Fp->eof()) + { + if ( Fp->fail() ) + gdcmWarningMacro("--> fail"); + + gdcmWarningMacro("Unread element value " << valEntry->GetKey() + << " lgt : " << valEntry->GetReadLength() + << " at " << std::hex << valEntry->GetOffset()); + valEntry->SetValue(GDCM_UNREAD); + return; + } + +// if ( vr == "UI" ) +// { +// // Because of correspondance with the VR dic +// valEntry->SetValue(newValue); +// } +// else +// { +// valEntry->SetValue(newValue); +// } + +// Anybody remembers the genesis of strange previous (commented out) code? + valEntry->SetValue(newValue); + + } + else + { + gdcmWarningMacro("Should have a ValEntry, here ! " << valEntry->GetKey() + << " lgt : " << valEntry->GetReadLength() + << " at " << std::hex << valEntry->GetOffset()); + } +} + +/** + * \brief Find the value Length of the passed Doc Entry + * @param entry Header Entry whose length of the value shall be loaded. + */ +void Document::FindDocEntryLength( DocEntry *entry ) + throw ( FormatError ) +{ + std::string vr = entry->GetVR(); + uint16_t length16; + + if ( Filetype == ExplicitVR && !entry->IsImplicitVR() ) + { + if ( vr == "OB" || vr == "OW" || vr == "SQ" || vr == "UT" + || vr == "UN" ) + { + // The following reserved two bytes (see PS 3.5-2003, section + // "7.1.2 Data element structure with explicit vr", p 27) must be + // skipped before proceeding on reading the length on 4 bytes. + + Fp->seekg( 2L, std::ios::cur); // Once per OW,OB,SQ DocEntry + uint32_t length32 = ReadInt32(); + + if ( (vr == "OB" || vr == "OW") && length32 == 0xffffffff ) + { + uint32_t lengthOB; + try + { + lengthOB = FindDocEntryLengthOBOrOW();// for encapsulation of encoded pixel + } + catch ( FormatUnexpected ) + { + // Computing the length failed (this happens with broken + // files like gdcm-JPEG-LossLess3a.dcm). We still have a + // chance to get the pixels by deciding the element goes + // until the end of the file. Hence we artificially fix the + // the length and proceed. + gdcmWarningMacro( " Computing the length failed for " << + entry->GetKey() <<" in " <<GetFileName()); + + long currentPosition = Fp->tellg(); // Only for gdcm-JPEG-LossLess3a.dcm-like + Fp->seekg(0L,std::ios::end); // Only for gdcm-JPEG-LossLess3a.dcm-like + + long lengthUntilEOF = (long)(Fp->tellg())-currentPosition; // Only for gdcm-JPEG-LossLess3a.dcm-like + Fp->seekg(currentPosition, std::ios::beg); // Only for gdcm-JPEG-LossLess3a.dcm-like + + entry->SetReadLength(lengthUntilEOF); + entry->SetLength(lengthUntilEOF); + return; + } + entry->SetReadLength(lengthOB); + entry->SetLength(lengthOB); + return; + } + FixDocEntryFoundLength(entry, length32); + return; + } + + // Length is encoded on 2 bytes. + length16 = ReadInt16(); + + // 0xffff means that we deal with 'No Length' Sequence + // or 'No Length' SQItem + if ( length16 == 0xffff) + { + length16 = 0; + } + FixDocEntryFoundLength( entry, (uint32_t)length16 ); + return; + } + else + { + // Either implicit VR or a non DICOM conformal (see note below) explicit + // VR that ommited the VR of (at least) this element. Farts happen. + // [Note: according to the part 5, PS 3.5-2001, section 7.1 p25 + // on Data elements "Implicit and Explicit VR Data Elements shall + // not coexist in a Data Set and Data Sets nested within it".] + // Length is on 4 bytes. + + // Well ... group 0002 is always coded in 'Explicit VR Litle Endian' + // even if Transfer Syntax is 'Implicit VR ...' + // --> Except for 'Implicit VR Big Endian Transfer Syntax GE Private' + + FixDocEntryFoundLength( entry, ReadInt32() ); + return; + } +} + +/** + * \brief Find the Length till the next sequence delimiter + * \warning NOT end user intended method ! + * @return + */ +uint32_t Document::FindDocEntryLengthOBOrOW() + throw( FormatUnexpected ) +{ + // See PS 3.5-2001, section A.4 p. 49 on encapsulation of encoded pixel data. + long positionOnEntry = Fp->tellg(); // Only for OB,OW DataElements + + bool foundSequenceDelimiter = false; + uint32_t totalLength = 0; + + while ( !foundSequenceDelimiter ) + { + uint16_t group; + uint16_t elem; + try + { + group = ReadInt16(); + elem = ReadInt16(); + } + catch ( FormatError ) + { + throw FormatError("Unexpected end of file encountered during ", + "Document::FindDocEntryLengthOBOrOW()"); + } + // We have to decount the group and element we just read + totalLength += 4; + if ( group != 0xfffe || ( ( elem != 0xe0dd ) && ( elem != 0xe000 ) ) ) + { + gdcmWarningMacro( + "Neither an Item tag nor a Sequence delimiter tag on :" + << std::hex << group << " , " << elem + << ")" ); + + Fp->seekg(positionOnEntry, std::ios::beg); // Once per fragment (if any) of OB,OW DataElements + throw FormatUnexpected( + "Neither an Item tag nor a Sequence delimiter tag."); + } + if ( elem == 0xe0dd ) + { + foundSequenceDelimiter = true; + } + uint32_t itemLength = ReadInt32(); + // We add 4 bytes since we just read the ItemLength with ReadInt32 + totalLength += itemLength + 4; + SkipBytes(itemLength); + + if ( foundSequenceDelimiter ) + { + break; + } + } + Fp->seekg( positionOnEntry, std::ios::beg); // Only for OB,OW DataElements + return totalLength; +} + +/** + * \brief Find the Value Representation of the current Dicom Element. + * @return Value Representation of the current Entry + */ +std::string Document::FindDocEntryVR() +{ + if ( Filetype != ExplicitVR ) + return GDCM_UNKNOWN; + + long positionOnEntry = Fp->tellg(); + // Warning: we believe this is explicit VR (Value Representation) because + // we used a heuristic that found "UL" in the first tag. Alas this + // doesn't guarantee that all the tags will be in explicit VR. In some + // cases (see e-film filtered files) one finds implicit VR tags mixed + // within an explicit VR file. Hence we make sure the present tag + // is in explicit VR and try to fix things if it happens not to be + // the case. + + char vr[3]; + Fp->read (vr, (size_t)2); + vr[2] = 0; + + if ( !CheckDocEntryVR(vr) ) + { + Fp->seekg(positionOnEntry, std::ios::beg); + return GDCM_UNKNOWN; + } + return vr; +} + +/** + * \brief Check the correspondance between the VR of the header entry + * and the taken VR. If they are different, the header entry is + * updated with the new VR. + * @param vr Dicom Value Representation + * @return false if the VR is incorrect or if the VR isn't referenced + * otherwise, it returns true +*/ +bool Document::CheckDocEntryVR(VRKey vr) +{ + if ( !Global::GetVR()->IsValidVR(vr) ) + return false; + + return true; +} + +/** + * \brief Get the transformed value of the header entry. The VR value + * is used to define the transformation to operate on the value + * \warning NOT end user intended method ! + * @param entry entry to tranform + * @return Transformed entry value + */ +std::string Document::GetDocEntryValue(DocEntry *entry) +{ + if ( IsDocEntryAnInteger(entry) && entry->IsImplicitVR() ) + { + std::string val = ((ValEntry *)entry)->GetValue(); + std::string vr = entry->GetVR(); + uint32_t length = entry->GetLength(); + itksys_ios::ostringstream s; + int nbInt; + + // When short integer(s) are expected, read and convert the following + // n * 2 bytes properly i.e. as a multivaluated strings + // (each single value is separated fromthe next one by '\' + // as usual for standard multivaluated filels + // Elements with Value Multiplicity > 1 + // contain a set of short integers (not a single one) + + if ( vr == "US" || vr == "SS" ) + { + uint16_t newInt16; + + nbInt = length / 2; + for (int i=0; i < nbInt; i++) + { + if ( i != 0 ) + { + s << '\\'; + } + newInt16 = ( val[2*i+0] & 0xFF ) + ( ( val[2*i+1] & 0xFF ) << 8); + newInt16 = SwapShort( newInt16 ); + s << newInt16; + } + } + + // When integer(s) are expected, read and convert the following + // n * 4 bytes properly i.e. as a multivaluated strings + // (each single value is separated fromthe next one by '\' + // as usual for standard multivaluated filels + // Elements with Value Multiplicity > 1 + // contain a set of integers (not a single one) + else if ( vr == "UL" || vr == "SL" ) + { + uint32_t newInt32; + + nbInt = length / 4; + for (int i=0; i < nbInt; i++) + { + if ( i != 0) + { + s << '\\'; + } + newInt32 = ( val[4*i+0] & 0xFF ) + + (( val[4*i+1] & 0xFF ) << 8 ) + + (( val[4*i+2] & 0xFF ) << 16 ) + + (( val[4*i+3] & 0xFF ) << 24 ); + newInt32 = SwapLong( newInt32 ); + s << newInt32; + } + } +#ifdef GDCM_NO_ANSI_STRING_STREAM + s << std::ends; // to avoid oddities on Solaris +#endif //GDCM_NO_ANSI_STRING_STREAM + return s.str(); + } + return ((ValEntry *)entry)->GetValue(); +} + +/** + * \brief Get the reverse transformed value of the header entry. The VR + * value is used to define the reverse transformation to operate on + * the value + * \warning NOT end user intended method ! + * @param entry Entry to reverse transform + * @return Reverse transformed entry value + */ +std::string Document::GetDocEntryUnvalue(DocEntry *entry) +{ + if ( IsDocEntryAnInteger(entry) && entry->IsImplicitVR() ) + { + std::string vr = entry->GetVR(); + std::vector<std::string> tokens; + itksys_ios::ostringstream s; + + if ( vr == "US" || vr == "SS" ) + { + uint16_t newInt16; + + tokens.erase( tokens.begin(), tokens.end()); // clean any previous value + Util::Tokenize (((ValEntry *)entry)->GetValue(), tokens, "\\"); + for (unsigned int i=0; i<tokens.size(); i++) + { + newInt16 = atoi(tokens[i].c_str()); + s << ( newInt16 & 0xFF ) + << (( newInt16 >> 8 ) & 0xFF ); + } + tokens.clear(); + } + if ( vr == "UL" || vr == "SL") + { + uint32_t newInt32; + + tokens.erase(tokens.begin(),tokens.end()); // clean any previous value + Util::Tokenize (((ValEntry *)entry)->GetValue(), tokens, "\\"); + for (unsigned int i=0; i<tokens.size();i++) + { + newInt32 = atoi(tokens[i].c_str()); + s << (char)( newInt32 & 0xFF ) + << (char)(( newInt32 >> 8 ) & 0xFF ) + << (char)(( newInt32 >> 16 ) & 0xFF ) + << (char)(( newInt32 >> 24 ) & 0xFF ); + } + tokens.clear(); + } + +#ifdef GDCM_NO_ANSI_STRING_STREAM + s << std::ends; // to avoid oddities on Solaris +#endif //GDCM_NO_ANSI_STRING_STREAM + return s.str(); + } + + return ((ValEntry *)entry)->GetValue(); +} + +/** + * \brief Skip a given Header Entry + * \warning NOT end user intended method ! + * @param entry entry to skip + */ +void Document::SkipDocEntry(DocEntry *entry) +{ + SkipBytes(entry->GetLength()); +} + +/** + * \brief Skips to the beginning of the next Header Entry + * \warning NOT end user intended method ! + * @param currentDocEntry entry to skip + */ +void Document::SkipToNextDocEntry(DocEntry *currentDocEntry) +{ + long l = currentDocEntry->GetReadLength(); + if ( l == -1 ) // length = 0xffff shouldn't appear here ... + // ... but PMS imagers happen ! + return; + Fp->seekg((size_t)(currentDocEntry->GetOffset()), std::ios::beg); //FIXME :each DocEntry + if (currentDocEntry->GetGroup() != 0xfffe) // for fffe pb + { + Fp->seekg( l,std::ios::cur); //FIXME :each DocEntry + } +} + +/** + * \brief When the length of an element value is obviously wrong (because + * the parser went Jabberwocky) one can hope improving things by + * applying some heuristics. + * @param entry entry to check + * @param foundLength first assumption about length + */ +void Document::FixDocEntryFoundLength(DocEntry *entry, + uint32_t foundLength) +{ + entry->SetReadLength( foundLength );// will be updated only if a bug is found + if ( foundLength == 0xffffffff) + { + foundLength = 0; + } + + uint16_t gr = entry->GetGroup(); + uint16_t elem = entry->GetElement(); + + if ( foundLength % 2) + { + gdcmWarningMacro( "Warning : Tag with uneven length " << foundLength + << " in x(" << std::hex << gr << "," << elem <<")"); + } + + //////// Fix for some naughty General Electric images. + // Allthough not recent many such GE corrupted images are still present + // on Creatis hard disks. Hence this fix shall remain when such images + // are no longer in use (we are talking a few years, here)... + // Note: XMedCon probably uses such a trick since it is able to read + // those pesky GE images ... + if ( foundLength == 13) + { + // Only happens for this length ! + if ( gr != 0x0008 || ( elem != 0x0070 && elem != 0x0080 ) ) + { + foundLength = 10; + entry->SetReadLength(10); // a bug is to be fixed !? + } + } + + //////// Fix for some brain-dead 'Leonardo' Siemens images. + // Occurence of such images is quite low (unless one leaves close to a + // 'Leonardo' source. Hence, one might consider commenting out the + // following fix on efficiency reasons. + else if ( gr == 0x0009 && ( elem == 0x1113 || elem == 0x1114 ) ) + { + foundLength = 4; + entry->SetReadLength(4); // a bug is to be fixed ! + } + + else if ( entry->GetVR() == "SQ" ) + { + foundLength = 0; // ReadLength is unchanged + } + + //////// We encountered a 'delimiter' element i.e. a tag of the form + // "fffe|xxxx" which is just a marker. Delimiters length should not be + // taken into account. + else if ( gr == 0xfffe ) + { + // According to the norm, fffe|0000 shouldn't exist. BUT the Philips + // image gdcmData/gdcm-MR-PHILIPS-16-Multi-Seq.dcm happens to + // causes extra troubles... + if ( entry->GetElement() != 0x0000 ) + { + foundLength = 0; + } + } + entry->SetLength(foundLength); +} + +/** + * \brief Apply some heuristics to predict whether the considered + * element value contains/represents an integer or not. + * @param entry The element value on which to apply the predicate. + * @return The result of the heuristical predicate. + */ +bool Document::IsDocEntryAnInteger(DocEntry *entry) +{ + uint16_t elem = entry->GetElement(); + uint16_t group = entry->GetGroup(); + const std::string &vr = entry->GetVR(); + uint32_t length = entry->GetLength(); + + // When we have some semantics on the element we just read, and if we + // a priori know we are dealing with an integer, then we shall be + // able to swap it's element value properly. + if ( elem == 0 ) // This is the group length of the group + { + if ( length == 4 ) + { + return true; + } + else + { + // Although this should never happen, still some images have a + // corrupted group length [e.g. have a glance at offset x(8336) of + // gdcmData/gdcm-MR-PHILIPS-16-Multi-Seq.dcm. + // Since for dicom compliant and well behaved headers, the present + // test is useless (and might even look a bit paranoid), when we + // encounter such an ill-formed image, we simply display a warning + // message and proceed on parsing (while crossing fingers). + long filePosition = Fp->tellg(); // Only when elem 0x0000 length is not 4 (?!?) + gdcmWarningMacro( "Erroneous Group Length element length on : (" + << std::hex << group << " , " << elem + << ") -before- position x(" << filePosition << ")" + << "lgt : " << length ); + } + } + + if ( vr == "UL" || vr == "US" || vr == "SL" || vr == "SS" ) + { + return true; + } + return false; +} + +/** + * \brief Discover what the swap code is (among little endian, big endian, + * bad little endian, bad big endian). + * sw is set + * @return false when we are absolutely sure + * it's neither ACR-NEMA nor DICOM + * true when we hope ours assuptions are OK + */ +bool Document::CheckSwap() +{ + uint32_t s32; + uint16_t s16; + + char deb[256]; + + // First, compare HostByteOrder and NetworkByteOrder in order to + // determine if we shall need to swap bytes (i.e. the Endian type). + bool net2host = Util::IsCurrentProcessorBigEndian(); + + // The easiest case is the one of a 'true' DICOM header, we just have + // to look for the string "DICM" inside the file preamble. + Fp->read(deb, 256); + + char *entCur = deb + 128; + if ( memcmp(entCur, "DICM", (size_t)4) == 0 ) + { + gdcmDebugMacro( "Looks like DICOM Version3 (preamble + DCM)" ); + + // Group 0002 should always be VR, and the first element 0000 + // Let's be carefull (so many wrong headers ...) + // and determine the value representation (VR) : + // Let's skip to the first element (0002,0000) and check there if we find + // "UL" - or "OB" if the 1st one is (0002,0001) -, + // in which case we (almost) know it is explicit VR. + // WARNING: if it happens to be implicit VR then what we will read + // is the length of the group. If this ascii representation of this + // length happens to be "UL" then we shall believe it is explicit VR. + // We need to skip : + // * the 128 bytes of File Preamble (often padded with zeroes), + // * the 4 bytes of "DICM" string, + // * the 4 bytes of the first tag (0002, 0000),or (0002, 0001) + // i.e. a total of 136 bytes. + entCur = deb + 136; + + // group 0x0002 *is always* Explicit VR Sometimes , + // even if elem 0002,0010 (Transfer Syntax) tells us the file is + // *Implicit* VR (see former 'gdcmData/icone.dcm') + + if ( memcmp(entCur, "UL", (size_t)2) == 0 || + memcmp(entCur, "OB", (size_t)2) == 0 || + memcmp(entCur, "UI", (size_t)2) == 0 || + memcmp(entCur, "CS", (size_t)2) == 0 ) // CS, to remove later + // when Write DCM *adds* + // FIXME + // Use Document::dicom_vr to test all the possibilities + // instead of just checking for UL, OB and UI !? group 0000 + { + Filetype = ExplicitVR; + gdcmDebugMacro( "Group 0002 : Explicit Value Representation"); + } + else + { + Filetype = ImplicitVR; + gdcmWarningMacro( "Group 0002 :Not an explicit Value Representation;" + << "Looks like a bugged Header!"); + } + + if ( net2host ) + { + SwapCode = 4321; + gdcmDebugMacro( "HostByteOrder != NetworkByteOrder, SwapCode = 4321"); + } + else + { + SwapCode = 1234; + gdcmDebugMacro( "HostByteOrder = NetworkByteOrder, SwapCode = 1234"); + } + + // Position the file position indicator at first tag + // (i.e. after the file preamble and the "DICM" string). + + Fp->seekg ( 132L, std::ios::beg); // Once per Document + return true; + } // ------------------------------- End of DicomV3 ---------------- + + // Alas, this is not a DicomV3 file and whatever happens there is no file + // preamble. We can reset the file position indicator to where the data + // is (i.e. the beginning of the file). + + gdcmWarningMacro( "Not a Kosher DICOM Version3 file (no preamble)"); + + Fp->seekg(0, std::ios::beg); // Once per ACR-NEMA Document + + // Let's check 'No Preamble Dicom File' : + // Should start with group 0x0002 + // and be Explicit Value Representation + + s16 = *((uint16_t *)(deb)); + SwapCode = 0; + switch ( s16 ) + { + case 0x0002 : + SwapCode = 1234; + entCur = deb + 4; + break; + case 0x0200 : + SwapCode = 4321; + entCur = deb + 6; + } + + if ( SwapCode != 0 ) + { + if ( memcmp(entCur, "UL", (size_t)2) == 0 || + memcmp(entCur, "OB", (size_t)2) == 0 || + memcmp(entCur, "UI", (size_t)2) == 0 || + memcmp(entCur, "SH", (size_t)2) == 0 || + memcmp(entCur, "AE", (size_t)2) == 0 || + memcmp(entCur, "OB", (size_t)2) == 0 ) + { + Filetype = ExplicitVR; // FIXME : not enough to say it's Explicit + // Wait untill reading Transfer Syntax + gdcmDebugMacro( "Group 0002 : Explicit Value Representation"); + return true; + } + } +// ------------------------------- End of 'No Preamble' DicomV3 ------------- + + // Our next best chance would be to be considering a 'clean' ACR/NEMA file. + // By clean we mean that the length of the first group is written down. + // If this is the case and since the length of the first group HAS to be + // four (bytes), then determining the proper swap code is straightforward. + + entCur = deb + 4; + // We assume the array of char we are considering contains the binary + // representation of a 32 bits integer. Hence the following dirty + // trick : + s32 = *((uint32_t *)(entCur)); + switch( s32 ) + { + case 0x00040000 : + SwapCode = 3412; + Filetype = ACR; + return true; + case 0x04000000 : + SwapCode = 4321; + Filetype = ACR; + return true; + case 0x00000400 : + SwapCode = 2143; + Filetype = ACR; + return true; + case 0x00000004 : + SwapCode = 1234; + Filetype = ACR; + return true; + default : + // We are out of luck. It is not a DicomV3 nor a 'clean' ACR/NEMA file. + // It is time for despaired wild guesses. + // So, let's check if this file wouldn't happen to be 'dirty' ACR/NEMA, + // i.e. the 'group length' element is not present : + + // check the supposed-to-be 'group number' + // in ( 0x0001 .. 0x0008 ) + // to determine ' SwapCode' value . + // Only 0 or 4321 will be possible + // (no oportunity to check for the formerly well known + // ACR-NEMA 'Bad Big Endian' or 'Bad Little Endian' + // if unsuccessfull (i.e. neither 0x0002 nor 0x0200 etc-3, 4, ..., 8-) + // the file IS NOT ACR-NEMA nor DICOM V3 + // Find a trick to tell it the caller... + + s16 = *((uint16_t *)(deb)); + + switch ( s16 ) + { + case 0x0001 : + case 0x0002 : + case 0x0003 : + case 0x0004 : + case 0x0005 : + case 0x0006 : + case 0x0007 : + case 0x0008 : + SwapCode = 1234; + Filetype = ACR; + return true; + case 0x0100 : + case 0x0200 : + case 0x0300 : + case 0x0400 : + case 0x0500 : + case 0x0600 : + case 0x0700 : + case 0x0800 : + SwapCode = 4321; + Filetype = ACR; + return true; + default : + gdcmWarningMacro("ACR/NEMA unfound swap info (Hopeless !)"); + Filetype = Unknown; + return false; + } + } +} + +/** + * \brief Change the Byte Swap code. + */ +void Document::SwitchByteSwapCode() +{ + gdcmDebugMacro( "Switching Byte Swap code from "<< SwapCode + << " at: 0x" << std::hex << Fp->tellg() ); // Only when DEBUG + if ( SwapCode == 1234 ) + { + SwapCode = 4321; + } + else if ( SwapCode == 4321 ) + { + SwapCode = 1234; + } + else if ( SwapCode == 3412 ) + { + SwapCode = 2143; + } + else if ( SwapCode == 2143 ) + { + SwapCode = 3412; + } + gdcmDebugMacro( " Into: "<< SwapCode ); +} + +/** + * \brief during parsing, Header Elements too long are not loaded in memory + * @param newSize new size + */ +void Document::SetMaxSizeLoadEntry(long newSize) +{ + if ( newSize < 0 ) + { + return; + } + if ((uint32_t)newSize >= (uint32_t)0xffffffff ) + { + MaxSizeLoadEntry = 0xffffffff; + return; + } + MaxSizeLoadEntry = newSize; + IsDocumentModified = true; +} + +/** + * \brief Read the next tag WITHOUT loading it's value + * (read the 'Group Number', the 'Element Number', + * gets the Dict Entry + * gets the VR, gets the length, gets the offset value) + * @return On succes : the newly created DocEntry, NULL on failure. + */ +DocEntry *Document::ReadNextDocEntry() +{ + uint16_t group; + uint16_t elem; + + try + { + group = ReadInt16(); + elem = ReadInt16(); + } + catch ( FormatError ) + { + // We reached the EOF (or an error occured) therefore + // header parsing has to be considered as finished. + return 0; + } + + // Sometimes file contains groups of tags with reversed endianess. + HandleBrokenEndian(group, elem); + + // In 'true DICOM' files Group 0002 is always little endian + if ( HasDCMPreamble ) + HandleOutOfGroup0002(group, elem); + + std::string vr = FindDocEntryVR(); + std::string realVR = vr; + + if ( vr == GDCM_UNKNOWN ) + { + if ( elem == 0x0000 ) // Group Length + { + realVR = "UL"; // must be UL + } + else if (group%2 == 1 && (elem >= 0x0010 && elem <=0x00ff )) + { + // DICOM PS 3-5 7.8.1 a) states that those + // (gggg-0010->00FF where gggg is odd) attributes have to be LO + realVR = "LO"; + } + else + { + DictEntry *dictEntry = GetDictEntry(group,elem); + if ( dictEntry ) + { + realVR = dictEntry->GetVR(); + } + } + } + + DocEntry *newEntry; + if ( Global::GetVR()->IsVROfSequence(realVR) ) + newEntry = NewSeqEntry(group, elem); + else if ( Global::GetVR()->IsVROfStringRepresentable(realVR) ) + newEntry = NewValEntry(group, elem, realVR); + else + newEntry = NewBinEntry(group, elem, realVR); + + if ( vr == GDCM_UNKNOWN ) + { + if ( Filetype == ExplicitVR ) + { + // We thought this was explicit VR, but we end up with an + // implicit VR tag. Let's backtrack. + if ( newEntry->GetGroup() != 0xfffe ) + { + std::string msg; + int offset = Fp->tellg(); + msg = Util::Format("Entry (%04x,%04x) at 0x(%x) should be Explicit VR\n", + newEntry->GetGroup(), newEntry->GetElement(), offset ); + gdcmWarningMacro( msg.c_str() ); + } + } + newEntry->SetImplicitVR(); + } + + try + { + FindDocEntryLength(newEntry); + } + catch ( FormatError ) + { + // Call it quits + delete newEntry; + return 0; + } + + newEntry->SetOffset(Fp->tellg()); // for each DocEntry + + return newEntry; +} + +/** + * \brief Handle broken private tag from Philips NTSCAN + * where the endianess is being switched to BigEndian + * for no apparent reason + * @return no return + */ +void Document::HandleBrokenEndian(uint16_t &group, uint16_t &elem) +{ + // Endian reversion. + // Some files contain groups of tags with reversed endianess. + static int reversedEndian = 0; + // try to fix endian switching in the middle of headers + if ((group == 0xfeff) && (elem == 0x00e0)) + { + // start endian swap mark for group found + gdcmDebugMacro( "Start endian swap mark found." ); + reversedEndian++; + SwitchByteSwapCode(); + // fix the tag + group = 0xfffe; + elem = 0xe000; + } + else if (group == 0xfffe && elem == 0xe00d && reversedEndian) + { + // end of reversed endian group + gdcmDebugMacro( "End of reversed endian." ); + reversedEndian--; + SwitchByteSwapCode(); + } + else if (group == 0xfeff && elem == 0xdde0) + { + // reversed Sequence Terminator found + // probabely a bug in the header ! + // Do what you want, it breaks ! + //reversedEndian--; + //SwitchByteSwapCode(); + gdcmWarningMacro( "Should never get here! reversed Sequence Terminator!" ); + // fix the tag + group = 0xfffe; + elem = 0xe0dd; + } + else if (group == 0xfffe && elem == 0xe0dd) + { + gdcmDebugMacro( "Straight Sequence Terminator." ); + } +} + +/** + * \brief Group 0002 is always coded Little Endian + * whatever Transfer Syntax is + * @return no return + */ +void Document::HandleOutOfGroup0002(uint16_t &group, uint16_t &elem) +{ + // Endian reversion. + // Some files contain groups of tags with reversed endianess. + if ( !Group0002Parsed && group != 0x0002) + { + Group0002Parsed = true; + // we just came out of group 0002 + // if Transfer Syntax is Big Endian we have to change CheckSwap + + std::string ts = GetTransferSyntax(); + if ( !Global::GetTS()->IsTransferSyntax(ts) ) + { + gdcmWarningMacro("True DICOM File, with NO Tansfer Syntax: " << ts ); + return; + } + + // Group 0002 is always 'Explicit ...' + // even when Transfer Syntax says 'Implicit ..." + + if ( Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::ImplicitVRLittleEndian ) + { + Filetype = ImplicitVR; + } + + // FIXME Strangely, this works with + //'Implicit VR BigEndian Transfer Syntax' (GE Private) + // + // --> Probabely normal, since we considered we never have + // to trust manufacturers. + // (we find very often 'Implicit VR' tag, + // even when Transfer Syntax tells us it's Explicit ... + if ( Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::ExplicitVRBigEndian ) + { + gdcmDebugMacro("Transfer Syntax Name = [" + << GetTransferSyntaxName() << "]" ); + SwitchByteSwapCode(); + group = SwapShort(group); + elem = SwapShort(elem); + } + } +} + +//----------------------------------------------------------------------------- +// Print + +//----------------------------------------------------------------------------- +} // end namespace gdcm diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmDocument.h b/Utilities/ITK/Utilities/gdcm/src/gdcmDocument.h new file mode 100644 index 0000000000000000000000000000000000000000..312657504edbcebd2db16230cf91be78b10b8ed1 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmDocument.h @@ -0,0 +1,245 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmDocument.h,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:39 $ + Version: $Revision: 1.9 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#ifndef GDCMDOCUMENT_H +#define GDCMDOCUMENT_H + +#include "gdcmVR.h" +#include "gdcmDict.h" +#include "gdcmElementSet.h" +#include "gdcmException.h" +#include "gdcmDebug.h" + +#include <map> +#include <list> +#include <fstream> + +namespace gdcm +{ +class ValEntry; +class BinEntry; +class SeqEntry; +class Dict; + +//----------------------------------------------------------------------------- +/** + * \brief Derived by both gdcm::File and gdcm::DicomDir + */ +class GDCM_EXPORT Document : public ElementSet +{ +public: + +typedef std::list<Element> ListElements; + +// Loading + //Deprecated : use SetFileName() + Load() +#ifndef GDCM_LEGACY_REMOVE + virtual bool Load( std::string const &filename ); +#endif + virtual bool Load( ); + +// Dictionaries + Dict *GetPubDict(); + Dict *GetShaDict(); + bool SetShaDict(Dict *dict); + bool SetShaDict(DictKey const &dictName); + +// Informations contained in the gdcm::Document + bool IsParsable(); + virtual bool IsReadable(); + bool IsDicomV3(); + bool IsPapyrus(); + FileType GetFileType(); + std::string GetTransferSyntax(); + /// Return the Transfer Syntax as a string + std::string GetTransferSyntaxName(); + +// Swap code + /// 'Swap code' accessor (see \ref SwapCode ) + int GetSwapCode() { return SwapCode; } + // System access (meaning endian related !?) + uint16_t SwapShort(uint16_t); + uint32_t SwapLong(uint32_t); + /// \brief Unswaps back the bytes of 2-bytes long integer + /// so they agree with the processor order. + uint16_t UnswapShort(uint16_t a) { return SwapShort(a);} + /// \brief Unswaps back the bytes of 4-byte long integer + /// so they agree with the processor order. + uint32_t UnswapLong(uint32_t a) { return SwapLong(a);} + +// File I/O + /// Accessor to \ref Filename + const std::string &GetFileName() const { return Filename; } + /// Accessor to \ref Filename + virtual void SetFileName(std::string const &fileName) + { if (Filename != fileName) + Filename = fileName, IsDocumentModified = true; } + + std::ifstream *OpenFile(); + bool CloseFile(); + void WriteContent( std::ofstream *fp, FileType type ); + +// Content entries + virtual void LoadEntryBinArea(uint16_t group, uint16_t elem); + virtual void LoadEntryBinArea(BinEntry *entry); + + void LoadDocEntrySafe(DocEntry *entry); + void SetMaxSizeLoadEntry(long); + void AddForceLoadElement(uint16_t group, uint16_t elem); + +// Ordering of Documents + bool operator<(Document &document); + +/** + * \brief Sets the LoadMode as a boolean string. + * LD_NOSEQ, LD_NOSHADOW, LD_NOSHADOWSEQ + ... (nothing more, right now) + * WARNING : before using NO_SHADOW, be sure *all* your files + * contain accurate values in the 0x0000 element (if any) + * of *each* Shadow Group. The parser will fail if the size is wrong ! + * @param mode Load mode to be used + */ + void SetLoadMode (int mode) { if (LoadMode != mode) + LoadMode=mode, IsDocumentModified = true; } + +protected: +// Methods + // Constructor and destructor are protected to forbid end user + // to instanciate from this class Document (only gdcm::File and + // gdcm::DicomDir are meaningfull). + Document(); + GDCM_LEGACY( Document( std::string const &filename ) ); + virtual ~Document(); + + uint16_t ReadInt16() throw ( FormatError ); + uint32_t ReadInt32() throw ( FormatError ); + void SkipBytes(uint32_t); + int ComputeGroup0002Length( ); + +// Variables + /// Refering underlying filename. + std::string Filename; + + /// \brief Swap code gives an information on the byte order of a + /// supposed to be an int32, as it's read on disc + /// (depending on the image Transfer Syntax *and* on the processor endianess) + /// as opposed as it should in memory to be dealt as an int32. + /// For instance : + /// - a 'Little Endian' image, read with a little endian processor + /// will have a SwapCode= 1234 (the order is OK; nothing to do) + /// - a 'Little Endian' image, read with a big endian procesor + /// will have a SwapCode= 4321 (the order is wrong; int32 an int16 must be + /// swapped) + /// note : values 2143, 4321, 3412 remain for the ACR-NEMA time, and + /// the well known 'Bad Big Endian' and 'Bad Little Endian' codes + int SwapCode; + + ///\brief whether we already parsed group 0002 (Meta Elements) + bool Group0002Parsed; + + ///\brief whether file has a DCM Preamble + bool HasDCMPreamble; + + /// File Pointer, opened during Document parsing. + std::ifstream *Fp; + + /// ACR, ACR_LIBIDO, ExplicitVR, ImplicitVR, Unknown + FileType Filetype; + + /// After opening the file, we read HEADER_LENGTH_TO_READ bytes. + static const unsigned int HEADER_LENGTH_TO_READ; + /// \brief Elements whose value is longer than MAX_SIZE_LOAD_ELEMENT_VALUE + /// are NOT loaded. + static const unsigned int MAX_SIZE_LOAD_ELEMENT_VALUE; + + /// User supplied list of elements to Anonymize + ListElements UserAnonymizeList; + + /// User supplied list of elements to force Load + ListElements UserForceLoadList; + + /// \brief Bit string integer (each one considered as a boolean) + /// Bit 0 : Skip Sequences, if possible + /// Bit 1 : Skip Shadow Groups if possible + /// Probabely, some more to add + int LoadMode; + + /// \brief Whether the gdcm::Document is already parsed/loaded : + /// False from the creation of the gdcm::Document untill + /// gdcm::Document:Load() + bool IsDocumentAlreadyLoaded; // FIXME : probabely useless now + + /// Whether the gdcm::Document was modified since the last Load() + bool IsDocumentModified; + +private: +// Methods + void Initialize(); + bool DoTheLoadingDocumentJob(); + // Read + void ParseDES(DocEntrySet *set, long offset, long l_max, bool delim_mode); + void ParseSQ (SeqEntry *seq, long offset, long l_max, bool delim_mode); + + void LoadDocEntry (DocEntry *e, bool forceLoad = false); + void FindDocEntryLength (DocEntry *e) throw ( FormatError ); + uint32_t FindDocEntryLengthOBOrOW() throw( FormatUnexpected ); + std::string FindDocEntryVR(); + bool CheckDocEntryVR (VRKey k); + + std::string GetDocEntryValue (DocEntry *entry); + std::string GetDocEntryUnvalue(DocEntry *entry); + + void SkipDocEntry (DocEntry *entry); + void SkipToNextDocEntry (DocEntry *entry); + + void FixDocEntryFoundLength(DocEntry *entry, uint32_t l); + bool IsDocEntryAnInteger (DocEntry *entry); + + bool CheckSwap(); + void SwitchByteSwapCode(); + + // DocEntry related utilities + DocEntry *ReadNextDocEntry(); + + void HandleBrokenEndian (uint16_t &group, uint16_t &elem); + void HandleOutOfGroup0002(uint16_t &group, uint16_t &elem); + DocEntry *Backtrack(DocEntry *docEntry); + +// Variables + /// Public dictionary used to parse this header + Dict *RefPubDict; + /// \brief Optional "shadow dictionary" (private elements) used to parse + /// this header + Dict *RefShaDict; + + /// \brief Size threshold above which an element value will NOT be loaded + /// in memory (to avoid loading the image/volume itself). By default, + /// this upper bound is fixed to 1024 bytes (which might look reasonable + /// when one considers the definition of the various VR contents). + uint32_t MaxSizeLoadEntry; + +// uint32_t GenerateFreeTagKeyInGroup(uint16_t group); +// void BuildFlatHashTableRecurse( TagDocEntryHT &builtHT, +// DocEntrySet *set ); + +}; + +} // end namespace gdcm + +//----------------------------------------------------------------------------- +#endif diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmElementSet.cxx b/Utilities/ITK/Utilities/gdcm/src/gdcmElementSet.cxx new file mode 100644 index 0000000000000000000000000000000000000000..998c578d602ff105c2c5e3de54193ea181217f42 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmElementSet.cxx @@ -0,0 +1,220 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmElementSet.cxx,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:39 $ + Version: $Revision: 1.5 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#include "gdcmElementSet.h" +#include "gdcmDebug.h" +#include "gdcmValEntry.h" +#include "gdcmBinEntry.h" +#include "gdcmSeqEntry.h" + +namespace gdcm +{ +//----------------------------------------------------------------------------- +// Constructor / Destructor +/** + * \brief Constructor for a given ElementSet + */ +ElementSet::ElementSet(int depthLevel) + : DocEntrySet() +{ + (void)depthLevel; +} + +/** + * \brief Canonical destructor. + */ +ElementSet::~ElementSet() +{ + ClearEntry(); +} + +//----------------------------------------------------------------------------- +// Public +/** + * \brief Writes the Header Entries (Dicom Elements) + * from the H Table + * @param fp ofstream to write to + * @param filetype filetype + */ +void ElementSet::WriteContent(std::ofstream *fp, FileType filetype) +{ + for (TagDocEntryHT::const_iterator i = TagHT.begin(); + i != TagHT.end(); + ++i) + { + i->second->WriteContent(fp, filetype); + } +} + +/** + * \brief add a new Dicom Element pointer to the H Table + * @param newEntry entry to add + */ +bool ElementSet::AddEntry(DocEntry *newEntry) +{ + const TagKey &key = newEntry->GetKey(); + + if ( TagHT.count(key) == 1 ) + { + gdcmWarningMacro( "Key already present: " << key ); + return false; + } + else + { + TagHT.insert(TagDocEntryHT::value_type(newEntry->GetKey(), newEntry)); + return true; + } +} + +/** + * \brief Clear the hash table from given entry AND delete the entry. + * @param entryToRemove Entry to remove AND delete. + */ +bool ElementSet::RemoveEntry( DocEntry *entryToRemove) +{ + const TagKey &key = entryToRemove->GetKey(); + if ( TagHT.count(key) == 1 ) + { + TagHT.erase(key); + delete entryToRemove; + return true; + } + + gdcmWarningMacro( "Key not present : " << key); + return false ; +} + +/** + * \brief Clear the hash table from given entry BUT keep the entry. + * @param entryToRemove Entry to remove. + */ +bool ElementSet::RemoveEntryNoDestroy(DocEntry *entryToRemove) +{ + const TagKey &key = entryToRemove->GetKey(); + if ( TagHT.count(key) == 1 ) + { + TagHT.erase(key); + //gdcmWarningMacro( "One element erased."); + return true; + } + + gdcmWarningMacro( "Key not present " << key); + return false ; +} + +/** + * \brief delete all entries in the ElementSet + */ +void ElementSet::ClearEntry() +{ + for(TagDocEntryHT::iterator cc = TagHT.begin();cc != TagHT.end(); ++cc) + { + if ( cc->second ) + { + delete cc->second; + } + } + TagHT.clear(); +} + +/** + * \brief Get the first entry while visiting *the* 'zero level' DocEntrySet + * (DocEntries out of any Sequence) + * \return The first DocEntry if found, otherwhise NULL + */ +DocEntry *ElementSet::GetFirstEntry() +{ + ItTagHT = TagHT.begin(); + if (ItTagHT != TagHT.end()) + return ItTagHT->second; + return NULL; +} + +/** + * \brief Get the next entry while visiting *the* 'zero level' DocEntrySet + * (DocEntries out of any Sequence) + * \note : meaningfull only if GetFirstEntry already called + * \return The next DocEntry if found, otherwhise NULL + */ +DocEntry *ElementSet::GetNextEntry() +{ + gdcmAssertMacro (ItTagHT != TagHT.end()); + + ++ItTagHT; + if (ItTagHT != TagHT.end()) + return ItTagHT->second; + return NULL; +} + +/** + * \brief retrieves a Dicom Element using (group, element) + * @param group Group number of the searched Dicom Element + * @param elem Element number of the searched Dicom Element + * @return + */ +DocEntry *ElementSet::GetDocEntry(uint16_t group, uint16_t elem) +{ + TagKey key = DictEntry::TranslateToKey(group, elem); + TagDocEntryHT::iterator it = TagHT.find(key); + + if ( it!=TagHT.end() ) + return it->second; + return NULL; +} + +//----------------------------------------------------------------------------- +// Protected + +//----------------------------------------------------------------------------- +// Private + +//----------------------------------------------------------------------------- +// Print +/** + * \brief Prints the Header Entries (Dicom Elements) from the H Table + * @param os ostream to write to + * @param indent Indentation string to be prepended during printing + */ +void ElementSet::Print(std::ostream &os, std::string const & ) +{ + // Let's change the 'warning value' for Pixel Data, + // to avoid human reader to be confused by 'gdcm::NotLoaded'. + gdcm::BinEntry *pixelElement = GetBinEntry(0x7fe0,0x0010); + if ( pixelElement != 0 ) + { + pixelElement->SetValue( gdcm::GDCM_PIXELDATA); + } + + for( TagDocEntryHT::const_iterator i = TagHT.begin(); i != TagHT.end(); ++i) + { + DocEntry *entry = i->second; + + entry->SetPrintLevel(PrintLevel); + entry->Print(os); + + if ( dynamic_cast<SeqEntry*>(entry) ) + { + // Avoid the newline for a sequence: + continue; + } + os << std::endl; + } +} + +//----------------------------------------------------------------------------- +} // end namespace gdcm diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmElementSet.h b/Utilities/ITK/Utilities/gdcm/src/gdcmElementSet.h new file mode 100644 index 0000000000000000000000000000000000000000..6451fbc408de934f36695a9b2f4b79702ba37662 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmElementSet.h @@ -0,0 +1,80 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmElementSet.h,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:39 $ + Version: $Revision: 1.6 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#ifndef GDCMELEMENTSET_H +#define GDCMELEMENTSET_H + +#include "gdcmDocEntrySet.h" + +#include <map> +#include <iostream> +#include <fstream> + +namespace gdcm +{ +class ValEntry; +class BinEntry; +class SeqEntry; + +typedef std::map<TagKey, DocEntry *> TagDocEntryHT; + +//----------------------------------------------------------------------------- +/** + * \brief + * \ref ElementSet is based on the STL map<> container + * (see \ref ElementSet::TagHT), as opposed to \ref SQItem + * which is based on an STL list container (see \ref ListDocEntry). + * It contains the 'zero-level- DocEntry (out of any Dicom Sequence) + */ +class GDCM_EXPORT ElementSet : public DocEntrySet +{ +public: + ElementSet(int); + ~ElementSet(); + + virtual void Print(std::ostream &os = std::cout, + std::string const &indent = "" ); + + void WriteContent(std::ofstream *fp, FileType filetype); + + bool AddEntry(DocEntry *Entry); + bool RemoveEntry(DocEntry *EntryToRemove); + bool RemoveEntryNoDestroy(DocEntry *EntryToRemove); + void ClearEntry(); + + DocEntry *GetFirstEntry(); + DocEntry *GetNextEntry(); + DocEntry *GetDocEntry(uint16_t group, uint16_t elem); + /// Tells us if the ElementSet contains no entry + bool IsEmpty() { return TagHT.empty(); } + +protected: + +private: +// Variables + /// Hash Table (map), to provide fast access + TagDocEntryHT TagHT; + /// iterator, used to visit the TagHT variable + TagDocEntryHT::iterator ItTagHT; + /// iterator, used to visit the TagHT variable, seeking only for ValEntries + TagDocEntryHT::iterator ItValEntryTagHT; +}; +} // end namespace gdcm +//----------------------------------------------------------------------------- +#endif + diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmException.cxx b/Utilities/ITK/Utilities/gdcm/src/gdcmException.cxx new file mode 100644 index 0000000000000000000000000000000000000000..fc3d8f76022414d6842807b7b97f86bc12d9881b --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmException.cxx @@ -0,0 +1,143 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmException.cxx,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:39 $ + Version: $Revision: 1.4 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#include "gdcmException.h" + +#include <typeinfo> +#include <stdlib.h> // for exit + +namespace gdcm +{ +//----------------------------------------------------------------------------- +// Exception +/** + * \brief constructor + * @param f f + * @param msg msg + */ +Exception::Exception(const std::string &f, const std::string &msg) throw() +#ifdef __GNUC__ + try +#endif + : From(f), Error(msg) + { + } +#ifdef __GNUC__ + catch(...) + { + fatal("Exception::Exception(const std::string&, const std::string&, const std::string&)"); + } +#endif + +/** + * \brief fatal + * @param from from + */ +void Exception::fatal(const char *from) throw() +{ + try + { + std::cerr << "Fatal: exception received in " << from + << " while handling exception." << std::endl; + exit(-1); + } + catch(...) + { + try + { + std::cerr << "Fatal: exception received in Exception::fatal while handling exception." + << std::endl; + exit(-1); + } + catch(...) + { + exit(-1); + } + } +} + +/** + * \brief getName + * @return string + */ +std::string Exception::getName() const throw() +{ + try + { +#if defined(__GNUC__) && 0 // GNU C++ compiler class name demangling + unsigned int nested = 1, i, nb; + int offset; + std::string one; + + std::string name; + std::string iname = typeid(*this).name(); + if ( iname[0] == 'Q' ) + { + nested = iname[1] - '0'; + iname = std::string(iname, 2, std::string::npos); + } + for(i = 0; i < nested; i++) + { + ::sscanf(iname.c_str(), "%u%n", &nb, &offset); + iname = std::string(iname, offset, std::string::npos); + name += std::string(iname, 0, nb); + if ( i + 1 < nested) name += "::"; + iname = std::string(iname, nb, std::string::npos ); + } + return name; +#else // no class name demangling + std::string name = typeid(*this).name(); + return name; +#endif + } + catch(...) + { + fatal("Exception::getName(std::string &)"); + return ""; + } +} + +/** + * \brief Exception + */ +Exception::operator const char *() const throw() +{ + return getName().c_str(); +} + +//----------------------------------------------------------------------------- +/** + * \brief Exception::operator << + * @param os ostream to write to + * @param e exception to raise + */ +std::ostream& operator<<(std::ostream &os, const Exception &e) +{ + try + { + os << "Exception " << e.getName() << " thrown: " << e.getError() << std::endl; + } + catch(...) + { + Exception::fatal("operator<<(std::ostream &, const Exception&)"); + } + return os; +} + +} // end namespace gdcm +//----------------------------------------------------------------------------- diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmException.h b/Utilities/ITK/Utilities/gdcm/src/gdcmException.h new file mode 100644 index 0000000000000000000000000000000000000000..632ee3048c086342ea9aad2268a80bf721bd8af5 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmException.h @@ -0,0 +1,139 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmException.h,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:39 $ + Version: $Revision: 1.4 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#ifndef GDCM_EXCEPTION_H +#define GDCM_EXCEPTION_H + +#include "gdcmCommon.h" + +#include <string> +#include <iostream> +#include <exception> + +namespace gdcm +{ + +//----------------------------------------------------------------------------- +/** + * \brief Any exception thrown in the gdcm library + */ +class GDCM_EXPORT Exception : public std::exception +{ +public: + /* + * \brief Builds an exception with minimal information: name of the thrower + * method and error message + * @param from name of the thrower + * @param error error description string + */ + explicit Exception(const std::string &from, const std::string &error = "") + throw(); + + /** + * \brief virtual destructor makes this class dynamic + */ + virtual ~Exception() throw() {} + + /// exception caught within exception class: print error message and die + static void fatal(const char *from) throw(); + + /// returns error message + const std::string &getError() const throw() { return Error;} + + /// try to discover this (dynamic) class name + virtual std::string getName() const throw(); + + /// returns exception name string (overloads std::exception::what) + virtual const char *what() const throw() { return (const char *) *this;} + + /// returns exception name string + operator const char *() const throw(); + + friend std::ostream &operator<<(std::ostream &os, const Exception &e); + +protected: + /// error message part 1 + std::string From; + /// error message part 2 + std::string Error; +}; + + +//----------------------------------------------------------------------------- +/** + * \brief File error exception thrown in the gdcm library + */ +class GDCM_EXPORT FileError : public Exception +{ +public: + /** + * \brief Builds an file-related exception with minimal information: name of + * the thrower method and error message + * @param from name of the thrower + * @param error error description string + */ + explicit FileError(const std::string &from, + const std::string &error = "File error") + throw() : Exception(from, error) { } +}; + + +//----------------------------------------------------------------------------- +/** + * \brief Unexpected file format exception + */ +class GDCM_EXPORT FormatUnexpected : public Exception +{ +public: + /// \brief Builds a file-related exception with minimal information: + /// name of the thrower method and error message + /// @param from name of the thrower + /// @param error error description string + explicit FormatUnexpected(const std::string &from, + const std::string &error = "Unexpected file format") + throw() : Exception( from, error ) { } +}; + +//----------------------------------------------------------------------------- +/** + * \brief Invalid file format exception + */ +class GDCM_EXPORT FormatError : public FormatUnexpected +{ +public: + /// \brief Builds a file-related exception with minimal information: + /// name of the thrower method and error message + /// @param from name of the thrower + /// @param error error description string + explicit FormatError(const std::string &from, + const std::string &error = "Invalid file format") + throw() : FormatUnexpected( from, error ) { } +}; + +//----------------------------------------------------------------------------- +/* prints exception stack on output stream + * @param os output stream + * @param e exception to print + * @returns output stream os + */ +std::ostream& operator<<(std::ostream &os, const Exception &e); + +} // end namespace gdcm + +//----------------------------------------------------------------------------- +#endif // GDCM_EXCEPTION_H diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmFile.cxx b/Utilities/ITK/Utilities/gdcm/src/gdcmFile.cxx new file mode 100644 index 0000000000000000000000000000000000000000..c4c2eee0dcc5457c07991a03f85fccb7e2a898f1 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmFile.cxx @@ -0,0 +1,1898 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmFile.cxx,v $ + Language: C++ + Date: $Date: 2006/02/20 15:56:57 $ + Version: $Revision: 1.14 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +// +// -------------- Remember ! ---------------------------------- +// +// Image Position (Patient) (0020,0032): +// If not found (ACR_NEMA) we try Image Position (0020,0030) +// If not found (ACR-NEMA), we consider Slice Location (0020,1041) +// or Location (0020,0050) +// as the Z coordinate, +// 0. for all the coordinates if nothing is found +// +// Image Position (Patient) (0020,0032) VM=3 +// --> +// The attribute Patient Orientation (0020,0020) from the General Image Module +// is of type 2C and has the condition Required if image does not require +// Image Orientation (0020,0037) and Image Position (0020,0032). +// However, if the image does require the attributes +// - Image Orientation (Patient) (0020,0037), VM=6 +// - Image Position (Patient) (0020,0032), VM=3 +// then attribute Patient Orientation (0020,0020) should not be present +// in the images. +// +// Remember also : +// Patient Position (0018,5100) values : + +// HFS = Head First-Supine, where increasing (positive axis direction) : +// X -> to the direction pointed to by the patient's oustretched left arm +// Y -> to the anterior-to-posterior direction in the patient's body +// Z -> to the feet-to-head direction in the patient's body + +// HFP = Head First-Prone, where increasing (positive axis direction) : +// X -> to the direction pointed to by the patient's oustretched left arm +// Y -> to the anterior-to-posterior direction in the patient's body +// Z -> to the feet-to-head direction in the patient's body + +// FFS = Feet First-Supine, where increasing (positive axis direction) : +// X -> to the direction pointed to by the patient's oustretched left arm +// Y -> to the anterior-to-posterion direction in the patient's body +// Z -> to the feet-to-head direction in the patient's body + +// FFP = Feet First-Prone, where increasing (positive axis direction) : +// X -> to the direction pointed to by the patient's oustretched left arm +// Y -> to the posterior-to-anterior direction in the patient's body +// Z -> to the feet-to-head direction in the patient's body + +// HFDR = Head First-Decubitus Right +// HFDL = Head First-Decubitus Left +// FFDR = Feet First-Decubitus Right +// FFDL = Feet First-Decubitus Left + +// we can also find (non standard!) + +// SEMIERECT +// SUPINE + +// CS 2 Patient Orientation (0020 0020) +// When the coordinates of the image +// are always present, this field is almost never used. +// Better we don't trust it too much ... +// Found Values are : +// L\P +// L\FP +// P\F +// L\F +// P\FR +// R\F +// +// (0020|0037) [Image Orientation (Patient)] [1\0\0\0\1\0 ] + + +// --------------------------------------------------------------- +// +#include "gdcmFile.h" +#include "gdcmGlobal.h" +#include "gdcmUtil.h" +#include "gdcmDebug.h" +#include "gdcmTS.h" +#include "gdcmValEntry.h" +#include "gdcmBinEntry.h" +#include "gdcmSeqEntry.h" +#include "gdcmRLEFramesInfo.h" +#include "gdcmJPEGFragmentsInfo.h" + +#include <vector> +#include <stdio.h> //sscanf +#include <stdlib.h> // for atoi + +namespace gdcm +{ + +//----------------------------------------------------------------------------- +// Constructor / Destructor + +/** + * \brief Constructor used when we want to generate dicom files from scratch + */ +File::File(): + Document() +{ + RLEInfo = new RLEFramesInfo; + JPEGInfo = new JPEGFragmentsInfo; + GrPixel = 0x7fe0; // to avoid further troubles + NumPixel = 0x0010; + BasicOffsetTableItemValue = 0; +} + + +/** + * \brief Canonical destructor. + */ +File::~File() +{ + if ( RLEInfo ) + delete RLEInfo; + if ( JPEGInfo ) + delete JPEGInfo; + delete[] BasicOffsetTableItemValue; +} + +//----------------------------------------------------------------------------- +// Public +/** + * \brief Loader + * @return false if file cannot be open or no swap info was found, + * or no tag was found. + */ +bool File::Load( ) +{ + if ( ! this->Document::Load( ) ) + return false; + + return DoTheLoadingJob( ); +} + +/** + * \brief Does the Loading Job (internal use only) + * @return false if file cannot be open or no swap info was found, + * or no tag was found. + */ +bool File::DoTheLoadingJob( ) +{ + // for some ACR-NEMA images GrPixel, NumPixel is *not* 7fe0,0010 + // We may encounter the 'RETired' (0x0028, 0x0200) tag + // (Image Location") . This entry contains the number of + // the group that contains the pixel data (hence the "Pixel Data" + // is found by indirection through the "Image Location"). + // Inside the group pointed by "Image Location" the searched element + // is conventionally the element 0x0010 (when the norm is respected). + // When the "Image Location" is missing we default to group 0x7fe0. + // Note: this IS the right place for the code + + // Image Location + const std::string &imgLocation = GetEntryValue(0x0028, 0x0200); + if ( imgLocation == GDCM_UNFOUND ) + { + // default value + GrPixel = 0x7fe0; + } + else + { + GrPixel = (uint16_t) atoi( imgLocation.c_str() ); + } + + // sometimes Image Location value doesn't follow + // the supposed processor endianness. + // see gdcmData/cr172241.dcm + if ( GrPixel == 0xe07f ) + { + GrPixel = 0x7fe0; + } + + if ( GrPixel != 0x7fe0 ) + { + // This is a kludge for old dirty Philips imager. + NumPixel = 0x1010; + } + else + { + NumPixel = 0x0010; + } + + // Now, we know GrPixel and NumPixel. + // Let's create a VirtualDictEntry to allow a further VR modification + // and force VR to match with BitsAllocated. + DocEntry *entry = GetDocEntry(GrPixel, NumPixel); + if ( entry != 0 ) + { + // Compute the RLE or JPEG info + OpenFile(); + const std::string &ts = GetTransferSyntax(); + Fp->seekg( entry->GetOffset(), std::ios::beg ); + if ( Global::GetTS()->IsRLELossless(ts) ) + ComputeRLEInfo(); + else if ( Global::GetTS()->IsJPEG(ts) ) + ComputeJPEGFragmentInfo(); + CloseFile(); + + // Create a new BinEntry to change the DictEntry + // The changed DictEntry will have + // - a correct PixelVR OB or OW) + // - the name to "Pixel Data" + BinEntry *oldEntry = dynamic_cast<BinEntry *>(entry); + if (oldEntry) + { + std::string PixelVR; + // 8 bits allocated is a 'O Bytes' , as well as 24 (old ACR-NEMA RGB) + // more than 8 (i.e 12, 16) is a 'O Words' + if ( GetBitsAllocated() == 8 || GetBitsAllocated() == 24 ) + PixelVR = "OB"; + else + PixelVR = "OW"; + + // Change only made if usefull + if ( PixelVR != oldEntry->GetVR() ) + { + DictEntry* newDict = NewVirtualDictEntry(GrPixel,NumPixel, + PixelVR,"1","Pixel Data"); + + BinEntry *newEntry = new BinEntry(newDict); + newEntry->Copy(entry); + newEntry->SetBinArea(oldEntry->GetBinArea(),oldEntry->IsSelfArea()); + oldEntry->SetSelfArea(false); + + RemoveEntry(oldEntry); + AddEntry(newEntry); + } + } + } + return true; +} +/** + * \brief This predicate, based on hopefully reasonable heuristics, + * decides whether or not the current File was properly parsed + * and contains the mandatory information for being considered as + * a well formed and usable Dicom/Acr File. + * @return true when File is the one of a reasonable Dicom/Acr file, + * false otherwise. + */ +bool File::IsReadable() +{ + if ( !Document::IsReadable() ) + { + return false; + } + + const std::string &res = GetEntryValue(0x0028, 0x0005); + if ( res != GDCM_UNFOUND && atoi(res.c_str()) > 4 ) + { + gdcmWarningMacro("Wrong Image Dimensions" << res); + return false; // Image Dimensions + } + bool b0028_0100 = true; + if ( !GetDocEntry(0x0028, 0x0100) ) + { + gdcmWarningMacro("Bits Allocated (0028|0100) not found"); + //return false; // "Bits Allocated" + b0028_0100 = false; + } + bool b0028_0101 = true; + if ( !GetDocEntry(0x0028, 0x0101) ) + { + gdcmWarningMacro("Bits Stored (0028|0101) not found"); + //return false; // "Bits Stored" + b0028_0101 = false; + } + bool b0028_0102 = true; + if ( !GetDocEntry(0x0028, 0x0102) ) + { + gdcmWarningMacro("Hight Bit (0028|0102) not found"); + //return false; // "High Bit" + b0028_0102 = false; + } + bool b0028_0103 = true; + if ( !GetDocEntry(0x0028, 0x0103) ) + { + gdcmWarningMacro("Pixel Representation (0028|0103) not found"); + //return false; // "Pixel Representation" i.e. 'Sign' ( 0 : unsigned, 1 : signed) + b0028_0103 = false; + } + + if ( !b0028_0100 && !b0028_0101 && !b0028_0102 && !b0028_0103) + { + gdcmWarningMacro("Too much mandatory Tags missing !"); + return false; + } + + if ( !GetDocEntry(GrPixel, NumPixel) ) + { + gdcmWarningMacro("Pixel Dicom Element " << std::hex << + GrPixel << "|" << NumPixel << "not found"); + return false; // Pixel Dicom Element not found :-( + } + return true; +} + +/** + * \brief gets the info from 0020,0013 : Image Number else 0. + * @return image number + */ +int File::GetImageNumber() +{ + //0020 0013 : Image Number + std::string strImNumber = GetEntryValue(0x0020,0x0013); + if ( strImNumber != GDCM_UNFOUND ) + { + return atoi( strImNumber.c_str() ); + } + return 0; //Hopeless +} + +/** + * \brief gets the info from 0008,0060 : Modality + * @return Modality Type + */ +ModalityType File::GetModality() +{ + // 0008 0060 : Modality + std::string strModality = GetEntryValue(0x0008,0x0060); + if ( strModality != GDCM_UNFOUND ) + { + if ( strModality.find("AU") < strModality.length()) return AU; + else if ( strModality.find("AS") < strModality.length()) return AS; + else if ( strModality.find("BI") < strModality.length()) return BI; + else if ( strModality.find("CF") < strModality.length()) return CF; + else if ( strModality.find("CP") < strModality.length()) return CP; + else if ( strModality.find("CR") < strModality.length()) return CR; + else if ( strModality.find("CT") < strModality.length()) return CT; + else if ( strModality.find("CS") < strModality.length()) return CS; + else if ( strModality.find("DD") < strModality.length()) return DD; + else if ( strModality.find("DF") < strModality.length()) return DF; + else if ( strModality.find("DG") < strModality.length()) return DG; + else if ( strModality.find("DM") < strModality.length()) return DM; + else if ( strModality.find("DS") < strModality.length()) return DS; + else if ( strModality.find("DX") < strModality.length()) return DX; + else if ( strModality.find("ECG") < strModality.length()) return ECG; + else if ( strModality.find("EPS") < strModality.length()) return EPS; + else if ( strModality.find("FA") < strModality.length()) return FA; + else if ( strModality.find("FS") < strModality.length()) return FS; + else if ( strModality.find("HC") < strModality.length()) return HC; + else if ( strModality.find("HD") < strModality.length()) return HD; + else if ( strModality.find("LP") < strModality.length()) return LP; + else if ( strModality.find("LS") < strModality.length()) return LS; + else if ( strModality.find("MA") < strModality.length()) return MA; + else if ( strModality.find("MR") < strModality.length()) return MR; + else if ( strModality.find("NM") < strModality.length()) return NM; + else if ( strModality.find("OT") < strModality.length()) return OT; + else if ( strModality.find("PT") < strModality.length()) return PT; + else if ( strModality.find("RF") < strModality.length()) return RF; + else if ( strModality.find("RG") < strModality.length()) return RG; + else if ( strModality.find("RTDOSE") + < strModality.length()) return RTDOSE; + else if ( strModality.find("RTIMAGE") + < strModality.length()) return RTIMAGE; + else if ( strModality.find("RTPLAN") + < strModality.length()) return RTPLAN; + else if ( strModality.find("RTSTRUCT") + < strModality.length()) return RTSTRUCT; + else if ( strModality.find("SM") < strModality.length()) return SM; + else if ( strModality.find("ST") < strModality.length()) return ST; + else if ( strModality.find("TG") < strModality.length()) return TG; + else if ( strModality.find("US") < strModality.length()) return US; + else if ( strModality.find("VF") < strModality.length()) return VF; + else if ( strModality.find("XA") < strModality.length()) return XA; + else if ( strModality.find("XC") < strModality.length()) return XC; + + else + { + /// \todo throw error return value ??? + /// specified <> unknown in our database + return Unknow; + } + } + return Unknow; +} + +/** + * \brief Retrieve the number of columns of image. + * @return The encountered size when found, 0 by default. + * 0 means the file is NOT USABLE. The caller will have to check + */ +int File::GetXSize() +{ + const std::string &strSize = GetEntryValue(0x0028,0x0011); + if ( strSize == GDCM_UNFOUND ) + { + return 0; + } + return atoi( strSize.c_str() ); +} + +/** + * \brief Retrieve the number of lines of image. + * \warning The defaulted value is 1 as opposed to File::GetXSize() + * @return The encountered size when found, 1 by default + * (The ACR-NEMA file contains a Signal, not an Image). + */ +int File::GetYSize() +{ + const std::string &strSize = GetEntryValue(0x0028,0x0010); + if ( strSize != GDCM_UNFOUND ) + { + return atoi( strSize.c_str() ); + } + if ( IsDicomV3() ) + { + return 0; + } + + // The Rows (0028,0010) entry was optional for ACR/NEMA. + // (at least some images didn't have it.) + // It might hence be a signal (1D image). So we default to 1: + return 1; +} + +/** + * \brief Retrieve the number of planes of volume or the number + * of frames of a multiframe. + * \warning When present we consider the "Number of Frames" as the third + * dimension. When missing we consider the third dimension as + * being the ACR-NEMA "Planes" tag content. + * @return The encountered size when found, 1 by default (single image). + */ +int File::GetZSize() +{ + // Both DicomV3 and ACR/Nema consider the "Number of Frames" + // as the third dimension. + const std::string &strSize = GetEntryValue(0x0028,0x0008); + if ( strSize != GDCM_UNFOUND ) + { + return atoi( strSize.c_str() ); + } + + // We then consider the "Planes" entry as the third dimension + const std::string &strSize2 = GetEntryValue(0x0028,0x0012); + if ( strSize2 != GDCM_UNFOUND ) + { + return atoi( strSize2.c_str() ); + } + return 1; +} + +/** + * \brief gets the info from 0018,1164 : ImagerPixelSpacing + * then 0028,0030 : Pixel Spacing + * else 1.0 + * @return X dimension of a pixel + */ +float File::GetXSpacing() +{ + float xspacing = 1.0; + float yspacing = 1.0; + int nbValues; + + // To follow David Clunie's advice, we first check ImagerPixelSpacing + + const std::string &strImagerPixelSpacing = GetEntryValue(0x0018,0x1164); + if ( strImagerPixelSpacing != GDCM_UNFOUND ) + { + if ( ( nbValues = sscanf( strImagerPixelSpacing.c_str(), + "%f\\%f", &yspacing, &xspacing)) != 2 ) + { + // if no values, xspacing is set to 1.0 + if ( nbValues == 0 ) + xspacing = 1.0; + // if single value is found, xspacing is defaulted to yspacing + if ( nbValues == 1 ) + xspacing = yspacing; + + if ( xspacing == 0.0 ) + xspacing = 1.0; + } + return xspacing; + } + + const std::string &strSpacing = GetEntryValue(0x0028,0x0030); + + if ( strSpacing == GDCM_UNFOUND ) + { + gdcmWarningMacro( "Unfound Pixel Spacing (0028,0030)" ); + return 1.; + } + + if ( ( nbValues = sscanf( strSpacing.c_str(), + "%f \\%f ", &yspacing, &xspacing)) != 2 ) + { + // if no values, xspacing is set to 1.0 + if ( nbValues == 0 ) + xspacing = 1.0; + // if single value is found, xspacing is defaulted to yspacing + if ( nbValues == 1 ) + xspacing = yspacing; + + if ( xspacing == 0.0 ) + xspacing = 1.0; + } + return xspacing; + + // to avoid troubles with David Clunie's-like images (at least one) + if ( xspacing == 0.0 && yspacing == 0.0) + return 1.0; + + if ( xspacing == 0.0) + { + gdcmWarningMacro("gdcmData/CT-MONO2-8-abdo.dcm-like problem"); + // seems to be a bug in the header ... + nbValues = sscanf( strSpacing.c_str(), "%f \\0\\%f ", &yspacing, &xspacing); + gdcmAssertMacro( nbValues == 2 ); + } + + return xspacing; +} + +/** + * \brief gets the info from 0018,1164 : ImagerPixelSpacing + * then from 0028,0030 : Pixel Spacing + * else 1.0 + * @return Y dimension of a pixel + */ +float File::GetYSpacing() +{ + float yspacing = 1.0; + int nbValues; + // To follow David Clunie's advice, we first check ImagerPixelSpacing + + const std::string &strImagerPixelSpacing = GetEntryValue(0x0018,0x1164); + if ( strImagerPixelSpacing != GDCM_UNFOUND ) + { + nbValues = sscanf( strImagerPixelSpacing.c_str(), "%f", &yspacing); + + // if sscanf cannot read any float value, it won't affect yspacing + if ( nbValues == 0 ) + yspacing = 1.0; + + if ( yspacing == 0.0 ) + yspacing = 1.0; + + return yspacing; + } + + std::string strSpacing = GetEntryValue(0x0028,0x0030); + if ( strSpacing == GDCM_UNFOUND ) + { + gdcmWarningMacro("Unfound Pixel Spacing (0028,0030)"); + return 1.; + } + + // if sscanf cannot read any float value, it won't affect yspacing + nbValues = sscanf( strSpacing.c_str(), "%f", &yspacing); + + // if no values, yspacing is set to 1.0 + if ( nbValues == 0 ) + yspacing = 1.0; + + if ( yspacing == 0.0 ) + yspacing = 1.0; + + return yspacing; +} + +/** + * \brief gets the info from 0018,0088 : Space Between Slices + * else from 0018,0050 : Slice Thickness + * else 1.0 + * + * When an element is missing, we suppose slices join together + * (no overlapping, no interslice gap) but we have no way to check it ! + * For *Dicom* images, ZSpacing *should be* calculated using + * XOrigin, YOrigin, ZOrigin (of the top left image corner) + * of 2 consecutive images, and the Orientation + * Computing ZSpacing on a single image is not really meaningfull ! + * @return Z dimension of a voxel-to be + */ +float File::GetZSpacing() +{ + // Spacing Between Slices : distance between the middle of 2 slices + // Slices may be : + // jointives (Spacing between Slices = Slice Thickness) + // overlapping (Spacing between Slices < Slice Thickness) + // disjointes (Spacing between Slices > Slice Thickness) + // Slice Thickness : epaisseur de tissus sur laquelle est acquis le signal + // It only concerns the MRI guys, not people wanting to visualize volumes + // If Spacing Between Slices is missing, + // we suppose slices joint together + + // ---> + // ---> Warning : + // ---> + + // + // For *Dicom* images, ZSpacing should be calculated using + // XOrigin, YOrigin, ZOrigin (of the top left image corner) + // of 2 consecutive images, and the Orientation + // + // Computing ZSpacing on a single image is not really meaningfull ! + + const std::string &strSpacingBSlices = GetEntryValue(0x0018,0x0088); + + if ( strSpacingBSlices == GDCM_UNFOUND ) + { + gdcmWarningMacro("Unfound Spacing Between Slices (0018,0088)"); + const std::string &strSliceThickness = GetEntryValue(0x0018,0x0050); + if ( strSliceThickness == GDCM_UNFOUND ) + { + gdcmWarningMacro("Unfound Slice Thickness (0018,0050)"); + return 1.0; + } + else + { + // if no 'Spacing Between Slices' is found, + // we assume slices join together + // (no overlapping, no interslice gap) + // if they don't, we're fucked up + return (float)atof( strSliceThickness.c_str() ); + } + } + //else + + float zsp = (float)atof( strSpacingBSlices.c_str()); + if (zsp == 0.0) // last change not to break further computations ... + zsp = 1.0; + return zsp; +} + +/** + * \brief gets the info from 0020,0032 : Image Position Patient + * else from 0020,0030 : Image Position (RET) + * else 0. + * @return up-left image corner X position + */ +float File::GetXOrigin() +{ + float xImPos, yImPos, zImPos; + std::string strImPos = GetEntryValue(0x0020,0x0032); + + if ( strImPos == GDCM_UNFOUND ) + { + gdcmWarningMacro( "Unfound Image Position Patient (0020,0032)"); + strImPos = GetEntryValue(0x0020,0x0030); // For ACR-NEMA images + if ( strImPos == GDCM_UNFOUND ) + { + gdcmWarningMacro( "Unfound Image Position (RET) (0020,0030)"); + return 0.0; + } + } + + if ( sscanf( strImPos.c_str(), "%f \\%f \\%f ", &xImPos, &yImPos, &zImPos) != 3 ) + { + return 0.0; + } + + return xImPos; +} + +/** + * \brief gets the info from 0020,0032 : Image Position Patient + * else from 0020,0030 : Image Position (RET) + * else 0. + * @return up-left image corner Y position + */ +float File::GetYOrigin() +{ + float xImPos, yImPos, zImPos; + std::string strImPos = GetEntryValue(0x0020,0x0032); + + if ( strImPos == GDCM_UNFOUND) + { + gdcmWarningMacro( "Unfound Image Position Patient (0020,0032)"); + strImPos = GetEntryValue(0x0020,0x0030); // For ACR-NEMA images + if ( strImPos == GDCM_UNFOUND ) + { + gdcmWarningMacro( "Unfound Image Position (RET) (0020,0030)"); + return 0.; + } + } + + if ( sscanf( strImPos.c_str(), "%f \\%f \\%f ", &xImPos, &yImPos, &zImPos) != 3 ) + { + return 0.; + } + + return yImPos; +} + +/** + * \brief gets the info from 0020,0032 : Image Position Patient + * else from 0020,0030 : Image Position (RET) + * else from 0020,1041 : Slice Location + * else from 0020,0050 : Location + * else 0. + * @return up-left image corner Z position + */ +float File::GetZOrigin() +{ + float xImPos, yImPos, zImPos; + std::string strImPos = GetEntryValue(0x0020,0x0032); + + if ( strImPos != GDCM_UNFOUND ) + { + if ( sscanf( strImPos.c_str(), "%f \\%f \\%f ", &xImPos, &yImPos, &zImPos) != 3) + { + gdcmWarningMacro( "Wrong Image Position Patient (0020,0032)"); + return 0.; // bug in the element 0x0020,0x0032 + } + else + { + return zImPos; + } + } + + strImPos = GetEntryValue(0x0020,0x0030); // For ACR-NEMA images + if ( strImPos != GDCM_UNFOUND ) + { + if ( sscanf( strImPos.c_str(), + "%f \\%f \\%f ", &xImPos, &yImPos, &zImPos ) != 3 ) + { + gdcmWarningMacro( "Wrong Image Position (RET) (0020,0030)"); + return 0.; // bug in the element 0x0020,0x0032 + } + else + { + return zImPos; + } + } + + // for *very* old ACR-NEMA images + std::string strSliceLocation = GetEntryValue(0x0020,0x1041); + if ( strSliceLocation != GDCM_UNFOUND ) + { + if ( sscanf( strSliceLocation.c_str(), "%f ", &zImPos) != 1) + { + gdcmWarningMacro( "Wrong Slice Location (0020,1041)"); + return 0.; // bug in the element 0x0020,0x1041 + } + else + { + return zImPos; + } + } + gdcmWarningMacro( "Unfound Slice Location (0020,1041)"); + + std::string strLocation = GetEntryValue(0x0020,0x0050); + if ( strLocation != GDCM_UNFOUND ) + { + if ( sscanf( strLocation.c_str(), "%f ", &zImPos) != 1 ) + { + gdcmWarningMacro( "Wrong Location (0020,0050)"); + return 0.; // bug in the element 0x0020,0x0050 + } + else + { + return zImPos; + } + } + gdcmWarningMacro( "Unfound Location (0020,0050)"); + + return 0.; // Hopeless +} + +/** + * \brief gets the info from 0020,0037 : Image Orientation Patient + * or from 0020 0035 : Image Orientation (RET) + * (needed to organize DICOM files based on their x,y,z position) + * @param iop adress of the (6)float array to receive values + * @return true when one of the tag is found + * false when nothing is found + */ +bool File::GetImageOrientationPatient( float iop[6] ) +{ + std::string strImOriPat; + //iop is supposed to be float[6] + iop[0] = iop[4] = 1.; + iop[1] = iop[2] = iop[3] = iop[5] = 0.; + + // 0020 0037 DS REL Image Orientation (Patient) + if ( (strImOriPat = GetEntryValue(0x0020,0x0037)) != GDCM_UNFOUND ) + { + if ( sscanf( strImOriPat.c_str(), "%f \\ %f \\%f \\%f \\%f \\%f ", + &iop[0], &iop[1], &iop[2], &iop[3], &iop[4], &iop[5]) != 6 ) + { + gdcmWarningMacro( "Wrong Image Orientation Patient (0020,0037)." + << " Less than 6 values were found." ); + return false; + } + return true; + } + //For ACR-NEMA + // 0020 0035 DS REL Image Orientation (RET) + else if ( (strImOriPat = GetEntryValue(0x0020,0x0035)) != GDCM_UNFOUND ) + { + if ( sscanf( strImOriPat.c_str(), "%f \\ %f \\%f \\%f \\%f \\%f ", + &iop[0], &iop[1], &iop[2], &iop[3], &iop[4], &iop[5]) != 6 ) + { + gdcmWarningMacro( "wrong Image Orientation Patient (0020,0035). " + << "Less than 6 values were found." ); + return false; + } + return true; + } + return false; +} + +/** + * \brief Retrieve the number of Bits Stored (actually used) + * (as opposed to number of Bits Allocated) + * @return The encountered number of Bits Stored, 0 by default. + * 0 means the file is NOT USABLE. The caller has to check it ! + */ +int File::GetBitsStored() +{ + std::string strSize = GetEntryValue( 0x0028, 0x0101 ); + if ( strSize == GDCM_UNFOUND ) + { + gdcmWarningMacro("BitsStored (0028,0101) is supposed to be mandatory"); + return 0; + } + return atoi( strSize.c_str() ); +} + +/** + * \brief Retrieve the number of Bits Allocated + * (8, 12 -compacted ACR-NEMA files-, 16, 24 -old RGB ACR-NEMA files-,) + * @return The encountered Number of Bits Allocated, 0 by default. + * 0 means the file is NOT USABLE. The caller has to check it ! + */ +int File::GetBitsAllocated() +{ + std::string strSize = GetEntryValue(0x0028,0x0100); + if ( strSize == GDCM_UNFOUND ) + { + gdcmWarningMacro("BitsAllocated (0028,0100) is supposed to be mandatory"); + return 0; + } + return atoi( strSize.c_str() ); +} + +/** + * \brief Retrieve the high bit position. + * \warning The method defaults to 0 when information is missing. + * The responsability of checking this value is left to the caller. + * @return The high bit position when present. 0 when missing. + */ +int File::GetHighBitPosition() +{ + std::string strSize = GetEntryValue( 0x0028, 0x0102 ); + if ( strSize == GDCM_UNFOUND ) + { + gdcmWarningMacro("HighBitPosition (0028,0102) is supposed to be mandatory"); + return 0; + } + return atoi( strSize.c_str() ); +} + +/** + * \brief Retrieve the number of Samples Per Pixel + * (1 : gray level, 3 : RGB/YBR -1 or 3 Planes-) + * @return The encountered number of Samples Per Pixel, 1 by default. + * (we assume Gray level Pixels) + */ +int File::GetSamplesPerPixel() +{ + const std::string &strSize = GetEntryValue(0x0028,0x0002); + if ( strSize == GDCM_UNFOUND ) + { + gdcmWarningMacro("SamplesPerPixel (0028,0002) is supposed to be mandatory"); + return 1; // Well, it's supposed to be mandatory ... + // but sometimes it's missing : *we* assume Gray pixels + } + return atoi( strSize.c_str() ); +} + +/** + * \brief Retrieve the Planar Configuration for RGB images + * (0 : RGB Pixels , 1 : R Plane + G Plane + B Plane) + * @return The encountered Planar Configuration, 0 by default. + */ +int File::GetPlanarConfiguration() +{ + std::string strSize = GetEntryValue(0x0028,0x0006); + if ( strSize == GDCM_UNFOUND ) + { + return 0; + } + return atoi( strSize.c_str() ); +} + +/** + * \brief Return the size (in bytes) of a single pixel of data. + * @return The size in bytes of a single pixel of data; 0 by default + * 0 means the file is NOT USABLE; the caller will have to check + */ +int File::GetPixelSize() +{ + // 0028 0100 US IMG Bits Allocated + // (in order no to be messed up by old ACR-NEMA RGB images) + assert( !(GetEntryValue(0x0028,0x0100) == "24") ); + + std::string pixelType = GetPixelType(); + if ( pixelType == "8U" || pixelType == "8S" ) + { + return 1; + } + if ( pixelType == "16U" || pixelType == "16S") + { + return 2; + } + if ( pixelType == "32U" || pixelType == "32S") + { + return 4; + } + if ( pixelType == "FD" ) + { + return 8; + } + gdcmWarningMacro( "Unknown pixel type: " << pixelType); + return 0; +} + +/** + * \brief Build the Pixel Type of the image. + * Possible values are: + * - 8U unsigned 8 bit, + * - 8S signed 8 bit, + * - 16U unsigned 16 bit, + * - 16S signed 16 bit, + * - 32U unsigned 32 bit, + * - 32S signed 32 bit, + * - FD floating double 64 bits (Not kosher DICOM, but so usefull!) + * \warning 12 bit images appear as 16 bit. + * 24 bit images appear as 8 bit + photochromatic interp ="RGB " + * + Planar Configuration = 0 + * @return 0S if nothing found. NOT USABLE file. The caller has to check + */ +std::string File::GetPixelType() +{ + std::string bitsAlloc = GetEntryValue(0x0028, 0x0100); // Bits Allocated + if ( bitsAlloc == GDCM_UNFOUND ) + { + gdcmWarningMacro( "Bits Allocated (0028,0100) supposed to be mandatory"); + bitsAlloc = "16"; // default and arbitrary value, not to polute the output + } + + if ( bitsAlloc == "64" ) + { + return "FD"; + } + else if ( bitsAlloc == "12" ) + { + // It will be unpacked + bitsAlloc = "16"; + } + else if ( bitsAlloc == "24" ) + { + // (in order no to be messed up by old RGB images) + bitsAlloc = "8"; + } + + std::string sign = GetEntryValue(0x0028, 0x0103);//"Pixel Representation" + + if (sign == GDCM_UNFOUND ) + { + gdcmWarningMacro( "Missing Pixel Representation (0028,0103)"); + sign = "U"; // default and arbitrary value, not to polute the output + } + else if ( sign == "0" ) + { + sign = "U"; + } + else + { + sign = "S"; + } + return bitsAlloc + sign; +} + +/** + * \brief Check whether the pixels are signed (1) or UNsigned (0) data. + * \warning The method defaults to false (UNsigned) when tag 0028|0103 + * is missing. + * The responsability of checking this value is left to the caller + * (NO transformation is performed on the pixels to make then >0) + * @return True when signed, false when UNsigned + */ +bool File::IsSignedPixelData() +{ + std::string strSign = GetEntryValue( 0x0028, 0x0103 ); + if ( strSign == GDCM_UNFOUND ) + { + gdcmWarningMacro( "Pixel Representation (0028,0103) supposed to be " + << "mandatory"); + return false; + } + int sign = atoi( strSign.c_str() ); + if ( sign == 0 ) + { + return false; + } + return true; +} + +/** + * \brief Check whether this a monochrome picture (gray levels) or not, + * using "Photometric Interpretation" tag (0x0028,0x0004). + * @return true when "MONOCHROME1" or "MONOCHROME2". False otherwise. + */ +bool File::IsMonochrome() +{ + const std::string &PhotometricInterp = GetEntryValue( 0x0028, 0x0004 ); + if ( Util::DicomStringEqual(PhotometricInterp, "MONOCHROME1") + || Util::DicomStringEqual(PhotometricInterp, "MONOCHROME2") ) + { + return true; + } + if ( PhotometricInterp == GDCM_UNFOUND ) + { + gdcmWarningMacro( "Photometric Interpretation (0028,0004) supposed to be " + << "mandatory"); + } + return false; +} + +/** + * \brief Check whether this a MONOCHROME1 picture (high values = dark) + * or not using "Photometric Interpretation" tag (0x0028,0x0004). + * @return true when "MONOCHROME1" . False otherwise. + */ +bool File::IsMonochrome1() +{ + const std::string &PhotometricInterp = GetEntryValue( 0x0028, 0x0004 ); + if ( Util::DicomStringEqual(PhotometricInterp, "MONOCHROME1") ) + { + return true; + } + if ( PhotometricInterp == GDCM_UNFOUND ) + { + gdcmWarningMacro( "Photometric Interpretation (0028,0004) : supposed to" + << " be mandatory! "); + } + return false; +} + +/** + * \brief Check whether this a "PALETTE COLOR" picture or not by accessing + * the "Photometric Interpretation" tag ( 0x0028, 0x0004 ). + * @return true when "PALETTE COLOR". False otherwise. + */ +bool File::IsPaletteColor() +{ + std::string PhotometricInterp = GetEntryValue( 0x0028, 0x0004 ); + if ( PhotometricInterp == "PALETTE COLOR " ) + { + return true; + } + if ( PhotometricInterp == GDCM_UNFOUND ) + { + gdcmWarningMacro( "Not found : Palette color (0028,0004)"); + } + return false; +} + +/** + * \brief Check whether this a "YBR_FULL" color picture or not by accessing + * the "Photometric Interpretation" tag ( 0x0028, 0x0004 ). + * @return true when "YBR_FULL". False otherwise. + */ +bool File::IsYBRFull() +{ + std::string PhotometricInterp = GetEntryValue( 0x0028, 0x0004 ); + if ( PhotometricInterp == "YBR_FULL" ) + { + return true; + } + if ( PhotometricInterp == GDCM_UNFOUND ) + { + gdcmWarningMacro( "Not found : YBR Full (0028,0004)"); + } + return false; +} + +/** + * \brief tells us if LUT are used + * \warning Right now, 'Segmented xxx Palette Color Lookup Table Data' + * are NOT considered as LUT, since nobody knows + * how to deal with them + * Please warn me if you know sbdy that *does* know ... jprx + * @return true if LUT Descriptors and LUT Tables were found + */ +bool File::HasLUT() +{ + // Check the presence of the LUT Descriptors, and LUT Tables + // LutDescriptorRed + if ( !GetDocEntry(0x0028,0x1101) ) + { + return false; + } + // LutDescriptorGreen + if ( !GetDocEntry(0x0028,0x1102) ) + { + return false; + } + // LutDescriptorBlue + if ( !GetDocEntry(0x0028,0x1103) ) + { + return false; + } + // Red Palette Color Lookup Table Data + if ( !GetDocEntry(0x0028,0x1201) ) + { + return false; + } + // Green Palette Color Lookup Table Data + if ( !GetDocEntry(0x0028,0x1202) ) + { + return false; + } + // Blue Palette Color Lookup Table Data + if ( !GetDocEntry(0x0028,0x1203) ) + { + return false; + } + + // FIXME : (0x0028,0x3006) : LUT Data (CTX dependent) + // NOT taken into account, but we don't know how to use it ... + return true; +} + +/** + * \brief gets the info from 0028,1101 : Lookup Table Desc-Red + * else 0 + * @return Lookup Table number of Bits , 0 by default + * when (0028,0004),Photometric Interpretation = [PALETTE COLOR ] + * @ return bit number of each LUT item + */ +int File::GetLUTNbits() +{ + std::vector<std::string> tokens; + int lutNbits; + + //Just hope Lookup Table Desc-Red = Lookup Table Desc-Red + // = Lookup Table Desc-Blue + // Consistency already checked in GetLUTLength + std::string lutDescription = GetEntryValue(0x0028,0x1101); + if ( lutDescription == GDCM_UNFOUND ) + { + return 0; + } + + tokens.clear(); // clean any previous value + Util::Tokenize ( lutDescription, tokens, "\\" ); + //LutLength=atoi(tokens[0].c_str()); + //LutDepth=atoi(tokens[1].c_str()); + + lutNbits = atoi( tokens[2].c_str() ); + tokens.clear(); + + return lutNbits; +} + +/** + *\brief gets the info from 0028,1052 : Rescale Intercept + * @return Rescale Intercept + */ +float File::GetRescaleIntercept() +{ + float resInter = 0.; + /// 0028 1052 DS IMG Rescale Intercept + const std::string &strRescInter = GetEntryValue(0x0028,0x1052); + if ( strRescInter != GDCM_UNFOUND ) + { + if ( sscanf( strRescInter.c_str(), "%f ", &resInter) != 1 ) + { + // bug in the element 0x0028,0x1052 + gdcmWarningMacro( "Rescale Intercept (0028,1052) is empty." ); + } + } + + return resInter; +} + +/** + *\brief gets the info from 0028,1053 : Rescale Slope + * @return Rescale Slope. defaulted to 1.0 is not found or empty + */ +float File::GetRescaleSlope() +{ + float resSlope = 1.; + //0028 1053 DS IMG Rescale Slope + std::string strRescSlope = GetEntryValue(0x0028,0x1053); + if ( strRescSlope != GDCM_UNFOUND ) + { + if ( sscanf( strRescSlope.c_str(), "%f ", &resSlope) != 1 ) + { + // bug in the element 0x0028,0x1053 + gdcmWarningMacro( "Rescale Slope (0028,1053) is empty."); + } + } + + return resSlope; +} + +/** + * \brief This function is intended to user who doesn't want + * to have to manage a LUT and expects to get an RBG Pixel image + * (or a monochrome one ...) + * \warning to be used with GetImagePixels() + * @return 1 if Gray level, 3 if Color (RGB, YBR, *or PALETTE COLOR*) + */ +int File::GetNumberOfScalarComponents() +{ + if ( GetSamplesPerPixel() == 3 ) + { + return 3; + } + + // 0028 0100 US IMG Bits Allocated + // (in order no to be messed up by old RGB images) + if ( GetEntryValue(0x0028,0x0100) == "24" ) + { + return 3; + } + + std::string strPhotometricInterpretation = GetEntryValue(0x0028,0x0004); + + if ( ( strPhotometricInterpretation == "PALETTE COLOR ") ) + { + if ( HasLUT() )// PALETTE COLOR is NOT enough + { + return 3; + } + else + { + return 1; + } + } + + // beware of trailing space at end of string + // DICOM tags are never of odd length + if ( strPhotometricInterpretation == GDCM_UNFOUND || + Util::DicomStringEqual(strPhotometricInterpretation, "MONOCHROME1") || + Util::DicomStringEqual(strPhotometricInterpretation, "MONOCHROME2") ) + { + return 1; + } + else + { + // we assume that *all* kinds of YBR are dealt with + return 3; + } +} + +/** + * \brief This function is intended to user that DOESN'T want + * to get RGB pixels image when it's stored as a PALETTE COLOR image + * - the (vtk) user is supposed to know how deal with LUTs - + * \warning to be used with GetImagePixelsRaw() + * @return 1 if Gray level, 3 if Color (RGB or YBR - NOT 'PALETTE COLOR' -) + */ +int File::GetNumberOfScalarComponentsRaw() +{ + // 0028 0100 US IMG Bits Allocated + // (in order no to be messed up by old RGB images) + if ( File::GetEntryValue(0x0028,0x0100) == "24" ) + { + return 3; + } + + // we assume that *all* kinds of YBR are dealt with + return GetSamplesPerPixel(); +} + +/** + * \brief Recover the offset (from the beginning of the file) + * of *image* pixels (not *icone image* pixels, if any !) + * @return Pixel Offset + */ +size_t File::GetPixelOffset() +{ + DocEntry *pxlElement = GetDocEntry(GrPixel, NumPixel); + if ( pxlElement ) + { + return pxlElement->GetOffset(); + } + else + { + gdcmDebugMacro( "Big trouble : Pixel Element (" + << std::hex << GrPixel<<","<< NumPixel<< ") NOT found" ); + return 0; + } +} + +/** + * \brief Recover the pixel area length (in Bytes) + * @return Pixel Element Length, as stored in the header + * (NOT the memory space necessary to hold the Pixels + * -in case of embeded compressed image-) + * 0 : NOT USABLE file. The caller has to check. + */ +size_t File::GetPixelAreaLength() +{ + DocEntry *pxlElement = GetDocEntry(GrPixel, NumPixel); + if ( pxlElement ) + { + return pxlElement->GetLength(); + } + else + { + gdcmDebugMacro( "Big trouble : Pixel Element (" + << std::hex << GrPixel<<","<< NumPixel<< ") NOT found" ); + return 0; + } +} + +/** + * \brief Adds the characteristics of a new element we want to anonymize + * @param group Group number of the target tag. + * @param elem Element number of the target tag. + * @param value new value (string) to substitute with + */ +void File::AddAnonymizeElement (uint16_t group, uint16_t elem, + std::string const &value) +{ + Element el; + el.Group = group; + el.Elem = elem; + el.Value = value; + UserAnonymizeList.push_back(el); +} + +/** + * \brief Overwrites in the file the values of the DicomElements + * held in the list + */ +void File::AnonymizeNoLoad() +{ + std::fstream *fp = new std::fstream(Filename.c_str(), + std::ios::in | std::ios::out | std::ios::binary); + gdcm::DocEntry *d; + uint32_t offset; + uint32_t lgth; + uint32_t valLgth = 0; + std::string *spaces; + for (ListElements::iterator it = UserAnonymizeList.begin(); + it != UserAnonymizeList.end(); + ++it) + { + d = GetDocEntry( (*it).Group, (*it).Elem); + + if ( d == NULL) + continue; + + if ( dynamic_cast<SeqEntry *>(d) ) + { + gdcmWarningMacro( "You cannot 'Anonymize' a SeqEntry "); + continue; + } + + offset = d->GetOffset(); + lgth = d->GetLength(); + if (valLgth < lgth) + { + spaces = new std::string( lgth-valLgth, ' '); + (*it).Value = (*it).Value + *spaces; + delete spaces; + } + fp->seekp( offset, std::ios::beg ); + fp->write( (*it).Value.c_str(), lgth ); + + } + fp->close(); + delete fp; +} + +/** + * \brief anonymize a File (remove Patient's personal info passed with + * AddAnonymizeElement() + * \note You cannot Anonymize a BinEntry (to be fixed) + */ +bool File::AnonymizeFile() +{ + // If Anonymisation list is empty, let's perform some basic anonymization + if ( UserAnonymizeList.begin() == UserAnonymizeList.end() ) + { + // If exist, replace by spaces + SetValEntry (" ",0x0010, 0x2154); // Telephone + SetValEntry (" ",0x0010, 0x1040); // Adress + SetValEntry (" ",0x0010, 0x0020); // Patient ID + + DocEntry* patientNameHE = GetDocEntry (0x0010, 0x0010); + + if ( patientNameHE ) // we replace it by Study Instance UID (why not ?) + { + std::string studyInstanceUID = GetEntryValue (0x0020, 0x000d); + if ( studyInstanceUID != GDCM_UNFOUND ) + { + SetValEntry(studyInstanceUID, 0x0010, 0x0010); + } + else + { + SetValEntry("anonymized", 0x0010, 0x0010); + } + } + } + else + { + gdcm::DocEntry *d; + for (ListElements::iterator it = UserAnonymizeList.begin(); + it != UserAnonymizeList.end(); + ++it) + { + d = GetDocEntry( (*it).Group, (*it).Elem); + + if ( d == NULL) + continue; + + if ( dynamic_cast<SeqEntry *>(d) ) + { + gdcmWarningMacro( "You cannot 'Anonymize' a SeqEntry "); + continue; + } + + if ( dynamic_cast<BinEntry *>(d) ) + { + gdcmWarningMacro( "To 'Anonymize' a BinEntry, better use AnonymizeNoLoad (FIXME) "); + continue; + } + else + SetValEntry ((*it).Value, (*it).Group, (*it).Elem); + } +} + + // In order to make definitively impossible any further identification + // remove or replace all the stuff that contains a Date + +//0008 0012 DA ID Instance Creation Date +//0008 0020 DA ID Study Date +//0008 0021 DA ID Series Date +//0008 0022 DA ID Acquisition Date +//0008 0023 DA ID Content Date +//0008 0024 DA ID Overlay Date +//0008 0025 DA ID Curve Date +//0008 002a DT ID Acquisition Datetime +//0018 9074 DT ACQ Frame Acquisition Datetime +//0018 9151 DT ACQ Frame Reference Datetime +//0018 a002 DT ACQ Contribution Date Time +//0020 3403 SH REL Modified Image Date (RET) +//0032 0032 DA SDY Study Verified Date +//0032 0034 DA SDY Study Read Date +//0032 1000 DA SDY Scheduled Study Start Date +//0032 1010 DA SDY Scheduled Study Stop Date +//0032 1040 DA SDY Study Arrival Date +//0032 1050 DA SDY Study Completion Date +//0038 001a DA VIS Scheduled Admission Date +//0038 001c DA VIS Scheduled Discharge Date +//0038 0020 DA VIS Admitting Date +//0038 0030 DA VIS Discharge Date +//0040 0002 DA PRC Scheduled Procedure Step Start Date +//0040 0004 DA PRC Scheduled Procedure Step End Date +//0040 0244 DA PRC Performed Procedure Step Start Date +//0040 0250 DA PRC Performed Procedure Step End Date +//0040 2004 DA PRC Issue Date of Imaging Service Request +//0040 4005 DT PRC Scheduled Procedure Step Start Date and Time +//0040 4011 DT PRC Expected Completion Date and Time +//0040 a030 DT PRC Verification Date Time +//0040 a032 DT PRC Observation Date Time +//0040 a120 DT PRC DateTime +//0040 a121 DA PRC Date +//0040 a13a DT PRC Referenced Datetime +//0070 0082 DA ??? Presentation Creation Date +//0100 0420 DT ??? SOP Autorization Date and Time +//0400 0105 DT ??? Digital Signature DateTime +//2100 0040 DA PJ Creation Date +//3006 0008 DA SSET Structure Set Date +//3008 0024 DA ??? Treatment Control Point Date +//3008 0054 DA ??? First Treatment Date +//3008 0056 DA ??? Most Recent Treatment Date +//3008 0162 DA ??? Safe Position Exit Date +//3008 0166 DA ??? Safe Position Return Date +//3008 0250 DA ??? Treatment Date +//300a 0006 DA RT RT Plan Date +//300a 022c DA RT Air Kerma Rate Reference Date +//300e 0004 DA RT Review Date + + return true; +} + +/** + * \brief Performs some consistency checking on various 'File related' + * (as opposed to 'DicomDir related') entries + * then writes in a file all the (Dicom Elements) included the Pixels + * @param fileName file name to write to + * @param writetype type of the file to be written + * (ACR, ExplicitVR, ImplicitVR) + */ +bool File::Write(std::string fileName, FileType writetype) +{ + std::ofstream *fp = new std::ofstream(fileName.c_str(), + std::ios::out | std::ios::binary); + if (*fp == NULL) + { + gdcmWarningMacro("Failed to open (write) File: " << fileName.c_str()); + return false; + } + + // Entry : 0002|0000 = group length -> recalculated + ValEntry *e0000 = GetValEntry(0x0002,0x0000); + if ( e0000 ) + { + itksys_ios::ostringstream sLen; + sLen << ComputeGroup0002Length( ); + e0000->SetValue(sLen.str()); + } + + int i_lgPix = GetEntryLength(GrPixel, NumPixel); + if (i_lgPix != -2) + { + // no (GrPixel, NumPixel) element + std::string s_lgPix = Util::Format("%d", i_lgPix+12); + s_lgPix = Util::DicomString( s_lgPix.c_str() ); + InsertValEntry(s_lgPix,GrPixel, 0x0000); + } + Document::WriteContent(fp, writetype); + + fp->close(); + delete fp; + + return true; +} + +//----------------------------------------------------------------------------- +// Protected + + +//----------------------------------------------------------------------------- +// Private +/** + * \brief Parse pixel data from disk of [multi-]fragment RLE encoding. + * Compute the RLE extra information and store it in \ref RLEInfo + * for later pixel retrieval usage. + */ +void File::ComputeRLEInfo() +{ + std::string ts = GetTransferSyntax(); + if ( !Global::GetTS()->IsRLELossless(ts) ) + { + return; + } + + // Encoded pixel data: for the time being we are only concerned with + // Jpeg or RLE Pixel data encodings. + // As stated in PS 3.5-2003, section 8.2 p44: + // "If sent in Encapsulated Format (i.e. other than the Native Format) the + // value representation OB is used". + // Hence we expect an OB value representation. Concerning OB VR, + // the section PS 3.5-2003, section A.4.c p 58-59, states: + // "For the Value Representations OB and OW, the encoding shall meet the + // following specifications depending on the Data element tag:" + // [...snip...] + // - the first item in the sequence of items before the encoded pixel + // data stream shall be basic offset table item. The basic offset table + // item value, however, is not required to be present" + ReadEncapsulatedBasicOffsetTable(); + + // Encapsulated RLE Compressed Images (see PS 3.5-2003, Annex G) + // Loop on the individual frame[s] and store the information + // on the RLE fragments in a RLEFramesInfo. + // Note: - when only a single frame is present, this is a + // classical image. + // - when more than one frame are present, then we are in + // the case of a multi-frame image. + long frameLength; + int i=0; + uint32_t sum = 0; + while ( (frameLength = ReadTagLength(0xfffe, 0xe000)) != 0 ) + { + // Since we have read the basic offset table, let's check the value were correct + // or else produce a warning: + if ( BasicOffsetTableItemValue ) + { + // If a BasicOffsetTableItemValue was read + uint32_t individualLength = BasicOffsetTableItemValue[i]; + assert( individualLength == sum ); // REMOVE that if this is a problem + if( individualLength != sum ) + { + gdcmWarningMacro( "BasicOffsetTableItemValue differs from the fragment lenght" ); + } + sum += frameLength + 8; + i++; + } + // Parse the RLE Header and store the corresponding RLE Segment + // Offset Table information on fragments of this current Frame. + // Note that the fragment pixels themselves are not loaded + // (but just skipped). + long frameOffset = Fp->tellg(); // once per fragment + + uint32_t nbRleSegments = ReadInt32(); + if ( nbRleSegments > 16 ) + { + // There should be at most 15 segments (refer to RLEFrame class) + gdcmWarningMacro( "Too many segments."); + } + + uint32_t rleSegmentOffsetTable[16]; + for( int k = 1; k <= 15; k++ ) + { + rleSegmentOffsetTable[k] = ReadInt32(); + } + + // Deduce from both RLE Header and frameLength + // the fragment length, and again store this info + // in a RLEFramesInfo. + long rleSegmentLength[15]; + // skipping (not reading) RLE Segments + if ( nbRleSegments > 1) + { + for(unsigned int k = 1; k <= nbRleSegments-1; k++) + { + rleSegmentLength[k] = rleSegmentOffsetTable[k+1] + - rleSegmentOffsetTable[k]; + SkipBytes(rleSegmentLength[k]); + } + } + + rleSegmentLength[nbRleSegments] = frameLength + - rleSegmentOffsetTable[nbRleSegments]; + SkipBytes(rleSegmentLength[nbRleSegments]); + + // Store the collected info + RLEFrame *newFrame = new RLEFrame; + newFrame->SetNumberOfFragments(nbRleSegments); + for( unsigned int uk = 1; uk <= nbRleSegments; uk++ ) + { + newFrame->SetOffset(uk,frameOffset + rleSegmentOffsetTable[uk]); + newFrame->SetLength(uk,rleSegmentLength[uk]); + } + RLEInfo->AddFrame(newFrame); + } + + // Make sure that we encounter a 'Sequence Delimiter Item' + // at the end of the item : + if ( !ReadTag(0xfffe, 0xe0dd) ) // once per RLE File + { + gdcmWarningMacro( "No sequence delimiter item at end of RLE item sequence"); + } +} + +/** + * \brief Parse pixel data from disk of [multi-]fragment Jpeg encoding. + * Compute the jpeg extra information (fragment[s] offset[s] and + * length) and store it[them] in \ref JPEGInfo for later pixel + * retrieval usage. + */ +void File::ComputeJPEGFragmentInfo() +{ + // If you need to, look for comments of ComputeRLEInfo(). + std::string ts = GetTransferSyntax(); + if ( ! Global::GetTS()->IsJPEG(ts) ) + { + return; + } + + ReadEncapsulatedBasicOffsetTable(); + + // Loop on the fragments[s] and store the parsed information in a + // JPEGInfo. + long fragmentLength; + int i=0; + uint32_t sum = 0; + while ( (fragmentLength = ReadTagLength(0xfffe, 0xe000)) != 0 ) + { + // Since we have read the basic offset table, let's check the value were correct + // or else produce a warning: + // A.4 Transfer syntaxes for encapsulation of encoded pixel data: + // When the Item Value is present, the Basic Offset Table Item Value shall contain + // concatenated 32-bit unsigned integer values that are byte offsets to the first + // byte of the Item Tag of the first fragment for each frame in the Sequence of + // Items. These offsets are measured from the first byte of the first Item Tag + // following the Basic Offset Table item (See Table A.4-2). + + if ( BasicOffsetTableItemValue ) + { + // If a BasicOffsetTableItemValue was read + uint32_t individualLength = BasicOffsetTableItemValue[i]; + //assert( individualLength == sum ); // Seems like 00191113.dcm is off by one ?? + if( individualLength != sum ) + { + gdcmWarningMacro( "BasicOffsetTableItemValue differs from the fragment lenght:" << + individualLength << " != " << sum ); + } + sum += fragmentLength + 8; + i++; + } + + long fragmentOffset = Fp->tellg(); // Once per fragment + // Store the collected info + JPEGFragment *newFragment = new JPEGFragment; + newFragment->SetOffset(fragmentOffset); + newFragment->SetLength(fragmentLength); + JPEGInfo->AddFragment(newFragment); + + SkipBytes(fragmentLength); + } + + // Make sure that we encounter a 'Sequence Delimiter Item' + // at the end of the item : + if ( !ReadTag(0xfffe, 0xe0dd) ) + { + gdcmWarningMacro( "No sequence delimiter item at end of JPEG item sequence"); + } +} + +/** + * \brief Assuming the internal file pointer \ref Document::Fp + * is placed at the beginning of a tag, check whether this + * tag is (TestGroup, TestElem). + * \warning On success the internal file pointer \ref Document::Fp + * is modified to point after the tag. + * On failure (i.e. when the tag wasn't the expected tag + * (TestGroup, TestElem) the internal file pointer + * \ref Document::Fp is restored to it's original position. + * @param testGroup The expected group of the tag. + * @param testElem The expected Element of the tag. + * @return True on success, false otherwise. + */ +bool File::ReadTag(uint16_t testGroup, uint16_t testElem) +{ + long positionOnEntry = Fp->tellg(); // Only when reading fragments + //long currentPosition = positionOnEntry; // On debugging purposes + + // Read the Item Tag group and element, and make + // sure they are what we expected: + uint16_t itemTagGroup; + uint16_t itemTagElem; + try + { + itemTagGroup = ReadInt16(); + itemTagElem = ReadInt16(); + } + catch ( FormatError ) + { + gdcmErrorMacro( "Can not read tag for " + << " We should have found tag (" + << DictEntry::TranslateToKey(testGroup,testElem) << ")" + ) ; + + return false; + } + if ( itemTagGroup != testGroup || itemTagElem != testElem ) + { + // in order not to pollute output we don't warn on 'delimitors' + if (itemTagGroup != 0xfffe || testGroup != 0xfffe ) + gdcmWarningMacro( "Wrong Item Tag found:" + << " We should have found tag (" + << std::hex << testGroup << "," << testElem << ")" << std::endl + << " but instead we encountered tag (" + << std::hex << itemTagGroup << "," << itemTagElem << ")" + << " at address: " << " 0x(" << (unsigned int)positionOnEntry << ")" + ) ; + Fp->seekg(positionOnEntry, std::ios::beg); + + return false; + } + return true; +} + +/** + * \brief Assuming the internal file pointer \ref Document::Fp + * is placed at the beginning of a tag (TestGroup, TestElement), + * read the length associated to the Tag. + * \warning On success the internal file pointer \ref Document::Fp + * is modified to point after the tag and it's length. + * On failure (i.e. when the tag wasn't the expected tag + * (TestGroup, TestElement) the internal file pointer + * \ref Document::Fp is restored to it's original position. + * @param testGroup The expected Group of the tag. + * @param testElem The expected Element of the tag. + * @return On success returns the length associated to the tag. On failure + * returns 0. + */ +uint32_t File::ReadTagLength(uint16_t testGroup, uint16_t testElem) +{ + + if ( !ReadTag(testGroup, testElem) ) + { + return 0; + } + + //// Then read the associated Item Length + long currentPosition = Fp->tellg(); + uint32_t itemLength = ReadInt32(); + { + gdcmWarningMacro( "Basic Item Length is: " + << itemLength << std::endl + << " at address: " << std::hex << (unsigned int)currentPosition); + } + return itemLength; +} + +/** + * \brief When parsing the Pixel Data of an encapsulated file, read + * the basic offset table (when present, and BTW dump it). + */ +void File::ReadEncapsulatedBasicOffsetTable() +{ + //// Read the Basic Offset Table Item Tag length... + uint32_t itemLength = ReadTagLength(0xfffe, 0xe000); + + // When present, read the basic offset table itself. + // Notes: - since the presence of this basic offset table is optional + // we can't rely on it for the implementation, and we will simply + // trash it's content (when present). + // - still, when present, we could add some further checks on the + // lengths, but we won't bother with such fuses for the time being. + if ( itemLength != 0 ) + { + char *charBasicOffsetTableItemValue = new char[itemLength]; + Fp->read(charBasicOffsetTableItemValue, itemLength); + unsigned int nbEntries = itemLength/4; + assert( nbEntries*4 == itemLength); // Make sure this is a multiple + BasicOffsetTableItemValue = new uint32_t[nbEntries]; + + for (unsigned int i=0; i < nbEntries; i++ ) + { + BasicOffsetTableItemValue[i] = *((uint32_t*)(&charBasicOffsetTableItemValue[4*i])); +#if defined(GDCM_WORDS_BIGENDIAN) || defined(GDCM_FORCE_BIGENDIAN_EMULATION) + uint32_t val = BasicOffsetTableItemValue[i]; + BasicOffsetTableItemValue[i] + = ( (val<<24) | ((val<<8) & 0x00ff0000) | + ( (val>>8) & 0x0000ff00) | (val>>24) ); +#endif + gdcmDebugMacro( "Read one length for: " << + std::hex << BasicOffsetTableItemValue[i] ); + } + + delete[] charBasicOffsetTableItemValue; + } +} + +// These are the deprecated method that one day should be removed (after the next release) + +#ifndef GDCM_LEGACY_REMOVE +/* + * \brief Constructor (DEPRECATED : temporaryly kept not to break the API) + * @param filename name of the file whose header we want to analyze + * @deprecated do not use any longer + */ +File::File( std::string const &filename ) + :Document( ) +{ + RLEInfo = new RLEFramesInfo; + JPEGInfo = new JPEGFragmentsInfo; + GrPixel = 0x7fe0; // to avoid further troubles + NumPixel = 0x0010; + BasicOffsetTableItemValue = 0; + + SetFileName( filename ); + Load( ); // gdcm::Document is first Loaded, then the 'File part' +} + +/** + * \brief Loader. (DEPRECATED : temporaryly kept not to break the API) + * @param fileName file to be open for parsing + * @return false if file cannot be open or no swap info was found, + * or no tag was found. + * @deprecated Use the Load() [ + SetLoadMode() ] + SetFileName() functions instead + */ +bool File::Load( std::string const &fileName ) +{ + GDCM_LEGACY_REPLACED_BODY(File::Load(std::string), "1.2", + File::Load()); + SetFileName( fileName ); + if ( ! this->Document::Load( ) ) + return false; + + return DoTheLoadingJob( ); +} +#endif + +//----------------------------------------------------------------------------- +// Print + +//----------------------------------------------------------------------------- +} // end namespace gdcm diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmFile.h b/Utilities/ITK/Utilities/gdcm/src/gdcmFile.h new file mode 100644 index 0000000000000000000000000000000000000000..b07e0629f000bb0d7037b76fec96ec1918e0832c --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmFile.h @@ -0,0 +1,208 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmFile.h,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:39 $ + Version: $Revision: 1.5 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#ifndef GDCMFILE_H +#define GDCMFILE_H + +#include "gdcmDebug.h" +#include "gdcmDocument.h" + + + +namespace gdcm +{ + +class RLEFramesInfo; +class JPEGFragmentsInfo; + +//----------------------------------------------------------------------------- +// Dicom Part 3.3 Compliant +enum ModalityType { + Unknow, + AU, // Voice Audio + AS, // Angioscopy + BI, // Biomagnetic Imaging + CF, // Cinefluorography + CP, // Culposcopy + CR, // Computed Radiography + CS, // Cystoscopy + CT, // Computed Tomography + DD, // Duplex Dopler + DF, // Digital Fluoroscopy + DG, // Diaphanography + DM, // Digital Microscopy + DS, // Digital Substraction Angiography + DX, // Digital Radiography + ECG, // Echocardiography + EPS, // Basic Cardiac EP + ES, // Endoscopy + FA, // Fluorescein Angiography + FS, // Fundoscopy + HC, // Hard Copy + HD, // Hemodynamic + LP, // Laparoscopy + LS, // Laser Surface Scan + MA, // Magnetic Resonance Angiography + MR, // Magnetic Resonance + NM, // Nuclear Medicine + OT, // Other + PT, // Positron Emission Tomography + RF, // Radio Fluoroscopy + RG, // Radiographic Imaging + RTDOSE, // Radiotherapy Dose + RTIMAGE, // Radiotherapy Image + RTPLAN, // Radiotherapy Plan + RTSTRUCT, // Radiotherapy Structure Set + SM, // Microscopic Imaging + ST, // Single-photon Emission Computed Tomography + TG, // Thermography + US, // Ultrasound + VF, // Videofluorography + XA, // X-Ray Angiography + XC // Photographic Imaging +}; + +//----------------------------------------------------------------------------- + +/** + * \brief DICOM elements and their corresponding values (and + * additionaly the corresponding DICOM dictionary entry) of the header + * of a DICOM file. + * + * The typical usage of instances of class File is to classify a set of + * dicom files according to header information e.g. to create a file hierarchy + * reflecting the Patient/Study/Serie informations, or extracting a given + * SerieId. Accessing the content (image[s] or volume[s]) is beyond the + * functionality of this class and belongs to gdcm::FileHelper. + * \note The various entries of the explicit value representation (VR) shall + * be managed within a dictionary which is shared by all File + * instances. + * \note The File::Set*Tag* family members cannot be defined as + * protected due to Swig limitations for as Has_a dependency between + * File and FileHelper. + */ +class GDCM_EXPORT File : public Document +{ +public: + File(); + GDCM_LEGACY(File( std::string const &filename )); + ~File(); + + // Loading + GDCM_LEGACY(bool Load( std::string const &filename )); + bool Load(); + // Standard values and informations contained in the header + bool IsReadable(); + + // Some heuristic based accessors, end user intended + int GetImageNumber(); + ModalityType GetModality(); + + int GetXSize(); + int GetYSize(); + int GetZSize(); + + float GetXSpacing(); + float GetYSpacing(); + float GetZSpacing(); + + float GetXOrigin(); + float GetYOrigin(); + float GetZOrigin(); + + bool GetImageOrientationPatient( float iop[6] ); + + int GetBitsStored(); + int GetBitsAllocated(); + int GetHighBitPosition(); + int GetSamplesPerPixel(); + int GetPlanarConfiguration(); + int GetPixelSize(); + std::string GetPixelType(); + bool IsSignedPixelData(); + bool IsMonochrome(); + bool IsMonochrome1(); + bool IsPaletteColor(); + bool IsYBRFull(); + + bool HasLUT(); + int GetLUTNbits(); + + // For rescaling graylevel: + float GetRescaleIntercept(); + float GetRescaleSlope(); + + int GetNumberOfScalarComponents(); + int GetNumberOfScalarComponentsRaw(); + + /// Accessor to \ref File::GrPixel + uint16_t GetGrPixel() { return GrPixel; } + /// Accessor to \ref File::NumPixel + uint16_t GetNumPixel() { return NumPixel; } + + size_t GetPixelOffset(); + size_t GetPixelAreaLength(); + + /// returns the RLE info + RLEFramesInfo *GetRLEInfo() { return RLEInfo; } + /// Returns the JPEG Fragments info + JPEGFragmentsInfo *GetJPEGInfo() { return JPEGInfo; } + +// Anonymization process + void AddAnonymizeElement (uint16_t group, uint16_t elem, + std::string const &value); + /// Clears the list of elements to be anonymized + void ClearAnonymizeList() { UserAnonymizeList.clear(); } + void AnonymizeNoLoad(); + /// Replace patient's own information by info from the Anonymization list + bool AnonymizeFile(); + + bool Write(std::string fileName, FileType filetype); + +protected: + + /// Store the RLE frames info obtained during parsing of pixels. + RLEFramesInfo *RLEInfo; + /// Store the JPEG fragments info obtained during parsing of pixels. + JPEGFragmentsInfo *JPEGInfo; + + /// \brief In some cases (e.g. for some ACR-NEMA images) the Entry Element + /// Number of the 'Pixel Element' is *not* found at 0x0010. In order to + /// make things easier the parser shall store the proper value in + /// NumPixel to provide a unique access facility. + uint16_t NumPixel; + /// \brief In some cases (e.g. for some ACR-NEMA images) the header entry for + /// the group of pixels is *not* found at 0x7fe0. + /// In order to make things easier the parser shall store the proper value + /// in GrPixel to provide a unique access facility. + uint16_t GrPixel; + +private: + bool DoTheLoadingJob(); + void ComputeRLEInfo(); + void ComputeJPEGFragmentInfo(); + bool ReadTag(uint16_t, uint16_t); + uint32_t ReadTagLength(uint16_t, uint16_t); + void ReadEncapsulatedBasicOffsetTable(); + uint32_t *BasicOffsetTableItemValue; + +}; +} // end namespace gdcm + +//----------------------------------------------------------------------------- +#endif diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmFileHelper.cxx b/Utilities/ITK/Utilities/gdcm/src/gdcmFileHelper.cxx new file mode 100644 index 0000000000000000000000000000000000000000..a6f7a08c24989af71b6e038ffa307f0dddefa211 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmFileHelper.cxx @@ -0,0 +1,1763 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmFileHelper.cxx,v $ + Language: C++ + + Date: $Date: 2006/03/08 20:09:44 $ + Version: $Revision: 1.12 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#include "gdcmFileHelper.h" +#include "gdcmGlobal.h" +#include "gdcmTS.h" +#include "gdcmDocument.h" +#include "gdcmDebug.h" +#include "gdcmUtil.h" +#include "gdcmBinEntry.h" +#include "gdcmValEntry.h" +#include "gdcmSeqEntry.h" +#include "gdcmSQItem.h" +#include "gdcmContentEntry.h" +#include "gdcmFile.h" +#include "gdcmPixelReadConvert.h" +#include "gdcmPixelWriteConvert.h" +#include "gdcmDocEntryArchive.h" +#include "gdcmDictSet.h" +#include "gdcmOrientation.h" +#if defined(__BORLANDC__) + #include <mem.h> // for memset +#endif + +#include <fstream> + +/* +// ----------------------------- WARNING ------------------------- + +These lines will be moved to the document-to-be 'User's Guide' + +// To read an image, user needs a gdcm::File +gdcm::File *f = new gdcm::File(fileName); +// or (advanced) : +// user may also decide he doesn't want to load some parts of the header +gdcm::File *f = new gdcm::File(); +f->SetFileName(fileName); + f->SetLoadMode(LD_NOSEQ); // or + f->SetLoadMode(LD_NOSHADOW); // or + f->SetLoadMode(LD_NOSEQ | LD_NOSHADOW); // or + f->SetLoadMode(LD_NOSHADOWSEQ); +f->Load(); + +// user can now check some values +std::string v = f->GetEntryValue(groupNb,ElementNb); + +// to get the pixels, user needs a gdcm::FileHelper +gdcm::FileHelper *fh = new gdcm::FileHelper(f); +// user may ask not to convert Palette to RGB +uint8_t *pixels = fh->GetImageDataRaw(); +int imageLength = fh->GetImageDataRawSize(); +// He can now use the pixels, create a new image, ... +uint8_t *userPixels = ... + +To re-write the image, user re-uses the gdcm::FileHelper + +fh->SetImageData( userPixels, userPixelsLength); +fh->SetTypeToRaw(); // Even if it was possible to convert Palette to RGB + // (WriteMode is set) + +fh->SetWriteTypeToDcmExpl(); // he wants Explicit Value Representation + // Little Endian is the default + // no other value is allowed + (-->SetWriteType(ExplicitVR);) + -->WriteType = ExplicitVR; +fh->Write(newFileName); // overwrites the file, if any + +// or : +fh->WriteDcmExplVR(newFileName); + + +// ----------------------------- WARNING ------------------------- + +These lines will be moved to the document-to-be 'Developer's Guide' + +WriteMode : WMODE_RAW / WMODE_RGB +WriteType : ImplicitVR, ExplicitVR, ACR, ACR_LIBIDO + +fh1->Write(newFileName); + SetWriteFileTypeToImplicitVR() / SetWriteFileTypeToExplicitVR(); + (modifies TransferSyntax) + SetWriteToRaw(); / SetWriteToRGB(); + (modifies, when necessary : photochromatic interpretation, + samples per pixel, Planar configuration, + bits allocated, bits stored, high bit -ACR 24 bits- + Pixels element VR, pushes out the LUT ) + CheckWriteIntegrity(); + (checks user given pixels length) + FileInternal->Write(fileName,WriteType) + fp = opens file(fileName); + ComputeGroup0002Length( ); + BitsAllocated 12->16 + RemoveEntryNoDestroy(palettes, etc) + Document::WriteContent(fp, writetype); + RestoreWrite(); + (moves back to the File all the archived elements) + RestoreWriteFileType(); + (pushes back group 0002, with TransferSyntax) +*/ + + + + +namespace gdcm +{ +//------------------------------------------------------------------------- +// Constructor / Destructor +/** + * \brief Constructor dedicated to deal with the *pixels* area of a ACR/DICOMV3 + * file (gdcm::File only deals with the ... header) + * Opens (in read only and when possible) an existing file and checks + * for DICOM compliance. Returns NULL on failure. + * It will be up to the user to load the pixels into memory + * ( GetImageDataSize() + GetImageData() methods) + * \note the in-memory representation of all available tags found in + * the DICOM header is post-poned to first header information access. + * This avoid a double parsing of public part of the header when + * one sets an a posteriori shadow dictionary (efficiency can be + * seen as a side effect). + */ +FileHelper::FileHelper( ) +{ + FileInternal = new File( ); + SelfHeader = true; + Initialize(); +} + +/** + * \brief Constructor dedicated to deal with the *pixels* area of a ACR/DICOMV3 + * file (File only deals with the ... header) + * Opens (in read only and when possible) an existing file and checks + * for DICOM compliance. Returns NULL on failure. + * It will be up to the user to load the pixels into memory + * ( GetImageDataSize() + GetImageData() methods) + * \note the in-memory representation of all available tags found in + * the DICOM header is post-poned to first header information access. + * This avoid a double parsing of public part of the header when + * user sets an a posteriori shadow dictionary (efficiency can be + * seen as a side effect). + * @param header already built Header + */ +FileHelper::FileHelper(File *header) +{ + FileInternal = header; + SelfHeader = false; + Initialize(); + if ( FileInternal->IsReadable() ) + { + PixelReadConverter->GrabInformationsFromFile( FileInternal ); + } +} + +#ifndef GDCM_LEGACY_REMOVE +/** + * \brief DEPRECATED : use SetFilename() + SetLoadMode() + Load() methods + * Constructor dedicated to deal with the *pixels* area of a ACR/DICOMV3 + * file (gdcm::File only deals with the ... header) + * Opens (in read only and when possible) an existing file and checks + * for DICOM compliance. Returns NULL on failure. + * It will be up to the user to load the pixels into memory + * \note the in-memory representation of all available tags found in + * the DICOM header is post-poned to first header information access. + * This avoid a double parsing of public part of the header when + * one sets an a posteriori shadow dictionary (efficiency can be + * seen as a side effect). + * @param filename file to be opened for parsing + * @deprecated use SetFilename() + Load() methods + */ +FileHelper::FileHelper(std::string const &filename ) +{ + FileInternal = new File( ); + FileInternal->SetFileName( filename ); + FileInternal->Load(); + SelfHeader = true; + Initialize(); + if ( FileInternal->IsReadable() ) + { + PixelReadConverter->GrabInformationsFromFile( FileInternal ); + } +} +#endif + +/** + * \brief canonical destructor + * \note If the header (gdcm::File) was created by the FileHelper constructor, + * it is destroyed by the FileHelper + */ +FileHelper::~FileHelper() +{ + if ( PixelReadConverter ) + { + delete PixelReadConverter; + } + if ( PixelWriteConverter ) + { + delete PixelWriteConverter; + } + if ( Archive ) + { + delete Archive; + } + + if ( SelfHeader ) + { + delete FileInternal; + } + FileInternal = 0; +} + +//----------------------------------------------------------------------------- +// Public + +/** + * \brief Sets the LoadMode of the internal gdcm::File as a boolean string. + * NO_SEQ, NO_SHADOW, NO_SHADOWSEQ ... (nothing more, right now) + * WARNING : before using NO_SHADOW, be sure *all* your files + * contain accurate values in the 0x0000 element (if any) + * of *each* Shadow Group. The parser will fail if the size is wrong ! + * @param loadMode Load mode to be used + */ +void FileHelper::SetLoadMode(int loadMode) +{ + GetFile()->SetLoadMode( loadMode ); +} +/** + * \brief Sets the LoadMode of the internal gdcm::File + * @param fileName name of the file to be open + */ +void FileHelper::SetFileName(std::string const &fileName) +{ + FileInternal->SetFileName( fileName ); +} + +/** + * \brief Loader + * @return false if file cannot be open or no swap info was found, + * or no tag was found. + */ +bool FileHelper::Load() +{ + if ( !FileInternal->Load() ) + return false; + + PixelReadConverter->GrabInformationsFromFile( FileInternal ); + return true; +} + +/** + * \brief Accesses an existing DocEntry (i.e. a Dicom Element) + * through it's (group, element) and modifies it's content with + * the given value. + * @param content new value (string) to substitute with + * @param group group number of the Dicom Element to modify + * @param elem element number of the Dicom Element to modify + * \return false if DocEntry not found + */ +bool FileHelper::SetValEntry(std::string const &content, + uint16_t group, uint16_t elem) +{ + return FileInternal->SetValEntry(content, group, elem); +} + + +/** + * \brief Accesses an existing DocEntry (i.e. a Dicom Element) + * through it's (group, element) and modifies it's content with + * the given value. + * @param content new value (void* -> uint8_t*) to substitute with + * @param lgth new value length + * @param group group number of the Dicom Element to modify + * @param elem element number of the Dicom Element to modify + * \return false if DocEntry not found + */ +bool FileHelper::SetBinEntry(uint8_t *content, int lgth, + uint16_t group, uint16_t elem) +{ + return FileInternal->SetBinEntry(content, lgth, group, elem); +} + +/** + * \brief Modifies the value of a given DocEntry (Dicom entry) + * when it exists. Creates it with the given value when unexistant. + * @param content (string)value to be set + * @param group Group number of the Entry + * @param elem Element number of the Entry + * \return pointer to the modified/created Dicom entry (NULL when creation + * failed). + */ +ValEntry *FileHelper::InsertValEntry(std::string const &content, + uint16_t group, uint16_t elem) +{ + return FileInternal->InsertValEntry(content, group, elem); +} + +/** + * \brief Modifies the value of a given DocEntry (Dicom entry) + * when it exists. Creates it with the given value when unexistant. + * A copy of the binArea is made to be kept in the Document. + * @param binArea (binary)value to be set + * @param lgth new value length + * @param group Group number of the Entry + * @param elem Element number of the Entry + * \return pointer to the modified/created Dicom entry (NULL when creation + * failed). + */ +BinEntry *FileHelper::InsertBinEntry(uint8_t *binArea, int lgth, + uint16_t group, uint16_t elem) +{ + return FileInternal->InsertBinEntry(binArea, lgth, group, elem); +} + +/** + * \brief Adds an empty SeqEntry + * (remove any existing entry with same group,elem) + * @param group Group number of the Entry + * @param elem Element number of the Entry + * \return pointer to the created SeqEntry (NULL when creation + * failed). + */ +SeqEntry *FileHelper::InsertSeqEntry(uint16_t group, uint16_t elem) +{ + return FileInternal->InsertSeqEntry(group, elem); +} + +/** + * \brief Get the size of the image data + * If the image can be RGB (with a lut or by default), the size + * corresponds to the RGB image + * (use GetImageDataRawSize if you want to be sure to get *only* + * the size of the pixels) + * @return The image size + */ +size_t FileHelper::GetImageDataSize() +{ + if ( PixelWriteConverter->GetUserData() ) + { + return PixelWriteConverter->GetUserDataSize(); + } + return PixelReadConverter->GetRGBSize(); +} + +/** + * \brief Get the size of the image data. + * If the image could be converted to RGB using a LUT, + * this transformation is not taken into account by GetImageDataRawSize + * (use GetImageDataSize if you wish) + * @return The raw image size + */ +size_t FileHelper::GetImageDataRawSize() +{ + if ( PixelWriteConverter->GetUserData() ) + { + return PixelWriteConverter->GetUserDataSize(); + } + return PixelReadConverter->GetRawSize(); +} + +/** + * \brief brings pixels into memory : + * - Allocates necessary memory, + * - Reads the pixels from disk (uncompress if necessary), + * - Transforms YBR pixels, if any, into RGB pixels, + * - Transforms 3 planes R, G, B, if any, into a single RGB Plane + * - Transforms single Grey plane + 3 Palettes into a RGB Plane + * - Copies the pixel data (image[s]/volume[s]) to newly allocated zone. + * @return Pointer to newly allocated pixel data. + * (uint8_t is just for prototyping. feel free to cast) + * NULL if alloc fails + */ +uint8_t *FileHelper::GetImageData() +{ + if ( PixelWriteConverter->GetUserData() ) + { + return PixelWriteConverter->GetUserData(); + } + + if ( ! GetRaw() ) + { + // If the decompression failed nothing can be done. + return 0; + } + + if ( FileInternal->HasLUT() && PixelReadConverter->BuildRGBImage() ) + { + return PixelReadConverter->GetRGB(); + } + else + { + // When no LUT or LUT conversion fails, return the Raw + return PixelReadConverter->GetRaw(); + } +} + +/** + * \brief brings pixels into memory : + * - Allocates necessary memory, + * - Transforms YBR pixels (if any) into RGB pixels + * - Transforms 3 planes R, G, B (if any) into a single RGB Plane + * - Copies the pixel data (image[s]/volume[s]) to newly allocated zone. + * - DOES NOT transform Grey plane + 3 Palettes into a RGB Plane + * @return Pointer to newly allocated pixel data. + * (uint8_t is just for prototyping. feel free to cast) + * NULL if alloc fails + */ +uint8_t *FileHelper::GetImageDataRaw () +{ + return GetRaw(); +} + +#ifndef GDCM_LEGACY_REMOVE +/* + * \brief Useless function, since PixelReadConverter forces us + * copy the Pixels anyway. + * Reads the pixels from disk (uncompress if necessary), + * Transforms YBR pixels, if any, into RGB pixels + * Transforms 3 planes R, G, B, if any, into a single RGB Plane + * Transforms single Grey plane + 3 Palettes into a RGB Plane + * Copies at most MaxSize bytes of pixel data to caller allocated + * memory space. + * \warning This function allows people that want to build a volume + * from an image stack *not to* have, first to get the image pixels, + * and then move them to the volume area. + * It's absolutely useless for any VTK user since vtk chooses + * to invert the lines of an image, that is the last line comes first + * (for some axis related reasons?). Hence he will have + * to load the image line by line, starting from the end. + * VTK users have to call GetImageData + * + * @param destination Address (in caller's memory space) at which the + * pixel data should be copied + * @param maxSize Maximum number of bytes to be copied. When MaxSize + * is not sufficient to hold the pixel data the copy is not + * executed (i.e. no partial copy). + * @return On success, the number of bytes actually copied. Zero on + * failure e.g. MaxSize is lower than necessary. + */ +size_t FileHelper::GetImageDataIntoVector (void *destination, size_t maxSize) +{ + if ( ! GetRaw() ) + { + // If the decompression failed nothing can be done. + return 0; + } + + if ( FileInternal->HasLUT() && PixelReadConverter->BuildRGBImage() ) + { + if ( PixelReadConverter->GetRGBSize() > maxSize ) + { + gdcmWarningMacro( "Pixel data bigger than caller's expected MaxSize"); + return 0; + } + memcpy( destination, + (void*)PixelReadConverter->GetRGB(), + PixelReadConverter->GetRGBSize() ); + return PixelReadConverter->GetRGBSize(); + } + + // Either no LUT conversion necessary or LUT conversion failed + if ( PixelReadConverter->GetRawSize() > maxSize ) + { + gdcmWarningMacro( "Pixel data bigger than caller's expected MaxSize"); + return 0; + } + memcpy( destination, + (void *)PixelReadConverter->GetRaw(), + PixelReadConverter->GetRawSize() ); + return PixelReadConverter->GetRawSize(); +} +#endif + +/** + * \brief Points the internal pointer to the callers inData + * image representation, BUT WITHOUT COPYING THE DATA. + * 'image' Pixels are presented as C-like 2D arrays : line per line. + * 'volume'Pixels are presented as C-like 3D arrays : plane per plane + * \warning Since the pixels are not copied, it is the caller's responsability + * not to deallocate its data before gdcm uses them (e.g. with + * the Write() method ) + * @param inData user supplied pixel area (uint8_t* is just for the compiler. + * user is allowed to pass any kind of pixelsn since the size is + * given in bytes) + * @param expectedSize total image size, *in Bytes* + */ +void FileHelper::SetImageData(uint8_t *inData, size_t expectedSize) +{ + SetUserData(inData, expectedSize); +} + +/** + * \brief Set the image data defined by the user + * \warning When writting the file, this data are get as default data to write + * @param inData user supplied pixel area (uint8_t* is just for the compiler. + * user is allowed to pass any kind of pixels since the size is + * given in bytes) + * @param expectedSize total image size, *in Bytes* + */ +void FileHelper::SetUserData(uint8_t *inData, size_t expectedSize) +{ + PixelWriteConverter->SetUserData(inData, expectedSize); +} + +/** + * \brief Get the image data defined by the user + * \warning When writting the file, this data are get as default data to write + */ +uint8_t *FileHelper::GetUserData() +{ + return PixelWriteConverter->GetUserData(); +} + +/** + * \brief Get the image data size defined by the user + * \warning When writting the file, this data are get as default data to write + */ +size_t FileHelper::GetUserDataSize() +{ + return PixelWriteConverter->GetUserDataSize(); +} + +/** + * \brief Get the image data from the file. + * If a LUT is found, the data are expanded to be RGB + */ +uint8_t *FileHelper::GetRGBData() +{ + return PixelReadConverter->GetRGB(); +} + +/** + * \brief Get the image data size from the file. + * If a LUT is found, the data are expanded to be RGB + */ +size_t FileHelper::GetRGBDataSize() +{ + return PixelReadConverter->GetRGBSize(); +} + +/** + * \brief Get the image data from the file. + * Even when a LUT is found, the data are not expanded to RGB! + */ +uint8_t *FileHelper::GetRawData() +{ + return PixelReadConverter->GetRaw(); +} + +/** + * \brief Get the image data size from the file. + * Even when a LUT is found, the data are not expanded to RGB! + */ +size_t FileHelper::GetRawDataSize() +{ + return PixelReadConverter->GetRawSize(); +} + +/** + * \brief Access to the underlying \ref PixelReadConverter RGBA LUT + */ +uint8_t* FileHelper::GetLutRGBA() +{ + if ( PixelReadConverter->GetLutRGBA() ==0 ) + PixelReadConverter->BuildLUTRGBA(); + return PixelReadConverter->GetLutRGBA(); +} + +/** + * \brief Access to the underlying \ref PixelReadConverter RGBA LUT Item Number + */ +int FileHelper::GetLutItemNumber() +{ + return PixelReadConverter->GetLutItemNumber(); +} + +/** + * \brief Access to the underlying \ref PixelReadConverter RGBA LUT Item Size + */ +int FileHelper::GetLutItemSize() +{ + return PixelReadConverter->GetLutItemSize(); +} + +/** + * \brief Writes on disk A SINGLE Dicom file + * NO test is performed on processor "Endiannity". + * It's up to the user to call his Reader properly + * @param fileName name of the file to be created + * (any already existing file is over written) + * @return false if write fails + */ +bool FileHelper::WriteRawData(std::string const &fileName) +{ + std::ofstream fp1(fileName.c_str(), std::ios::out | std::ios::binary ); + if (!fp1) + { + gdcmWarningMacro( "Fail to open (write) file:" << fileName.c_str()); + return false; + } + + if ( PixelWriteConverter->GetUserData() ) + { + fp1.write( (char *)PixelWriteConverter->GetUserData(), + PixelWriteConverter->GetUserDataSize() ); + } + else if ( PixelReadConverter->GetRGB() ) + { + fp1.write( (char *)PixelReadConverter->GetRGB(), + PixelReadConverter->GetRGBSize()); + } + else if ( PixelReadConverter->GetRaw() ) + { + fp1.write( (char *)PixelReadConverter->GetRaw(), + PixelReadConverter->GetRawSize()); + } + else + { + gdcmErrorMacro( "Nothing written." ); + } + + fp1.close(); + + return true; +} + +/** + * \brief Writes on disk A SINGLE Dicom file, + * using the Implicit Value Representation convention + * NO test is performed on processor "Endianity". + * @param fileName name of the file to be created + * (any already existing file is overwritten) + * @return false if write fails + */ + +bool FileHelper::WriteDcmImplVR (std::string const &fileName) +{ + SetWriteTypeToDcmImplVR(); + return Write(fileName); +} + +/** +* \brief Writes on disk A SINGLE Dicom file, + * using the Explicit Value Representation convention + * NO test is performed on processor "Endiannity". + * @param fileName name of the file to be created + * (any already existing file is overwritten) + * @return false if write fails + */ + +bool FileHelper::WriteDcmExplVR (std::string const &fileName) +{ + SetWriteTypeToDcmExplVR(); + return Write(fileName); +} + +/** + * \brief Writes on disk A SINGLE Dicom file, + * using the ACR-NEMA convention + * NO test is performed on processor "Endiannity". + * (a l'attention des logiciels cliniques + * qui ne prennent en entr�e QUE des images ACR ... + * \warning if a DICOM_V3 header is supplied, + * groups < 0x0008 and shadow groups are ignored + * \warning NO TEST is performed on processor "Endiannity". + * @param fileName name of the file to be created + * (any already existing file is overwritten) + * @return false if write fails + */ + +bool FileHelper::WriteAcr (std::string const &fileName) +{ + SetWriteTypeToAcr(); + return Write(fileName); +} + +/** + * \brief Writes on disk A SINGLE Dicom file, + * @param fileName name of the file to be created + * (any already existing file is overwritten) + * @return false if write fails + */ +bool FileHelper::Write(std::string const &fileName) +{ + switch(WriteType) + { + case ImplicitVR: + SetWriteFileTypeToImplicitVR(); + break; + case Unknown: // should never happen; ExplicitVR is the default value + case ExplicitVR: + SetWriteFileTypeToExplicitVR(); + break; + case ACR: + case ACR_LIBIDO: + // NOTHING is done here just for LibIDO. + // Just to avoid further trouble if user creates a file ex-nihilo, + // wants to write it as an ACR-NEMA file, + // and forgets to create any Entry belonging to group 0008 + // (shame on him !) + // We add Recognition Code (RET) + if ( ! FileInternal->GetValEntry(0x0008, 0x0010) ) + FileInternal->InsertValEntry("", 0x0008, 0x0010); + SetWriteFileTypeToACR(); + // SetWriteFileTypeToImplicitVR(); // ACR IS implicit VR ! + break; + case JPEG: + SetWriteFileTypeToJPEG(); + break; + } + CheckMandatoryElements(); + + // -------------------------------------------------------------- + // Special Patch to allow gdcm to re-write ACR-LibIDO formated images + // + // if recognition code tells us we dealt with a LibIDO image + // we reproduce on disk the switch between lineNumber and columnNumber + // just before writting ... + /// \todo the best trick would be *change* the recognition code + /// but pb expected if user deals with, e.g. COMPLEX images + + if ( WriteType == ACR_LIBIDO ) + { + SetWriteToLibido(); + } + else + { + SetWriteToNoLibido(); + } + // ----------------- End of Special Patch ---------------- + + switch(WriteMode) + { + case WMODE_RAW : + SetWriteToRaw(); // modifies and pushes to the archive, when necessary + break; + case WMODE_RGB : + SetWriteToRGB(); // modifies and pushes to the archive, when necessary + break; + } + + bool check = CheckWriteIntegrity(); // verifies length + if (WriteType == JPEG ) check = true; + if (check) + { + check = FileInternal->Write(fileName,WriteType); + } + + RestoreWrite(); + RestoreWriteFileType(); + RestoreWriteMandatory(); + + // -------------------------------------------------------------- + // Special Patch to allow gdcm to re-write ACR-LibIDO formated images + // + // ...and we restore the header to be Dicom Compliant again + // just after writting + RestoreWriteOfLibido(); + // ----------------- End of Special Patch ---------------- + + return check; +} + +//----------------------------------------------------------------------------- +// Protected +/** + * \brief Checks the write integrity + * + * The tests made are : + * - verify the size of the image to write with the possible write + * when the user set an image data + * @return true if check is successfull + */ +bool FileHelper::CheckWriteIntegrity() +{ + if ( PixelWriteConverter->GetUserData() ) + { + int numberBitsAllocated = FileInternal->GetBitsAllocated(); + if ( numberBitsAllocated == 0 || numberBitsAllocated == 12 ) + { + gdcmWarningMacro( "numberBitsAllocated changed from " + << numberBitsAllocated << " to 16 " + << " for consistency purpose" ); + numberBitsAllocated = 16; + } + + size_t decSize = FileInternal->GetXSize() + * FileInternal->GetYSize() + * FileInternal->GetZSize() + * FileInternal->GetSamplesPerPixel() + * ( numberBitsAllocated / 8 ); + size_t rgbSize = decSize; + if ( FileInternal->HasLUT() ) + rgbSize = decSize * 3; + + switch(WriteMode) + { + case WMODE_RAW : + if ( decSize!=PixelWriteConverter->GetUserDataSize() ) + { + gdcmWarningMacro( "Data size (Raw) is incorrect. Should be " + << decSize << " / Found :" + << PixelWriteConverter->GetUserDataSize() ); + return false; + } + break; + case WMODE_RGB : + if ( rgbSize!=PixelWriteConverter->GetUserDataSize() ) + { + gdcmWarningMacro( "Data size (RGB) is incorrect. Should be " + << decSize << " / Found " + << PixelWriteConverter->GetUserDataSize() ); + return false; + } + break; + } + } + + return true; +} + +/** + * \brief Updates the File to write RAW data (as opposed to RGB data) + * (modifies, when necessary, photochromatic interpretation, + * bits allocated, Pixels element VR) + */ +void FileHelper::SetWriteToRaw() +{ + if ( FileInternal->GetNumberOfScalarComponents() == 3 + && !FileInternal->HasLUT() ) + { + SetWriteToRGB(); + } + else + { + ValEntry *photInt = CopyValEntry(0x0028,0x0004); + if (FileInternal->HasLUT() ) + { + photInt->SetValue("PALETTE COLOR "); + } + else + { + photInt->SetValue("MONOCHROME2 "); + } + + PixelWriteConverter->SetReadData(PixelReadConverter->GetRaw(), + PixelReadConverter->GetRawSize()); + + std::string vr = "OB"; + if ( FileInternal->GetBitsAllocated()>8 ) + vr = "OW"; + if ( FileInternal->GetBitsAllocated()==24 ) // For RGB ACR files + vr = "OB"; + BinEntry *pixel = + CopyBinEntry(GetFile()->GetGrPixel(),GetFile()->GetNumPixel(),vr); + pixel->SetValue(GDCM_BINLOADED); + pixel->SetBinArea(PixelWriteConverter->GetData(),false); + pixel->SetLength(PixelWriteConverter->GetDataSize()); + + Archive->Push(photInt); + Archive->Push(pixel); + } +} + +/** + * \brief Updates the File to write RGB data (as opposed to RAW data) + * (modifies, when necessary, photochromatic interpretation, + * samples per pixel, Planar configuration, + * bits allocated, bits stored, high bit -ACR 24 bits- + * Pixels element VR, pushes out the LUT, ) + */ +void FileHelper::SetWriteToRGB() +{ + if ( FileInternal->GetNumberOfScalarComponents()==3 ) + { + PixelReadConverter->BuildRGBImage(); + + ValEntry *spp = CopyValEntry(0x0028,0x0002); + spp->SetValue("3 "); + + ValEntry *planConfig = CopyValEntry(0x0028,0x0006); + planConfig->SetValue("0 "); + + ValEntry *photInt = CopyValEntry(0x0028,0x0004); + photInt->SetValue("RGB "); + + if ( PixelReadConverter->GetRGB() ) + { + PixelWriteConverter->SetReadData(PixelReadConverter->GetRGB(), + PixelReadConverter->GetRGBSize()); + } + else // Raw data + { + PixelWriteConverter->SetReadData(PixelReadConverter->GetRaw(), + PixelReadConverter->GetRawSize()); + } + + std::string vr = "OB"; + if ( FileInternal->GetBitsAllocated()>8 ) + vr = "OW"; + if ( FileInternal->GetBitsAllocated()==24 ) // For RGB ACR files + vr = "OB"; + BinEntry *pixel = + CopyBinEntry(GetFile()->GetGrPixel(),GetFile()->GetNumPixel(),vr); + pixel->SetValue(GDCM_BINLOADED); + pixel->SetBinArea(PixelWriteConverter->GetData(),false); + pixel->SetLength(PixelWriteConverter->GetDataSize()); + + Archive->Push(spp); + Archive->Push(planConfig); + Archive->Push(photInt); + Archive->Push(pixel); + + // Remove any LUT + Archive->Push(0x0028,0x1101); + Archive->Push(0x0028,0x1102); + Archive->Push(0x0028,0x1103); + Archive->Push(0x0028,0x1201); + Archive->Push(0x0028,0x1202); + Archive->Push(0x0028,0x1203); + + // push out Palette Color Lookup Table UID, if any + Archive->Push(0x0028,0x1199); + + // For old '24 Bits' ACR-NEMA + // Thus, we have a RGB image and the bits allocated = 24 and + // samples per pixels = 1 (in the read file) + if ( FileInternal->GetBitsAllocated()==24 ) + { + ValEntry *bitsAlloc = CopyValEntry(0x0028,0x0100); + bitsAlloc->SetValue("8 "); + + ValEntry *bitsStored = CopyValEntry(0x0028,0x0101); + bitsStored->SetValue("8 "); + + ValEntry *highBit = CopyValEntry(0x0028,0x0102); + highBit->SetValue("7 "); + + Archive->Push(bitsAlloc); + Archive->Push(bitsStored); + Archive->Push(highBit); + } + } + else + { + SetWriteToRaw(); + } +} + +/** + * \brief Restore the File write mode + */ +void FileHelper::RestoreWrite() +{ + Archive->Restore(0x0028,0x0002); + Archive->Restore(0x0028,0x0004); + Archive->Restore(0x0028,0x0006); + Archive->Restore(GetFile()->GetGrPixel(),GetFile()->GetNumPixel()); + + // For old ACR-NEMA (24 bits problem) + Archive->Restore(0x0028,0x0100); + Archive->Restore(0x0028,0x0101); + Archive->Restore(0x0028,0x0102); + + // For the LUT + Archive->Restore(0x0028,0x1101); + Archive->Restore(0x0028,0x1102); + Archive->Restore(0x0028,0x1103); + Archive->Restore(0x0028,0x1201); + Archive->Restore(0x0028,0x1202); + Archive->Restore(0x0028,0x1203); + + // For the Palette Color Lookup Table UID + Archive->Restore(0x0028,0x1203); + + + // group 0002 may be pushed out for ACR-NEMA writting purposes + Archive->Restore(0x0002,0x0000); + Archive->Restore(0x0002,0x0001); + Archive->Restore(0x0002,0x0002); + Archive->Restore(0x0002,0x0003); + Archive->Restore(0x0002,0x0010); + Archive->Restore(0x0002,0x0012); + Archive->Restore(0x0002,0x0013); + Archive->Restore(0x0002,0x0016); + Archive->Restore(0x0002,0x0100); + Archive->Restore(0x0002,0x0102); +} + +/** + * \brief Pushes out the whole group 0002 + * FIXME : better, set a flag to tell the writer not to write it ... + * FIXME : method should probably have an other name ! + * SetWriteFileTypeToACR is NOT opposed to + * SetWriteFileTypeToExplicitVR and SetWriteFileTypeToImplicitVR + */ +void FileHelper::SetWriteFileTypeToACR() +{ + Archive->Push(0x0002,0x0000); + Archive->Push(0x0002,0x0001); + Archive->Push(0x0002,0x0002); + Archive->Push(0x0002,0x0003); + Archive->Push(0x0002,0x0010); + Archive->Push(0x0002,0x0012); + Archive->Push(0x0002,0x0013); + Archive->Push(0x0002,0x0016); + Archive->Push(0x0002,0x0100); + Archive->Push(0x0002,0x0102); +} + +/** + * \brief Sets in the File the TransferSyntax to 'JPEG' + */ +void FileHelper::SetWriteFileTypeToJPEG() +{ + std::string ts = Util::DicomString( + Global::GetTS()->GetSpecialTransferSyntax(TS::JPEGBaselineProcess1) ); + + ValEntry *tss = CopyValEntry(0x0002,0x0010); + tss->SetValue(ts); + + Archive->Push(tss); +} + +/** + * \brief Sets in the File the TransferSyntax to 'Explicit VR Little Endian" + */ +void FileHelper::SetWriteFileTypeToExplicitVR() +{ + std::string ts = Util::DicomString( + Global::GetTS()->GetSpecialTransferSyntax(TS::ExplicitVRLittleEndian) ); + + ValEntry *tss = CopyValEntry(0x0002,0x0010); + tss->SetValue(ts); + + Archive->Push(tss); +} + +/** + * \brief Sets in the File the TransferSyntax to 'Implicit VR Little Endian" + */ +void FileHelper::SetWriteFileTypeToImplicitVR() +{ + std::string ts = Util::DicomString( + Global::GetTS()->GetSpecialTransferSyntax(TS::ImplicitVRLittleEndian) ); + + ValEntry *tss = CopyValEntry(0x0002,0x0010); + tss->SetValue(ts); + + Archive->Push(tss); +} + + +/** + * \brief Restore in the File the initial group 0002 + */ +void FileHelper::RestoreWriteFileType() +{ +} + +/** + * \brief Set the Write not to Libido format + */ +void FileHelper::SetWriteToLibido() +{ + ValEntry *oldRow = dynamic_cast<ValEntry *> + (FileInternal->GetDocEntry(0x0028, 0x0010)); + ValEntry *oldCol = dynamic_cast<ValEntry *> + (FileInternal->GetDocEntry(0x0028, 0x0011)); + + if ( oldRow && oldCol ) + { + std::string rows, columns; + + ValEntry *newRow=new ValEntry(oldRow->GetDictEntry()); + ValEntry *newCol=new ValEntry(oldCol->GetDictEntry()); + + newRow->Copy(oldCol); + newCol->Copy(oldRow); + + newRow->SetValue(oldCol->GetValue()); + newCol->SetValue(oldRow->GetValue()); + + Archive->Push(newRow); + Archive->Push(newCol); + } + + ValEntry *libidoCode = CopyValEntry(0x0008,0x0010); + libidoCode->SetValue("ACRNEMA_LIBIDO_1.1"); + Archive->Push(libidoCode); +} + +/** + * \brief Set the Write not to No Libido format + */ +void FileHelper::SetWriteToNoLibido() +{ + ValEntry *recCode = dynamic_cast<ValEntry *> + (FileInternal->GetDocEntry(0x0008,0x0010)); + if ( recCode ) + { + if ( recCode->GetValue() == "ACRNEMA_LIBIDO_1.1" ) + { + ValEntry *libidoCode = CopyValEntry(0x0008,0x0010); + libidoCode->SetValue(""); + Archive->Push(libidoCode); + } + } +} + +/** + * \brief Restore the Write format + */ +void FileHelper::RestoreWriteOfLibido() +{ + Archive->Restore(0x0028,0x0010); + Archive->Restore(0x0028,0x0011); + Archive->Restore(0x0008,0x0010); + + // Restore 'LibIDO-special' entries, if any + Archive->Restore(0x0028,0x0015); + Archive->Restore(0x0028,0x0016); + Archive->Restore(0x0028,0x0017); + Archive->Restore(0x0028,0x00199); +} + +/** + * \brief Duplicates a ValEntry or creates it. + * @param group Group number of the Entry + * @param elem Element number of the Entry + * \return pointer to the new Val Entry (NULL when creation failed). + */ +ValEntry *FileHelper::CopyValEntry(uint16_t group, uint16_t elem) +{ + DocEntry *oldE = FileInternal->GetDocEntry(group, elem); + ValEntry *newE; + + if ( oldE ) + { + newE = new ValEntry(oldE->GetDictEntry()); + newE->Copy(oldE); + } + else + { + newE = GetFile()->NewValEntry(group, elem); + } + + return newE; +} + +/** + * \brief Duplicates a BinEntry or creates it. + * @param group Group number of the Entry + * @param elem Element number of the Entry + * @param vr Value Representation of the Entry + * FIXME : what is it used for? + * \return pointer to the new Bin Entry (NULL when creation failed). + */ +BinEntry *FileHelper::CopyBinEntry(uint16_t group, uint16_t elem, + const TagName &vr) +{ + DocEntry *oldE = FileInternal->GetDocEntry(group, elem); + BinEntry *newE; + + if ( oldE && vr != GDCM_UNKNOWN ) + if ( oldE->GetVR() != vr ) + oldE = NULL; + + if ( oldE ) + { + newE = new BinEntry(oldE->GetDictEntry()); + newE->Copy(oldE); + } + else + { + newE = GetFile()->NewBinEntry(group, elem, vr); + } + + return newE; +} + +/** + * \brief This method is called automatically, just before writting + * in order to produce a 'True Dicom V3' image. + * + * We cannot know *how* the user made the File : + * (reading an old ACR-NEMA file or a not very clean DICOM file ...) + * Just before writting : + * - we check the Entries + * - we create the mandatory entries if they are missing + * - we modify the values if necessary + * - we push the sensitive entries to the Archive + * The writing process will restore the entries as they where before + * entering FileHelper::CheckMandatoryElements, so the user will always + * see the entries just as they were before he decided to write. + * + * \note + * - Entries whose type is 1 are mandatory, with a mandatory value + * - Entries whose type is 1c are mandatory-inside-a-Sequence, + * with a mandatory value + * - Entries whose type is 2 are mandatory, with an optional value + * - Entries whose type is 2c are mandatory-inside-a-Sequence, + * with an optional value + * - Entries whose type is 3 are optional + * + * \todo + * - warn the user if we had to add some entries : + * even if a mandatory entry is missing, we add it, with a default value + * (we don't want to give up the writting process if user forgot to + * specify Lena's Patient ID, for instance ...) + * - read the whole PS 3.3 Part of DICOM (890 pages) + * and write a *full* checker (probably one method per Modality ...) + * Any contribution is welcome. + * - write a user callable full checker, to allow post reading + * and/or pre writting image consistency check. + */ + +/* ------------------------------------------------------------------------------------- +To be moved to User's guide / WIKI ? + +We have to deal with 4 *very* different cases : +-1) user created ex nihilo his own image and wants to write it as a Dicom image. +-2) user modified the pixels of an existing image. +-3) user created a new image, using existing images (eg MIP, MPR, cartography image) +-4) user anonymized an image without processing the pixels. + +gdcm::FileHelper::CheckMandatoryElements() deals automatically with these cases. + +1)2)3)4) +0008 0012 Instance Creation Date +0008 0013 Instance Creation Time +0008 0018 SOP Instance UID +are *always* created with the current values; user has *no* possible intervention on +them. + +'Serie Instance UID'(0x0020,0x000e) +'Study Instance UID'(0x0020,0x000d) are kept as is if already exist, + created if it doesn't. + The user is allowed to create his own Series/Studies, + keeping the same 'Serie Instance UID' / 'Study Instance UID' for various images + Warning : + The user shouldn't add any image to a 'Manufacturer Serie' + but there is no way no to allowed him to do that + + None of the 'shadow elements' are droped out. + + +1) +'Modality' (0x0008,0x0060) is defaulted to "OT" (other) if missing. +'Conversion Type (0x0008,0x0064) is forced to 'SYN' (Synthetic Image). +'Study Date', 'Study Time' are defaulted to current Date and Time. + +1)2)3) +'Media Storage SOP Class UID' (0x0002,0x0002) +'SOP Class UID' (0x0008,0x0016) are set to + [Secondary Capture Image Storage] +'Image Type' (0x0008,0x0008) is forced to "DERIVED\PRIMARY" +Conversion Type (0x0008,0x0064) is forced to 'SYN' (Synthetic Image) + +2)4) +If 'SOP Class UID' exists in the native image ('true DICOM' image) + we create the 'Source Image Sequence' SeqEntry (0x0008, 0x2112) + --> 'Referenced SOP Class UID' (0x0008, 0x1150) + whose value is the original 'SOP Class UID' + --> 'Referenced SOP Instance UID' (0x0008, 0x1155) + whose value is the original 'SOP Class UID' + +3) TODO : find a trick to allow user to pass to the writter the list of the Dicom images + or the Series, (or the Study ?) he used to created his image + (MIP, MPR, cartography image, ...) + These info should be stored (?) + 0008 1110 SQ 1 Referenced Study Sequence + 0008 1115 SQ 1 Referenced Series Sequence + 0008 1140 SQ 1 Referenced Image Sequence + +4) When user *knows* he didn't modified the pixels, he may ask the writer to keep some +informations unchanged : +'Media Storage SOP Class UID' (0x0002,0x0002) +'SOP Class UID' (0x0008,0x0016) +'Image Type' (0x0008,0x0008) +'Conversion Type' (0x0008,0x0064) +He has to use gdcm::FileHelper::SetKeepMediaStorageSOPClassUID(true) +(probabely name has to be changed) + + +Bellow follows the full description (hope so !) of the consistency checks performed +by gdcm::FileHelper::CheckMandatoryElements() + + +-->'Media Storage SOP Class UID' (0x0002,0x0002) +-->'SOP Class UID' (0x0008,0x0016) are set to + [Secondary Capture Image Storage] + (Potentialy, the image was modified by user, and post-processed; + it's no longer a 'native' image) + Except if user told he wants to keep MediaStorageSOPClassUID, + when *he* knows he didn't modify the image (e.g. : he just anonymized the file) + +--> 'Image Type' (0x0008,0x0008) + is forced to "DERIVED\PRIMARY" + (The written image is no longer an 'ORIGINAL' one) + Except if user told he wants to keep MediaStorageSOPClassUID, + when *he* knows he didn't modify the image (e.g. : he just anonymized the file) + + --> Conversion Type (0x0008,0x0064) + is forced to 'SYN' (Synthetic Image) + Except if user told he wants to keep MediaStorageSOPClassUID, + when *he* knows he didn't modify the image (e.g. : he just anonymized the file) + +--> 'Modality' (0x0008,0x0060) + is defaulted to "OT" (other) if missing. + (a fully user created image belongs to *no* modality) + +--> 'Media Storage SOP Instance UID' (0x0002,0x0003) +--> 'Implementation Class UID' (0x0002,0x0012) + are automatically generated; no user intervention possible + +--> 'Serie Instance UID'(0x0020,0x000e) +--> 'Study Instance UID'(0x0020,0x000d) are kept as is if already exist + created if it doesn't. + The user is allowed to create his own Series/Studies, + keeping the same 'Serie Instance UID' / 'Study Instance UID' + for various images + Warning : + The user shouldn't add any image to a 'Manufacturer Serie' + but there is no way no to allowed him to do that + +--> If 'SOP Class UID' exists in the native image ('true DICOM' image) + we create the 'Source Image Sequence' SeqEntry (0x0008, 0x2112) + + --> 'Referenced SOP Class UID' (0x0008, 0x1150) + whose value is the original 'SOP Class UID' + --> 'Referenced SOP Instance UID' (0x0008, 0x1155) + whose value is the original 'SOP Class UID' + +--> Bits Stored, Bits Allocated, Hight Bit Position are checked for consistency +--> Pixel Spacing (0x0028,0x0030) is defaulted to "1.0\1.0" +--> Samples Per Pixel (0x0028,0x0002) is defaulted to 1 (grayscale) + +--> Imager Pixel Spacing (0x0018,0x1164) : defaulted to Pixel Spacing value + +--> Instance Creation Date, Instance Creation Time are forced to current Date and Time + +--> Study Date, Study Time are defaulted to current Date and Time + (they remain unchanged if they exist) + +--> Patient Orientation : (0x0020,0x0020), if not present, is deduced from + Image Orientation (Patient) : (0020|0037) or from + Image Orientation (RET) : (0020 0035) + +--> Study ID, Series Number, Instance Number, Patient Orientation (Type 2) + are created, with empty value if there are missing. + +--> Manufacturer, Institution Name, Patient's Name, (Type 2) + are defaulted with a 'gdcm' value. + +--> Patient ID, Patient's Birth Date, Patient's Sex, (Type 2) +--> Referring Physician's Name (Type 2) + are created, with empty value if there are missing. + + -------------------------------------------------------------------------------------*/ + +void FileHelper::CheckMandatoryElements() +{ + std::string sop = Util::CreateUniqueUID(); + + // just to remember : 'official' 0002 group + if ( WriteType != ACR && WriteType != ACR_LIBIDO ) + { + // Group 000002 (Meta Elements) already pushed out + + //0002 0000 UL 1 Meta Group Length + //0002 0001 OB 1 File Meta Information Version + //0002 0002 UI 1 Media Stored SOP Class UID + //0002 0003 UI 1 Media Stored SOP Instance UID + //0002 0010 UI 1 Transfer Syntax UID + //0002 0012 UI 1 Implementation Class UID + //0002 0013 SH 1 Implementation Version Name + //0002 0016 AE 1 Source Application Entity Title + //0002 0100 UI 1 Private Information Creator + //0002 0102 OB 1 Private Information + + // Create them if not found + // Always modify the value + // Push the entries to the archive. + CopyMandatoryEntry(0x0002,0x0000,"0"); + + BinEntry *e_0002_0001 = CopyBinEntry(0x0002,0x0001, "OB"); + e_0002_0001->SetBinArea((uint8_t*)Util::GetFileMetaInformationVersion(), + false); + e_0002_0001->SetLength(2); + Archive->Push(e_0002_0001); + + // 'Media Storage SOP Class UID' --> [Secondary Capture Image Storage] + // Only if not specified by user, to let people create DERIVED images + ValEntry *e_0002_0002 = FileInternal->GetValEntry(0x0002, 0x0002); + if( !e_0002_0002) + { + CopyMandatoryEntry(0x0002,0x0002,"1.2.840.10008.5.1.4.1.1.7"); + } + + // 'Media Storage SOP Instance UID' + // CopyMandatoryEntry(0x0002,0x0003,sop); + + // 'Implementation Class UID' + CopyMandatoryEntry(0x0002,0x0012,Util::CreateUniqueUID()); + + // 'Implementation Version Name' + std::string version = "GDCM "; + version += Util::GetVersion(); + CopyMandatoryEntry(0x0002,0x0013,version); + } + + // Push out 'LibIDO-special' entries, if any + Archive->Push(0x0028,0x0015); + Archive->Push(0x0028,0x0016); + Archive->Push(0x0028,0x0017); + Archive->Push(0x0028,0x00199); + + // Deal with the pb of (Bits Stored = 12) + // - we're gonna write the image as Bits Stored = 16 + if ( FileInternal->GetEntryValue(0x0028,0x0100) == "12") + { + CopyMandatoryEntry(0x0028,0x0100,"16"); + } + + // Check if user wasn't drunk ;-) + + itksys_ios::ostringstream s; + // check 'Bits Allocated' vs decent values + int nbBitsAllocated = FileInternal->GetBitsAllocated(); + if ( nbBitsAllocated == 0 || nbBitsAllocated > 32) + { + CopyMandatoryEntry(0x0028,0x0100,"16"); + gdcmWarningMacro("(0028,0100) changed from " + << nbBitsAllocated << " to 16 for consistency purpose"); + nbBitsAllocated = 16; + } + // check 'Bits Stored' vs 'Bits Allocated' + int nbBitsStored = FileInternal->GetBitsStored(); + if ( nbBitsStored == 0 || nbBitsStored > nbBitsAllocated ) + { + s.str(""); + s << nbBitsAllocated; + CopyMandatoryEntry(0x0028,0x0101,s.str()); + gdcmWarningMacro("(0028,0101) changed from " + << nbBitsStored << " to " << nbBitsAllocated + << " for consistency purpose" ); + nbBitsStored = nbBitsAllocated; + } + // check 'Hight Bit Position' vs 'Bits Allocated' and 'Bits Stored' + int highBitPosition = FileInternal->GetHighBitPosition(); + if ( highBitPosition == 0 || + highBitPosition > nbBitsAllocated-1 || + highBitPosition < nbBitsStored-1 ) + { + s.str(""); + s << nbBitsStored - 1; + CopyMandatoryEntry(0x0028,0x0102,s.str()); + gdcmWarningMacro("(0028,0102) changed from " + << highBitPosition << " to " << nbBitsAllocated-1 + << " for consistency purpose"); + } + + std::string pixelSpacing = FileInternal->GetEntryValue(0x0028,0x0030); + if ( pixelSpacing == GDCM_UNFOUND ) + { + pixelSpacing = "1.0\\1.0"; + // if missing, Pixel Spacing forced to "1.0\1.0" + CopyMandatoryEntry(0x0028,0x0030,pixelSpacing); + } + std::string imageOrientationPatient = FileInternal->GetEntryValue(0x0020,0x0037); + if ( imageOrientationPatient == GDCM_UNFOUND ) + { + imageOrientationPatient = "1\\0\\0\\0\\1\\0"; + CopyMandatoryEntry(0x0020,0x0037,imageOrientationPatient); + } + + // 'Imager Pixel Spacing' : defaulted to 'Pixel Spacing' + // --> This one is the *legal* one ! + // FIXME : we should write it only when we are *sure* the image comes from + // an imager (see also 0008,0x0064) + CheckMandatoryEntry(0x0018,0x1164,pixelSpacing); + + // Samples Per Pixel (type 1) : default to grayscale + CheckMandatoryEntry(0x0028,0x0002,"1"); + + // --- Check UID-related Entries --- + + // If 'SOP Class UID' exists ('true DICOM' image) + // we create the 'Source Image Sequence' SeqEntry + // to hold informations about the Source Image + + ValEntry *e_0008_0016 = FileInternal->GetValEntry(0x0008, 0x0016); + if ( e_0008_0016 ) + { + // Create 'Source Image Sequence' SeqEntry + SeqEntry *sis = new SeqEntry ( + Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0008, 0x2112) ); + SQItem *sqi = new SQItem(1); + // (we assume 'SOP Instance UID' exists too) + // create 'Referenced SOP Class UID' + ValEntry *e_0008_1150 = new ValEntry( + Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0008, 0x1150) ); + e_0008_1150->SetValue( e_0008_0016->GetValue()); + sqi->AddEntry(e_0008_1150); + + // create 'Referenced SOP Instance UID' + ValEntry *e_0008_0018 = FileInternal->GetValEntry(0x0008, 0x0018); + ValEntry *e_0008_1155 = new ValEntry( + Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0008, 0x1155) ); + e_0008_1155->SetValue( e_0008_0018->GetValue()); + sqi->AddEntry(e_0008_1155); + + sis->AddSQItem(sqi,1); + // temporarily replaces any previous 'Source Image Sequence' + Archive->Push(sis); + + // 'Image Type' (The written image is no longer an 'ORIGINAL' one) + CopyMandatoryEntry(0x0008,0x0008,"DERIVED\\PRIMARY"); + } + else + { + // There was no 'SOP Class UID'. + // the source image was NOT a true Dicom one. + // We consider the image is a 'Secondary Capture' one + // SOP Class UID + e_0008_0016 = new ValEntry( + Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0008, 0x0016) ); + // [Secondary Capture Image Storage] + e_0008_0016 ->SetValue("1.2.840.10008.5.1.4.1.1.7"); + Archive->Push(e_0008_0016); + } + + // ---- The user will never have to take any action on the following ---- + + // new value for 'SOP Instance UID' + //ValEntry *e_0008_0018 = new ValEntry( + // Global::GetDicts()->GetDefaultPubDict()->GetEntry(0x0008, 0x0018) ); + //e_0008_0018->SetValue( Util::CreateUniqueUID() ); + //Archive->Push(e_0008_0018); + + // Instance Creation Date + const std::string &date = Util::GetCurrentDate(); + CopyMandatoryEntry(0x0008,0x0012,date); + + // Instance Creation Time + const std::string &time = Util::GetCurrentTime(); + CopyMandatoryEntry(0x0008,0x0013,time); + + // Study Date + CheckMandatoryEntry(0x0008,0x0020,date); + // Study Time + CheckMandatoryEntry(0x0008,0x0030,time); + + // Accession Number + //CopyMandatoryEntry(0x0008,0x0050,""); + CheckMandatoryEntry(0x0008,0x0050,""); + + + // ----- Add Mandatory Entries if missing --- + // Entries whose type is 1 are mandatory, with a mandatory value + // Entries whose type is 1c are mandatory-inside-a-Sequence, + // with a mandatory value + // Entries whose type is 2 are mandatory, with an optional value + // Entries whose type is 2c are mandatory-inside-a-Sequence, + // with an optional value + // Entries whose type is 3 are optional + + // 'Study Instance UID' + // Keep the value if exists + // The user is allowed to create his own Study, + // keeping the same 'Study Instance UID' for various images + // The user may add images to a 'Manufacturer Study', + // adding new Series to an already existing Study + CheckMandatoryEntry(0x0020,0x000d,Util::CreateUniqueUID()); + + // 'Serie Instance UID' + // Keep the value if exists + // The user is allowed to create his own Series, + // keeping the same 'Serie Instance UID' for various images + // The user shouldn't add any image to a 'Manufacturer Serie' + // but there is no way no to prevent him for doing that + CheckMandatoryEntry(0x0020,0x000e,Util::CreateUniqueUID()); + + // Study ID + CheckMandatoryEntry(0x0020,0x0010,""); + + // Series Number + CheckMandatoryEntry(0x0020,0x0011,""); + + // Instance Number + CheckMandatoryEntry(0x0020,0x0013,""); + + // Patient Orientation + // Can be computed from (0020|0037) : Image Orientation (Patient) + gdcm::Orientation o; + std::string ori = o.GetOrientation ( FileInternal ); + if (ori != "\\" && ori != GDCM_UNFOUND) + CheckMandatoryEntry(0x0020,0x0020,ori); + else + CheckMandatoryEntry(0x0020,0x0020,""); + + // Modality : if missing we set it to 'OTher' + CheckMandatoryEntry(0x0008,0x0060,"OT"); + + // Manufacturer : if missing we set it to 'GDCM Factory' + CheckMandatoryEntry(0x0008,0x0070,"GDCM Factory"); + + // Institution Name : if missing we set it to 'GDCM Hospital' + CheckMandatoryEntry(0x0008,0x0080,"GDCM Hospital"); + + // Patient's Name : if missing, we set it to 'GDCM^Patient' + CheckMandatoryEntry(0x0010,0x0010,"GDCM^Patient"); + + // Patient ID + CheckMandatoryEntry(0x0010,0x0020,""); + + // Patient's Birth Date : 'type 2' entry -> must exist, value not mandatory + CheckMandatoryEntry(0x0010,0x0030,""); + + // Patient's Sex :'type 2' entry -> must exist, value not mandatory + CheckMandatoryEntry(0x0010,0x0040,""); + + // Referring Physician's Name :'type 2' entry -> must exist, value not mandatory + CheckMandatoryEntry(0x0008,0x0090,""); + +} + +void FileHelper::CheckMandatoryEntry(uint16_t group,uint16_t elem,std::string value) +{ + ValEntry *ve = FileInternal->GetValEntry(group, elem); + if ( !ve) + { + ve = new ValEntry( + Global::GetDicts()->GetDefaultPubDict()->GetEntry(group, elem) ); + ve->SetValue( value ); + Archive->Push(ve); + } +} + +void FileHelper::CopyMandatoryEntry(uint16_t group,uint16_t elem,std::string value) +{ + ValEntry *entry = CopyValEntry(group,elem); + entry->SetValue(value); + Archive->Push(entry); +} + +/** + * \brief Restore in the File the initial group 0002 + */ +void FileHelper::RestoreWriteMandatory() +{ + // group 0002 may be pushed out for ACR-NEMA writting purposes + Archive->Restore(0x0002,0x0000); + Archive->Restore(0x0002,0x0001); + Archive->Restore(0x0002,0x0002); + Archive->Restore(0x0002,0x0003); + Archive->Restore(0x0002,0x0010); + Archive->Restore(0x0002,0x0012); + Archive->Restore(0x0002,0x0013); + Archive->Restore(0x0002,0x0016); + Archive->Restore(0x0002,0x0100); + Archive->Restore(0x0002,0x0102); + + Archive->Restore(0x0008,0x0012); + Archive->Restore(0x0008,0x0013); + Archive->Restore(0x0008,0x0016); + Archive->Restore(0x0008,0x0018); + Archive->Restore(0x0008,0x0060); + Archive->Restore(0x0008,0x0070); + Archive->Restore(0x0008,0x0080); + Archive->Restore(0x0008,0x0090); + Archive->Restore(0x0008,0x2112); + + Archive->Restore(0x0010,0x0010); + Archive->Restore(0x0010,0x0030); + Archive->Restore(0x0010,0x0040); + + Archive->Restore(0x0020,0x000d); + Archive->Restore(0x0020,0x000e); + +} + +//----------------------------------------------------------------------------- +// Private +/** + * \brief Factorization for various forms of constructors. + */ +void FileHelper::Initialize() +{ + UserFunction = 0; + KeepMediaStorageSOPClassUID = false; + + WriteMode = WMODE_RAW; + WriteType = ExplicitVR; + + PixelReadConverter = new PixelReadConvert; + PixelWriteConverter = new PixelWriteConvert; + Archive = new DocEntryArchive( FileInternal ); +} + +/** + * \brief Reads/[decompresses] the pixels, + * *without* making RGB from Palette Colors + * @return the pixels area, whatever its type + * (uint8_t is just for prototyping : feel free to Cast it) + */ +uint8_t *FileHelper::GetRaw() +{ + PixelReadConverter->SetUserFunction( UserFunction ); + + uint8_t *raw = PixelReadConverter->GetRaw(); + if ( ! raw ) + { + // The Raw image migth not be loaded yet: + std::ifstream *fp = FileInternal->OpenFile(); + PixelReadConverter->ReadAndDecompressPixelData( fp ); + if ( fp ) + FileInternal->CloseFile(); + + raw = PixelReadConverter->GetRaw(); + if ( ! raw ) + { + gdcmWarningMacro( "Read/decompress of pixel data apparently went wrong."); + return 0; + } + } + return raw; +} + +//----------------------------------------------------------------------------- +/** + * \brief Prints the common part of ValEntry, BinEntry, SeqEntry + * @param os ostream we want to print in + * @param indent (unused) + */ +void FileHelper::Print(std::ostream &os, std::string const &) +{ + FileInternal->SetPrintLevel(PrintLevel); + FileInternal->Print(os); + + if ( FileInternal->IsReadable() ) + { + PixelReadConverter->SetPrintLevel(PrintLevel); + PixelReadConverter->Print(os); + } +} + +//----------------------------------------------------------------------------- +} // end namespace gdcm diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmFileHelper.h b/Utilities/ITK/Utilities/gdcm/src/gdcmFileHelper.h new file mode 100644 index 0000000000000000000000000000000000000000..be8cd180f0d8c815ac092bbeb75fa6008b56022e --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmFileHelper.h @@ -0,0 +1,234 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmFileHelper.h,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:39 $ + Version: $Revision: 1.4 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#ifndef GDCMFILEHELPER_H +#define GDCMFILEHELPER_H + +#include "gdcmDebug.h" +#include "gdcmBase.h" + + + +namespace gdcm +{ +class File; +class ValEntry; +class BinEntry; +class SeqEntry; +class PixelReadConvert; +class PixelWriteConvert; +class DocEntryArchive; + +typedef void (*VOID_FUNCTION_PUINT8_PFILE_POINTER)(uint8_t *, File *); + +//----------------------------------------------------------------------------- +/** + * \brief In addition to Dicom header exploration, this class is designed + * for accessing the image/volume content. One can also use it to + * write Dicom/ACR-NEMA/RAW files. + */ +class GDCM_EXPORT FileHelper : public Base +{ +public: + enum FileMode + { + WMODE_RAW, + WMODE_RGB + }; + +public: + FileHelper( ); + FileHelper( File *header ); + GDCM_LEGACY(FileHelper( std::string const &filename )); + + virtual ~FileHelper(); + + void Print(std::ostream &os = std::cout, std::string const &indent = ""); + + /// Accessor to \ref File + File *GetFile() { return FileInternal; } + + + void SetLoadMode(int loadMode); + void SetFileName(std::string const &fileName); + bool Load(); + /// to allow user to modify pixel order (e.g. Mirror, TopDown,...) + void SetUserFunction( VOID_FUNCTION_PUINT8_PFILE_POINTER userFunc ) + { UserFunction = userFunc; } + // File methods + bool SetValEntry(std::string const &content, + uint16_t group, uint16_t elem); + bool SetBinEntry(uint8_t *content, int lgth, + uint16_t group, uint16_t elem); + + ValEntry *InsertValEntry(std::string const &content, + uint16_t group, uint16_t elem); + BinEntry *InsertBinEntry(uint8_t *binArea, int lgth, + uint16_t group, uint16_t elem); + SeqEntry *InsertSeqEntry(uint16_t group, uint16_t elem); + + // File helpers + size_t GetImageDataSize(); + size_t GetImageDataRawSize(); + + uint8_t *GetImageData(); + uint8_t *GetImageDataRaw(); + + GDCM_LEGACY(size_t GetImageDataIntoVector(void *destination,size_t maxSize)); + + void SetImageData(uint8_t *data, size_t expectedSize); + + // User data + void SetUserData(uint8_t *data, size_t expectedSize); + uint8_t *GetUserData(); + size_t GetUserDataSize(); + // RBG data (from file) + uint8_t *GetRGBData(); + size_t GetRGBDataSize(); + // RAW data (from file) + uint8_t *GetRawData(); + size_t GetRawDataSize(); + + // LUT + uint8_t* GetLutRGBA(); + int GetLutItemNumber(); + int GetLutItemSize(); + + // Write mode + + /// \brief Tells the writer we want to keep 'Grey pixels + Palettes color' + /// when possible (as opposed to convert 'Palettes color' to RGB) + void SetWriteModeToRaw() { SetWriteMode(WMODE_RAW); } + /// \brief Tells the writer we want to write RGB image when possible + /// (as opposed to 'Grey pixels + Palettes color') + void SetWriteModeToRGB() { SetWriteMode(WMODE_RGB); } + /// \brief Sets the Write Mode ( ) + void SetWriteMode(FileMode mode) { WriteMode = mode; } + /// \brief Gets the Write Mode ( ) + FileMode GetWriteMode() { return WriteMode; } + + // Write format + + /// \brief Tells the writer we want to write as Implicit VR + void SetWriteTypeToDcmImplVR() { SetWriteType(ImplicitVR); } + /// \brief Tells the writer we want to write as Explicit VR + void SetWriteTypeToDcmExplVR() { SetWriteType(ExplicitVR); } + /// \brief Tells the writer we want to write as ACR-NEMA + void SetWriteTypeToAcr() { SetWriteType(ACR); } + /// \brief Tells the writer we want to write as LibIDO + void SetWriteTypeToAcrLibido() { SetWriteType(ACR_LIBIDO); } + /// \brief Tells the writer we want to write as JPEG + void SetWriteTypeToJPEG() { SetWriteType(JPEG); } + /// \brief Tells the writer which format we want to write + /// (ImplicitVR, ExplicitVR, ACR, ACR_LIBIDO) + void SetWriteType(FileType format) { WriteType = format; } + /// \brief Gets the format we talled the write we wanted to write + /// (ImplicitVR, ExplicitVR, ACR, ACR_LIBIDO) + FileType GetWriteType() { return WriteType; } + + // Write pixels of ONE image on hard drive + // No test is made on processor "endianness" + // The user must call his reader correctly + bool WriteRawData (std::string const &fileName); + bool WriteDcmImplVR(std::string const &fileName); + bool WriteDcmExplVR(std::string const &fileName); + bool WriteAcr (std::string const &fileName); + bool Write (std::string const &fileName); + /// \brief if user knows he didn't modify the pixels (e.g. he just anonymized + /// the file), he is allowed to ask to keep the original + /// 'Media Storage SOP Class UID' and 'Image Type' + void SetKeepMediaStorageSOPClassUID (bool v) + { KeepMediaStorageSOPClassUID = v; } + // no GetKeepMediaStorageSOPClassUID() method, on purpose! + +protected: + bool CheckWriteIntegrity(); + + void SetWriteToRaw(); + void SetWriteToRGB(); + void RestoreWrite(); + + void SetWriteFileTypeToACR(); + void SetWriteFileTypeToJPEG(); + void SetWriteFileTypeToExplicitVR(); + void SetWriteFileTypeToImplicitVR(); + void RestoreWriteFileType(); + + void SetWriteToLibido(); + void SetWriteToNoLibido(); + void RestoreWriteOfLibido(); + + ValEntry *CopyValEntry(uint16_t group, uint16_t elem); + BinEntry *CopyBinEntry(uint16_t group, uint16_t elem, + const std::string &vr); + void CheckMandatoryElements(); + void CheckMandatoryEntry(uint16_t group, uint16_t elem,std::string value); + void CopyMandatoryEntry(uint16_t group, uint16_t elem,std::string value); + void RestoreWriteMandatory(); + +private: + void Initialize(); + + uint8_t *GetRaw(); + +// members variables: + /// gdcm::File to use to load the file + File *FileInternal; + + /// \brief Whether the underlying \ref gdcm::File was loaded by + /// the constructor or passed to the constructor. + /// When false the destructor is in charge of deletion. + bool SelfHeader; + + /// Whether already parsed or not + bool Parsed; + + // Utility pixel converter + /// \brief Pointer to the PixelReadConverter + PixelReadConvert *PixelReadConverter; + /// \brief Pointer to the PixelWriteConverter + PixelWriteConvert *PixelWriteConverter; + + // Utility header archive + /// \brief Pointer to the DocEntryArchive (used while writting process) + DocEntryArchive *Archive; + + // Write variables + /// \brief (WMODE_RAW, WMODE_RGB) + FileMode WriteMode; + + /// \brief (ImplicitVR, ExplicitVR, ACR, ACR_LIBIDO) + FileType WriteType; + + /// \brief Pointer to a user supplied function to allow modification of pixel order + /// (i.e. : Mirror, TopDown, 90�Rotation, ...) + /// use as : void userSuppliedFunction(uint8_t *im, gdcm::File *f) + /// NB : the "uint8_t *" type of first param is just for prototyping. + /// User will Cast it according what he founds with f->GetPixelType() + /// See vtkgdcmSerieViewer for an example + VOID_FUNCTION_PUINT8_PFILE_POINTER UserFunction; + + /// \brief if user knows he didn't modify the pixels (e.g. he just + /// anonymized the file), he is allowed to ask to keep the original + /// 'Media Storage SOP Class UID' and 'Image Type' + bool KeepMediaStorageSOPClassUID; +}; +} // end namespace gdcm + +//----------------------------------------------------------------------------- +#endif diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmGlobal.cxx b/Utilities/ITK/Utilities/gdcm/src/gdcmGlobal.cxx new file mode 100644 index 0000000000000000000000000000000000000000..b477c458e9035f33ea54585b85f9ebad083f9a30 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmGlobal.cxx @@ -0,0 +1,141 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmGlobal.cxx,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:39 $ + Version: $Revision: 1.5 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#include "gdcmGlobal.h" + +#include "gdcmDebug.h" +#include "gdcmVR.h" +#include "gdcmTS.h" +#include "gdcmDictGroupName.h" +#include "gdcmDictSet.h" +#include "gdcmDicomDirElement.h" + +namespace gdcm +{ +//----------------------------------------------------------------------------- +/// \brief Those global string that are returned by reference everywhere in +/// gdcm code used to be in gdcmCommon.h but due to a 'bug' in gcc/MacOSX +/// you cannot have static initialization in a multithreaded environment +/// since there is a lazy construction everything got skrew up somehow +/// Therefore the actual initialization is done in a cxx file (avoid +/// duplicated symbol), and an extern is used in gdcmCommon.h + +const std::string GDCM_UNKNOWN = "gdcm::Unknown"; +const std::string GDCM_UNFOUND = "gdcm::Unfound"; +const std::string GDCM_BINLOADED = "gdcm::Binary data loaded"; +const std::string GDCM_NOTLOADED = "gdcm::NotLoaded"; +const std::string GDCM_UNREAD = "gdcm::UnRead"; +const std::string GDCM_NOTASCII = "gdcm::NotAscii"; +const std::string GDCM_PIXELDATA = "gdcm::Pixel Data to be loaded"; +//----------------------------------------------------------------------------- +DictSet *Global::Dicts = (DictSet *)0; +VR *Global::ValRes = (VR *)0; +TS *Global::TranSyn = (TS *)0; +DictGroupName *Global::GroupName = (DictGroupName *)0; +DicomDirElement *Global::ddElem = (DicomDirElement *)0; + +//----------------------------------------------------------------------------- +/** + * \brief Global container + */ +Global Glob; + +//------------------------------------------------------------------------- +// Constructor / Destructor +/** + * \brief constructor : populates the various H Tables + */ +Global::Global() +{ + if (ValRes || TranSyn || Dicts || ddElem) + { + gdcmWarningMacro( "VR or TS or Dicts already allocated"); + return; + } + Dicts = new DictSet(); + ValRes = new VR(); + TranSyn = new TS(); + GroupName = new DictGroupName(); + ddElem = new DicomDirElement(); +} + +/** + * \brief canonical destructor + */ +Global::~Global() +{ + delete Dicts; + delete ValRes; + delete TranSyn; + delete GroupName; + delete ddElem; +} + +//----------------------------------------------------------------------------- +// Public +/** + * \brief returns a pointer to Dictionaries Table + */ +DictSet *Global::GetDicts() +{ + return Dicts; +} + +/** + * \brief returns a pointer to the 'Value Representation Table' + */ +VR *Global::GetVR() +{ + return ValRes; +} + +/** + * \brief returns a pointer to the 'Transfer Syntax Table' + */ +TS *Global::GetTS() +{ + return TranSyn; +} + +/** + * \brief returns a pointer to the Group name correspondance table + */ +DictGroupName *Global::GetDictGroupName() +{ + return GroupName; +} + +/** + * \brief returns a pointer to the DicomDir related elements Table + */ +DicomDirElement *Global::GetDicomDirElements() +{ + return ddElem; +} + +//----------------------------------------------------------------------------- +// Protected + +//----------------------------------------------------------------------------- +// Private + +//----------------------------------------------------------------------------- +// Print + +//----------------------------------------------------------------------------- +} // end namespace gdcm diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmGlobal.h b/Utilities/ITK/Utilities/gdcm/src/gdcmGlobal.h new file mode 100644 index 0000000000000000000000000000000000000000..addcc9540c6e63f77136221cca3308f7ee8311ae --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmGlobal.h @@ -0,0 +1,66 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmGlobal.h,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:39 $ + Version: $Revision: 1.4 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#ifndef GDCMGLOBAL_H +#define GDCMGLOBAL_H + +#include "gdcmCommon.h" + +namespace gdcm +{ +class DictSet; +class VR; +class TS; +class DictGroupName; +class DicomDirElement; +//----------------------------------------------------------------------------- +/** + * \brief This class contains all globals elements that might be + * instanciated only once (singletons). + */ +class GDCM_EXPORT Global +{ +public: + Global(); + ~Global(); + + static DictSet *GetDicts(); + static VR *GetVR(); + static TS *GetTS(); + static DictGroupName *GetDictGroupName(); + static DicomDirElement *GetDicomDirElements(); + +private: + /// Pointer to a container, holding _all_ the Dicom Dictionaries. + static DictSet *Dicts; + /// Pointer to a hash table containing the 'Value Representations'. + static VR *ValRes; + /// \brief Pointer to a hash table containing the Transfer Syntax codes + /// and their english description + static TS *TranSyn; + /// \brief Pointer to a hash table containing the Group codes + /// and their english name (from NIH) + static DictGroupName *GroupName; + /// \brief Pointer to the hash table containing the Dicom Elements necessary + /// to describe each part of a DICOMDIR + static DicomDirElement *ddElem; +}; +} // end namespace gdcm + +//----------------------------------------------------------------------------- +#endif diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmJPEGFragment.cxx b/Utilities/ITK/Utilities/gdcm/src/gdcmJPEGFragment.cxx new file mode 100644 index 0000000000000000000000000000000000000000..502f8554ca7a2f21f001b4b7d732ff1a53de2f2b --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmJPEGFragment.cxx @@ -0,0 +1,112 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmJPEGFragment.cxx,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:39 $ + Version: $Revision: 1.4 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#include "gdcmJPEGFragment.h" +#include "gdcmDebug.h" + +namespace gdcm +{ +//------------------------------------------------------------------------- +// For JPEG 2000, body in file gdcmJpeg2000.cxx +// Not yet made +bool gdcm_read_JPEG2000_file (std::ifstream *fp, void *image_buffer); + +// For JPEG-LS, body in file gdcmJpegLS.cxx +// Not yet made +bool gdcm_read_JPEGLS_file (std::ifstream *fp, void *image_buffer); + +//------------------------------------------------------------------------- +// Constructor / Destructor +/** + * \brief Default constructor. + */ +JPEGFragment::JPEGFragment() +{ + Offset = 0; + Length = 0; + + pImage = 0; + +} + +//----------------------------------------------------------------------------- +// Public +/** + * \brief Decompress 8bits JPEG Fragment + * @param fp ifstream to write to + * @param buffer output (data decompress) + * @param nBits 8/12 or 16 bits jpeg + * @param statesuspension state suspension + */ +void JPEGFragment::DecompressJPEGFramesFromFile(std::ifstream *fp, + uint8_t *buffer, int nBits, + int &statesuspension) +{ + // First thing need to reset file to proper position: + fp->seekg( Offset, std::ios::beg); + + if ( nBits == 8 ) + { + // JPEG Lossy : call to IJG 6b - 8 bits + ReadJPEGFile8( fp, buffer, statesuspension); + } + else if ( nBits <= 12 ) + { + // JPEG Lossy : call to IJG 6b - 12 bits + ReadJPEGFile12 ( fp, buffer, statesuspension); + } + else if ( nBits <= 16 ) + { + // JPEG Lossy : call to IJG 6b - 16 bits + ReadJPEGFile16 ( fp, buffer, statesuspension); + //gdcmAssertMacro( IsJPEGLossless ); + } + else + { + // FIXME : only the bits number is checked, + // NOT the compression method + + // other JPEG lossy not supported + gdcmErrorMacro( "Unknown jpeg lossy compression "); + } +} + +//----------------------------------------------------------------------------- +// Protected + +//----------------------------------------------------------------------------- +// Private + +//----------------------------------------------------------------------------- +// Print +/** + * \brief Print self. + * @param os Stream to print to. + * @param indent Indentation string to be prepended during printing. + */ +void JPEGFragment::Print( std::ostream &os, std::string const &indent ) +{ + os << indent + << "JPEG fragment: offset : " << Offset + << " length : " << Length + << std::endl; +} + +//----------------------------------------------------------------------------- +} // end namespace gdcm + diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmJPEGFragment.h b/Utilities/ITK/Utilities/gdcm/src/gdcmJPEGFragment.h new file mode 100644 index 0000000000000000000000000000000000000000..800e29d4762ded11e3ae18cf2b8e115badeb28a9 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmJPEGFragment.h @@ -0,0 +1,70 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmJPEGFragment.h,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:39 $ + Version: $Revision: 1.4 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + + +#ifndef GDCMJPEGFRAGMENT_H +#define GDCMJPEGFRAGMENT_H + +#include "gdcmCommon.h" + +#include <iostream> +#include <fstream> + +namespace gdcm +{ +/** + * \brief *very* internal class . Shouldn't appear here ! + * Utility class for summerizing the informations of a JPEG + * fragment of an "Encapsulated JPEG Compressed Image". + * This information is a mix of: + * - the fragment offset + * - the fragment length + * + * Each instance of this class (they can be as many instances for + * a given Document as they are JPEG fragments and they are + * collected in a \ref JPEGFragmentsInfo ) + */ +class GDCM_EXPORT JPEGFragment +{ +public: + JPEGFragment(); + void Print( std::ostream &os = std::cout, std::string const &indent = "" ); + void DecompressJPEGFramesFromFile(std::ifstream *fp, + uint8_t *buffer, int nBits, + int &statesuspension); + + bool ReadJPEGFile8 (std::ifstream *fp, void *image_buffer, int &statesuspension ); + bool ReadJPEGFile12 (std::ifstream *fp, void *image_buffer, int &statesuspension ); + bool ReadJPEGFile16 (std::ifstream *fp, void *image_buffer, int &statesuspension ); + + void SetLength(uint32_t length) { Length = length; } + uint32_t GetLength() { return Length; } + void SetOffset(uint32_t offset) { Offset = offset; } + uint32_t GetOffset() { return Offset; } + uint8_t *GetImage() { return pImage; } + +private: + uint32_t Offset; + uint32_t Length; + + uint8_t *pImage; +}; +} // end namespace gdcm + +//----------------------------------------------------------------------------- +#endif diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmJPEGFragmentsInfo.cxx b/Utilities/ITK/Utilities/gdcm/src/gdcmJPEGFragmentsInfo.cxx new file mode 100644 index 0000000000000000000000000000000000000000..62418cbfd6627791180a67081a9d711cb8f8b0a1 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmJPEGFragmentsInfo.cxx @@ -0,0 +1,129 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmJPEGFragmentsInfo.cxx,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:39 $ + Version: $Revision: 1.4 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#include "gdcmJPEGFragmentsInfo.h" +#include "gdcmDebug.h" + +#include <fstream> + +namespace gdcm +{ +//------------------------------------------------------------------------- +// Constructor / Destructor +JPEGFragmentsInfo::JPEGFragmentsInfo() +{ + StateSuspension = 0; +} + +/** + * \brief Default destructor + */ +JPEGFragmentsInfo::~JPEGFragmentsInfo() +{ + for(JPEGFragmentsList::iterator it = Fragments.begin(); + it != Fragments.end(); + ++it ) + { + delete *it; + } + Fragments.clear(); +} + +//----------------------------------------------------------------------------- +// Public +void JPEGFragmentsInfo::DecompressFromFile(std::ifstream *fp, uint8_t *buffer, int nBits, int , int ) +{ + // Pointer to the Raw image + uint8_t *localRaw = buffer; + + // Loop on the fragment[s] + JPEGFragmentsList::const_iterator it; + for( it = Fragments.begin(); + it != Fragments.end(); + ++it ) + { + (*it)->DecompressJPEGFramesFromFile(fp, localRaw, nBits, StateSuspension); + // update pointer to image after some scanlines read: + localRaw = (*it)->GetImage(); + } +} + +void JPEGFragmentsInfo::AddFragment(JPEGFragment *fragment) +{ + Fragments.push_back(fragment); +} + +JPEGFragment *JPEGFragmentsInfo::GetFirstFragment() +{ + ItFragments = Fragments.begin(); + if (ItFragments != Fragments.end()) + return *ItFragments; + return NULL; +} + +JPEGFragment *JPEGFragmentsInfo::GetNextFragment() +{ + gdcmAssertMacro (ItFragments != Fragments.end()); + + ++ItFragments; + if (ItFragments != Fragments.end()) + return *ItFragments; + return NULL; +} + +unsigned int JPEGFragmentsInfo::GetFragmentCount() +{ + return Fragments.size(); +} + +//----------------------------------------------------------------------------- +// Protected + +//----------------------------------------------------------------------------- +// Private + +//----------------------------------------------------------------------------- +// Print +/** + * \brief Print self. + * @param os Stream to print to. + * @param indent Indentation string to be prepended during printing. + */ +void JPEGFragmentsInfo::Print( std::ostream &os, std::string const &indent ) +{ + os << std::endl; + os << indent + << "----------------- JPEG fragments --------------------------------" + << std::endl << std::endl; + os << indent + << "Total number of fragments : " << Fragments.size() + << std::endl; + int fragmentNumber = 0; + for(JPEGFragmentsList::iterator it = Fragments.begin(); + it != Fragments.end(); + ++it) + { + os << indent + << " fragment number :" << fragmentNumber++; + (*it)->Print( os, indent + " "); + } + os << std::endl; +} + +//----------------------------------------------------------------------------- +} // end namespace gdcm diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmJPEGFragmentsInfo.h b/Utilities/ITK/Utilities/gdcm/src/gdcmJPEGFragmentsInfo.h new file mode 100644 index 0000000000000000000000000000000000000000..c6eac97018375e9ececc7359f8fae29461ecc3b5 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmJPEGFragmentsInfo.h @@ -0,0 +1,71 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmJPEGFragmentsInfo.h,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:39 $ + Version: $Revision: 1.4 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + + +#ifndef GDCMJPEGFRAGMENTSINFO_H +#define GDCMJPEGFRAGMENTSINFO_H + +#include "gdcmJPEGFragment.h" + +#include <list> +#include <iostream> + +namespace gdcm +{ +/** + * \brief Utility class for gathering the informations of the collection + * of JPEG fragment[s] (see \ref JPEGFragment) when handling + * "Encapsulated JPEG Compressed Images". + * The informations on each frame are obtained during the pixel parsing + * of a gdcm::File (refer to \ref File::ComputeJPEGFragmentInfo() ). + * They shall be used when (if necessary) decoding the fragments. + * + * This class is simply a stl list<> of \ref JPEGFragment. + */ +class GDCM_EXPORT JPEGFragmentsInfo +{ +friend class File; +friend class PixelReadConvert; + +private: + JPEGFragmentsInfo(); + ~JPEGFragmentsInfo(); + void Print( std::ostream &os = std::cout, std::string const &indent = "" ); + + void DecompressFromFile(std::ifstream *fp, uint8_t *buffer, int nBits, + int numBytes, int length); + + void AddFragment(JPEGFragment *fragment); + JPEGFragment *GetFirstFragment(); + JPEGFragment *GetNextFragment(); + unsigned int GetFragmentCount(); + + typedef std::list<JPEGFragment *> JPEGFragmentsList; + + //Some mathieu hack: + int StateSuspension; + void *SampBuffer; + char *pimage; + JPEGFragmentsList Fragments; + JPEGFragmentsList::iterator ItFragments; +}; +} // end namespace gdcm + +//----------------------------------------------------------------------------- +#endif + diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmJpeg.cxx b/Utilities/ITK/Utilities/gdcm/src/gdcmJpeg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..8d6eab3a265b27e52c5c6add6fc2d998b9204536 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmJpeg.cxx @@ -0,0 +1,379 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmJpeg.cxx,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:39 $ + Version: $Revision: 1.7 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ +#include "gdcmFileHelper.h" +#include "gdcmJPEGFragment.h" +#include "gdcmDebug.h" + +#if defined(__sgi) && !defined(__GNUC__) +// Try to get rid of the warning: +//cc-3505 CC: WARNING File = /usr/include/internal/setjmp_core.h, Line = 74 +// setjmp not marked as unknown_control_flow because it is not declared as a +// function +// +// #pragma unknown_control_flow (setjmp) +# if (_COMPILER_VERSION >= 730) +# pragma set woff 3505 +# endif +#endif +#ifdef _MSC_VER +// Let us get rid of this funny warning on /W4: +// warning C4611: interaction between '_setjmp' and C++ object +// destruction is non-portable +#pragma warning( disable : 4611 ) +#endif + +#include <setjmp.h> +#include <fstream> + +#if defined(__BORLANDC__) + #include <mem.h> // for memset +#endif + +#include "jdatasrc.cxx" +#include "jdatadst.cxx" + +namespace gdcm +{ + + /** + * \brief routine for JPEG decompression + * @param fp pointer to an already open file descriptor + * 8 significant bits per pixel + * @param im_buf Points to array (of R,G,B-order) data to compress + * @param quality compression quality + * @param image_height Number of rows in image + * @param image_width Number of columns in image + * @return 1 on success, 0 on error + */ + +bool gdcm_write_JPEG_file (std::ostream *fp, void *im_buf, + int image_width, int image_height, int quality) +{ + + JSAMPLE *image_buffer = (JSAMPLE*) im_buf; + + /* This struct contains the JPEG compression parameters and pointers to + * working space (which is allocated as needed by the JPEG library). + * It is possible to have several such structures, representing multiple + * compression/decompression processes, in existence at once. We refer + * to any one struct (and its associated working data) as a "JPEG object". + */ + struct jpeg_compress_struct cinfo; + /* This struct represents a JPEG error handler. It is declared separately + * because applications often want to supply a specialized error handler + * (see the second half of this file for an example). But here we just + * take the easy way out and use the standard error handler, which will + * print a message on stderr and call exit() if compression fails. + * Note that this struct must live as long as the main JPEG parameter + * struct, to avoid dangling-pointer problems. + */ + struct jpeg_error_mgr jerr; + /* More stuff */ + //FILE* outfile; /* target FILE* / + JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ + int row_stride; /* physical row width in image buffer */ + + /* Step 1: allocate and initialize JPEG compression object */ + + /* We have to set up the error handler first, in case the initialization + * step fails. (Unlikely, but it could happen if you are out of memory.) + * This routine fills in the contents of struct jerr, and returns jerr's + * address which we place into the link field in cinfo. + */ + cinfo.err = jpeg_std_error(&jerr); + /* Now we can initialize the JPEG compression object. */ + jpeg_create_compress(&cinfo); + + /* Step 2: specify data destination (eg, a file) */ + /* Note: steps 2 and 3 can be done in either order. */ + + /* Here we use the library-supplied code to send compressed data to a + * stdio stream. You can also write your own code to do something else. + * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that + * requires it in order to write binary files. + */ + // if ((outfile = fopen(filename, "wb")) == NULL) { + // fprintf(stderr, "can't open %s\n", filename); + // exit(1); + // + // } + assert( 0 ); + (void)fp; + //jpeg_stdio_dest(&cinfo, fp, 0, 0, image_width, image_height, quality); + + /* Step 3: set parameters for compression */ + + /* First we supply a description of the input image. + * Four fields of the cinfo struct must be filled in: + */ + cinfo.image_width = image_width;/* image width and height, in pixels */ + cinfo.image_height = image_height; + cinfo.input_components = 3; /* # of color components per pixel */ + cinfo.in_color_space = JCS_RGB; /* colorspace of input image */ + /* Now use the library's routine to set default compression parameters. + * (You must set at least cinfo.in_color_space before calling this, + * since the defaults depend on the source color space.) + */ + jpeg_set_defaults(&cinfo); + /* Now you can set any non-default parameters you wish to. + * Here we just illustrate the use of quality (quantization table) scaling: + */ + jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */); + + /* Step 4: Start compressor */ + + /* TRUE ensures that we will write a complete interchange-JPEG file. + * Pass TRUE unless you are very sure of what you're doing. + */ + jpeg_start_compress(&cinfo, TRUE); + + /* Step 5: while (scan lines remain to be written) */ + /* jpeg_write_scanlines(...); */ + + /* Here we use the library's state variable cinfo.next_scanline as the + * loop counter, so that we don't have to keep track ourselves. + * To keep things simple, we pass one scanline per call; you can pass + * more if you wish, though. + */ + row_stride = image_width * 3;/* JSAMPLEs per row in image_buffer */ + + while (cinfo.next_scanline < cinfo.image_height) { + /* jpeg_write_scanlines expects an array of pointers to scanlines. + * Here the array is only one element long, but you could pass + * more than one scanline at a time if that's more convenient. + */ + row_pointer[0] = & image_buffer[cinfo.next_scanline * row_stride]; + + (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); + } + + /* Step 6: Finish compression */ + + jpeg_finish_compress(&cinfo); + + /* After finish_compress, we can close the output file. */ + + // fclose(fp); --> the caller will close (multiframe treatement) + + /* Step 7: release JPEG compression object */ + + /* This is an important step since it will release a good deal of memory. */ + jpeg_destroy_compress(&cinfo); + + /* And we're done! */ + + return true; +} + +//----------------------------------------------------------------------------- +struct my_error_mgr { + struct jpeg_error_mgr pub; /* "public" fields */ + jmp_buf setjmp_buffer; /* for return to caller */ +}; +typedef struct my_error_mgr* my_error_ptr; +//----------------------------------------------------------------------------- + +/* + * Here's the routine that will replace the standard error_exit method: + */ +extern "C" { +METHODDEF(void) my_error_exit (j_common_ptr cinfo) { + /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */ + my_error_ptr myerr = (my_error_ptr) cinfo->err; + + /* Always display the message. */ + /* We could postpone this until after returning, if we chose. */ + (*cinfo->err->output_message) (cinfo); + + /* Return control to the setjmp point */ + longjmp(myerr->setjmp_buffer, 1); +} + +//METHODDEF(void) my_output_message (j_common_ptr cinfo) +//{ +// char buffer[JMSG_LENGTH_MAX]; +// +// /* Create the message */ +// (*cinfo->err->format_message) (cinfo, buffer); +// +// // Custom display message, we could be more fancy and throw an exception: +// gdcmErrorMacro( buffer ); +//} + +} +//----------------------------------------------------------------------------- + +/** + * \brief routine for JPEG decompression + * @param fp pointer to an already open file descriptor + * 8 significant bits per pixel + * @param image_buffer to receive uncompressed pixels + * @param statesuspension Suspension State basically it should be 3 otherwise more complex to handle + * @return 1 on success, 0 on error + */ +void *SampBuffer; +bool JPEGFragment::ReadJPEGFile (std::ifstream *fp, void *image_buffer, int &statesuspension) +{ + pImage = (uint8_t*)image_buffer; + // This struct contains the JPEG decompression parameters and pointers to + // working space (which is allocated as needed by the JPEG library). + + static struct jpeg_decompress_struct cinfo; + + // -------------- inside, we found : + // JDIMENSION image_width; // input image width + // JDIMENSION image_height; // input image height + // int input_components; // nb of color components in input image + // J_COLOR_SPACE in_color_space; // colorspace of input image + // double input_gamma; // image gamma of input image + + // We use our private extension JPEG error handler. + // Note that this struct must live as long as the main JPEG parameter + // struct, to avoid dangling-pointer problems. + + struct my_error_mgr jerr; + + JSAMPARRAY buffer;// Output row buffer + + // rappel : + // ------ + // typedef unsigned char JSAMPLE; + // typedef JSAMPLE FAR *JSAMPROW;/* ptr to one image row of pixel samples. */ + // typedef JSAMPROW *JSAMPARRAY;/* ptr to some rows (a 2-D sample array) */ + // typedef JSAMPARRAY *JSAMPIMAGE;/* a 3-D sample array: top index is color */ + + int row_stride;// physical row width in output buffer + + // We set up the normal JPEG error routines, then override error_exit. + + cinfo.err = jpeg_std_error(&jerr.pub); + // for any jpeg error call my_error_exit + jerr.pub.error_exit = my_error_exit; + // for any output message call my_output_message + //jerr.pub.output_message = my_output_message; + + // Establish the setjmp return context for my_error_exit to use. + if (setjmp(jerr.setjmp_buffer)) + { + // If we get here, the JPEG code has signaled an error. + // We need to clean up the JPEG object, close the input file, and return. + + gdcmErrorMacro( "Serious Problem !" ); + jpeg_destroy_decompress(&cinfo); + return 0; + } + // Now we can initialize the JPEG decompression object. + if ( statesuspension == 0 ) + { + jpeg_create_decompress(&cinfo); + jpeg_stdio_src(&cinfo, fp, this, 1); + } + else + { + jpeg_stdio_src(&cinfo, fp, this, 0); + } + // Step 3: read file parameters with jpeg_read_header() + + if ( statesuspension < 2 ) + { + if ( jpeg_read_header(&cinfo, TRUE) == JPEG_SUSPENDED ) + { + // Suspension in jpeg_read_header + statesuspension = 2; + } + + // Step 4: set parameters for decompression + // prevent the library from performing any color space conversion + if ( cinfo.process == JPROC_LOSSLESS ) + { + cinfo.jpeg_color_space = JCS_UNKNOWN; + cinfo.out_color_space = JCS_UNKNOWN; + } + } + + // Step 5: Start decompressor + if (statesuspension < 3 ) + { + if ( jpeg_start_decompress(&cinfo) == FALSE ) + { + // Suspension: jpeg_start_decompress + statesuspension = 3; + } + + // JSAMPLEs per row in output buffer + row_stride = cinfo.output_width * cinfo.output_components*2; + + // Make a one-row-high sample array that will go away when done with image + buffer = (*cinfo.mem->alloc_sarray) + ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); + + // Step 6: while (scan lines remain to be read) + + // Save the buffer in case of suspension to be able to reuse it later: + SampBuffer = buffer; + } + else + { + // Suspension: re-use the buffer: + buffer = (JSAMPARRAY)SampBuffer; + } + int bufsize = cinfo.output_width * cinfo.output_components; + size_t rowsize = bufsize * sizeof(JSAMPLE); + + while (cinfo.output_scanline < cinfo.output_height) + { + if ( jpeg_read_scanlines(&cinfo, buffer, 1) == 0 ) + { + // Suspension in jpeg_read_scanlines + statesuspension = 3; + return true; + } +// The ijg has no notion of big endian, therefore always swap the jpeg stream +#if (defined(GDCM_WORDS_BIGENDIAN) || defined(GDCM_FORCE_BIGENDIAN_EMULATION)) && (CMAKE_BITS_IN_JSAMPLE != 8) + uint16_t *buffer16 = (uint16_t*)*buffer; + uint16_t *pimage16 = (uint16_t*)pImage; + for(unsigned int i=0;i<rowsize/2;i++) + pimage16[i] = (buffer16[i] >> 8) | (buffer16[i] << 8 ); +#else + memcpy( pImage, *buffer,rowsize); +#endif //GDCM_WORDS_BIGENDIAN + pImage+=rowsize; + } + + // Step 7: Finish decompression + if ( jpeg_finish_decompress(&cinfo) == FALSE ) + { + // Suspension: jpeg_finish_decompress + statesuspension = 4; + } + + // Step 8: Release JPEG decompression object + jpeg_destroy_decompress(&cinfo); + + // At this point you may want to check to see whether any corrupt-data + // warnings occurred (test whether jerr.pub.num_warnings is nonzero). + + return true; +} + +#ifdef _MSC_VER +// Put the warning back +#pragma warning( default : 4611 ) +#endif + +} // end namespace gdcm diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmJpeg12.cxx b/Utilities/ITK/Utilities/gdcm/src/gdcmJpeg12.cxx new file mode 100644 index 0000000000000000000000000000000000000000..c9728484a1efd33cc9de42e22e033ca60ca6c42f --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmJpeg12.cxx @@ -0,0 +1,33 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmJpeg12.cxx,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:39 $ + Version: $Revision: 1.6 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ +#include "gdcmFileHelper.h" +#include <stdio.h> + +extern "C" { +#include "itkjpeg/12/jconfig.h" +#include "itkjpeg/12/jpeglib.h" +#include "itkjpeg/12/jinclude.h" +#include "itkjpeg/12/jerror.h" +} + +#define gdcm_write_JPEG_file gdcm_write_JPEG_file12 +#define ReadJPEGFile ReadJPEGFile12 +#define SampBuffer SampBuffer12 + +#include "gdcmJpeg.cxx" + diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmJpeg16.cxx b/Utilities/ITK/Utilities/gdcm/src/gdcmJpeg16.cxx new file mode 100644 index 0000000000000000000000000000000000000000..8a6dccd90ae46affce029c84ae37b9da654ac421 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmJpeg16.cxx @@ -0,0 +1,33 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmJpeg16.cxx,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:39 $ + Version: $Revision: 1.6 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ +#include "gdcmFileHelper.h" +#include <stdio.h> + +extern "C" { +#include "itkjpeg/16/jconfig.h" +#include "itkjpeg/16/jpeglib.h" +#include "itkjpeg/16/jinclude.h" +#include "itkjpeg/16/jerror.h" +} + +#define gdcm_write_JPEG_file gdcm_write_JPEG_file16 +#define ReadJPEGFile ReadJPEGFile16 +#define SampBuffer SampBuffer16 + +#include "gdcmJpeg.cxx" + diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmJpeg2000.cxx b/Utilities/ITK/Utilities/gdcm/src/gdcmJpeg2000.cxx new file mode 100644 index 0000000000000000000000000000000000000000..e77308ef5d719dd93e42055c7bc514a3d444e6c1 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmJpeg2000.cxx @@ -0,0 +1,350 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmJpeg2000.cxx,v $ + Language: C++ + Date: $Date: 2006/02/18 12:46:05 $ + Version: $Revision: 1.6 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ +#include "gdcmFileHelper.h" +#include "gdcmDebug.h" + +#include <iostream> +#include <fstream> + +#if defined(__BORLANDC__) + #include <mem.h> // for memset +#endif + +extern "C" { + #include "openjpeg/openjpeg.h" +} + +namespace gdcm +{ +//----------------------------------------------------------------------------- + /** + * \brief routine for JPEG decompression + * @param raw raw + * @param inputdata inputdata + * @param inputlength inputlength + * @return 1 on success, 0 on error + */ + +/** +sample error callback expecting a FILE* client object +*/ +void error_callback(const char *msg, void *) { + std::cerr << "Error in gdcmopenjpeg" << msg << std::endl; +} +/** +sample warning callback expecting a FILE* client object +*/ +void warning_callback(const char *msg, void *) { + std::cerr << "Warning in gdcmopenjpeg" << msg << std::endl; +} +/** +sample debug callback expecting no client object +*/ +void info_callback(const char *msg, void *) { + std::cerr << "Info in gdcmopenjpeg" << msg << std::endl; +} + +#define J2K_CFMT 0 +#define JP2_CFMT 1 +#define JPT_CFMT 2 +#define MJ2_CFMT 3 +#define PXM_DFMT 0 +#define PGX_DFMT 1 +#define BMP_DFMT 2 +#define YUV_DFMT 3 + +/* + * Divide an integer by a power of 2 and round upwards. + * + * a divided by 2^b + */ +inline int int_ceildivpow2(int a, int b) { + return (a + (1 << b) - 1) >> b; +} + +/* + * The following function was copy paste from j2k_to_image.c with part from convert.c + */ +bool gdcm_read_JPEG2000_file (void* raw, char *inputdata, size_t inputlength) +{ + opj_dparameters_t parameters; /* decompression parameters */ + opj_event_mgr_t event_mgr; /* event manager */ + opj_image_t *image; + opj_dinfo_t* dinfo; /* handle to a decompressor */ + opj_cio_t *cio; + unsigned char *src = (unsigned char*)inputdata; + int file_length = inputlength; + + /* configure the event callbacks (not required) */ + memset(&event_mgr, 0, sizeof(opj_event_mgr_t)); + event_mgr.error_handler = error_callback; + event_mgr.warning_handler = warning_callback; + event_mgr.info_handler = info_callback; + + /* set decoding parameters to default values */ + opj_set_default_decoder_parameters(¶meters); + + // default blindly copied + parameters.cp_layer=0; + parameters.cp_reduce=0; +// parameters.decod_format=-1; +// parameters.cod_format=-1; + + /* JPEG-2000 codestream */ + parameters.decod_format = J2K_CFMT; + assert(parameters.decod_format == J2K_CFMT); + parameters.cod_format = PGX_DFMT; + assert(parameters.cod_format == PGX_DFMT); + + /* get a decoder handle */ + dinfo = opj_create_decompress(CODEC_J2K); + + /* catch events using our callbacks and give a local context */ + opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, NULL); + + /* setup the decoder decoding parameters using user parameters */ + opj_setup_decoder(dinfo, ¶meters); + + /* open a byte stream */ + cio = opj_cio_open((opj_common_ptr)dinfo, src, file_length); + + /* decode the stream and fill the image structure */ + image = opj_decode(dinfo, cio); + if(!image) { + opj_destroy_decompress(dinfo); + opj_cio_close(cio); + return 1; + } + + /* close the byte stream */ + opj_cio_close(cio); + + /* free the memory containing the code-stream */ + delete[] src; //FIXME + + // Copy buffer + for (int compno = 0; compno < image->numcomps; compno++) + { + opj_image_comp_t *comp = &image->comps[compno]; + + int w = image->comps[compno].w; + int wr = int_ceildivpow2(image->comps[compno].w, image->comps[compno].factor); + + //int h = image.comps[compno].h; + int hr = int_ceildivpow2(image->comps[compno].h, image->comps[compno].factor); + + if (comp->prec <= 8) + { + uint8_t *data8 = (uint8_t*)raw; + for (int i = 0; i < wr * hr; i++) + { + int v = image->comps[compno].data[i / wr * w + i % wr]; + *data8++ = (uint8_t)v; + } + } + else if (comp->prec <= 16) + { + uint16_t *data16 = (uint16_t*)raw; + for (int i = 0; i < wr * hr; i++) + { + int v = image->comps[compno].data[i / wr * w + i % wr]; + *data16++ = (uint16_t)v; + } + } + else + { + uint32_t *data32 = (uint32_t*)raw; + for (int i = 0; i < wr * hr; i++) + { + int v = image->comps[compno].data[i / wr * w + i % wr]; + *data32++ = (uint32_t)v; + } + } + //free(image.comps[compno].data); + } + + + /* free remaining structures */ + if(dinfo) { + opj_destroy_decompress(dinfo); + } + + /* free image data structure */ + opj_image_destroy(image); + + return true; +} + +#if 0 +// For openjpeg 0.97 +bool gdcm_read_JPEG2000_file (void* raw, char *inputdata, size_t inputlength) +{ + j2k_image_t img; + j2k_cp_t cp; + + // default blindly copied + cp.layer=0; + cp.reduce=0; + cp.decod_format=-1; + cp.cod_format=-1; + + cp.cod_format=J2K_CFMT; + cp.decod_format = PGX_DFMT; + int len = inputlength; + unsigned char *src = (unsigned char*)inputdata; + + // Decompression + if (!j2k_decode(src, len, &img, &cp)) + { + gdcmErrorMacro( "ERROR -> j2k_to_image: failed to decode image!" ); + return false; + } + + // Copy buffer + for (int compno = 0; compno < img.numcomps; compno++) + { + j2k_comp_t *comp = &img.comps[compno]; + + int w = img.comps[compno].w; + int wr = int_ceildivpow2(img.comps[compno].w, img.comps[compno].factor); + + //int h = img.comps[compno].h; + int hr = int_ceildivpow2(img.comps[compno].h, img.comps[compno].factor); + + if (comp->prec <= 8) + { + uint8_t *data8 = (uint8_t*)raw; + for (int i = 0; i < wr * hr; i++) + { + int v = img.comps[compno].data[i / wr * w + i % wr]; + *data8++ = (uint8_t)v; + } + } + else if (comp->prec <= 16) + { + uint16_t *data16 = (uint16_t*)raw; + for (int i = 0; i < wr * hr; i++) + { + int v = img.comps[compno].data[i / wr * w + i % wr]; + *data16++ = (uint16_t)v; + } + } + else + { + uint32_t *data32 = (uint32_t*)raw; + for (int i = 0; i < wr * hr; i++) + { + int v = img.comps[compno].data[i / wr * w + i % wr]; + *data32++ = (uint32_t)v; + } + } + free(img.comps[compno].data); + } + + // Free remaining structures + j2k_dec_release(); + // FIXME + delete[] inputdata; + + return true; +} +#endif + +#if 0 +bool gdcm_read_JASPER_file (void* raw, char *inputdata, size_t inputlength) +{ +#if 0 + std::cerr << "Inputlenght=" << inputlength << std::endl; + std::ofstream out("/tmp/jpeg2000.jpc", std::ios::binary); + out.write((char*)inputdata,inputlength); + out.close(); +#endif + jas_init(); //important... + jas_stream_t *jasStream = + jas_stream_memopen((char *)inputdata, inputlength); + + int fmtid; + if ((fmtid = jas_image_getfmt(jasStream)) < 0) + { + gdcmErrorMacro("unknown image format"); + return false; + } + + // Decode the image. + jas_image_t *jasImage /* = NULL*/; // Useless assignation + if (!(jasImage = jas_image_decode(jasStream, fmtid, 0))) + { + gdcmErrorMacro("cannot decode image"); + return false; + } + + // close the stream. + jas_stream_close(jasStream); + int numcmpts = jas_image_numcmpts(jasImage); + int width = jas_image_cmptwidth(jasImage, 0); + int height = jas_image_cmptheight(jasImage, 0); + int prec = jas_image_cmptprec(jasImage, 0); + int i, j, k; + + // The following should serioulsy be rewritten I cannot believe we need to + // do a per pixel decompression, there should be a way to read a full + // scanline... + if (prec == 8) + { + uint8_t *data8 = (uint8_t*)raw; + for ( i = 0; i < height; i++) + for ( j = 0; j < width; j++) + for ( k= 0; k < numcmpts; k++) + *data8++ = (uint8_t)(jas_image_readcmptsample(jasImage, k, j ,i )); + } + else if (prec <= 16) + { + uint16_t *data16 = (uint16_t*)raw; + for ( i = 0; i < height; i++) + for ( j = 0; j < width; j++) + for ( k= 0; k < numcmpts; k++) + *data16++ = (uint16_t)(jas_image_readcmptsample(jasImage, k, j ,i )); + } + else if (prec <= 32) + { + uint32_t *data32 = (uint32_t*)raw; + for ( i = 0; i < height; i++) + for ( j = 0; j < width; j++) + for ( k= 0; k < numcmpts; k++) + *data32++ = (uint32_t)(jas_image_readcmptsample(jasImage, k, j ,i )); + } + + jas_image_destroy(jasImage); + jas_image_clearfmts(); + + //FIXME + //delete the jpeg temp buffer +#if 0 + std::ofstream rawout("/tmp/jpeg2000.raw"); + rawout.write((char*)raw,height*width*numcmpts*((prec+4)/8)); + rawout.close(); +#endif + delete[] inputdata; + + return true; +} +#endif + +//----------------------------------------------------------------------------- +} // end namespace gdcm + diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmJpeg8.cxx b/Utilities/ITK/Utilities/gdcm/src/gdcmJpeg8.cxx new file mode 100644 index 0000000000000000000000000000000000000000..31a6a51f970644d302460660bcaf811f7592a66d --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmJpeg8.cxx @@ -0,0 +1,33 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmJpeg8.cxx,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:39 $ + Version: $Revision: 1.6 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ +#include "gdcmFileHelper.h" +#include <stdio.h> + +extern "C" { +#include "itkjpeg/8/jconfig.h" +#include "itkjpeg/8/jpeglib.h" +#include "itkjpeg/8/jinclude.h" +#include "itkjpeg/8/jerror.h" +} + +#define gdcm_write_JPEG_file gdcm_write_JPEG_file8 +#define ReadJPEGFile ReadJPEGFile8 +#define SampBuffer SampBuffer8 + +#include "gdcmJpeg.cxx" + diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmJpegLS.cxx b/Utilities/ITK/Utilities/gdcm/src/gdcmJpegLS.cxx new file mode 100644 index 0000000000000000000000000000000000000000..5cf1b0eb5850c09ddb9d8740412fc2e273e5bb60 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmJpegLS.cxx @@ -0,0 +1,51 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmJpegLS.cxx,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:39 $ + Version: $Revision: 1.3 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ +#include "gdcmFileHelper.h" +#include "gdcmDebug.h" + +#include <iostream> +#include <fstream> + +namespace gdcm +{ + +//----------------------------------------------------------------------------- + /** + * \brief routine for JPEG decompression. WARNING LPEG-LS is NOT + * the 'classical' jpeg lossless. See : + * http://www.jpeg.org/jpeg/jpegls.html + * gdcm DOES deal with 'classical' jpeg lossless + * + * @param fp pointer to an already open file descriptor + * JPEG-LS encoded image + * @param image_buffer to receive uncompressed pixels + * @return 1 on success, 0 on error + * @warning : not yet made + */ + +bool gdcm_read_JPEGLS_file (std::ifstream *fp, void *image_buffer) +{ + (void)fp; + (void)image_buffer; + gdcmWarningMacro( "Sorry JPEG-LS File not yet taken into account" ); + return false; +} +} // end namespace gdcm + +//----------------------------------------------------------------------------- + diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmMpeg.cxx b/Utilities/ITK/Utilities/gdcm/src/gdcmMpeg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..587037837f70644887def74f8ac2fdec0102e801 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmMpeg.cxx @@ -0,0 +1,421 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmMpeg.cxx,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:39 $ + Version: $Revision: 1.2 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ +#include "gdcmDebug.h" + +#include <fstream> +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <fcntl.h> +extern "C" { +#define GLOBAL +#include "config.h" +#include "global.h" + +/* private prototypes */ +static int video_sequence _ANSI_ARGS_((int *framenum)); +static int Decode_Bitstream _ANSI_ARGS_((void)); +static int Headers _ANSI_ARGS_((void)); +static void Initialize_Sequence _ANSI_ARGS_((void)); +static void Initialize_Decoder _ANSI_ARGS_((void)); +static void Deinitialize_Sequence _ANSI_ARGS_((void)); +//static void Process_Options _ANSI_ARGS_((int argc, char *argv[])); + +/* IMPLEMENTATION specific routines */ +static void Initialize_Decoder() +{ + int i; + + /* Clip table */ + if ( !(Clip=(unsigned char *)malloc(1024)) ) + Error("Clip[] malloc failed\n"); + + Clip += 384; + + for (i=-384; i<640; i++) + Clip[i] = (i<0) ? 0 : ((i>255) ? 255 : i); + + /* IDCT */ + if ( Reference_IDCT_Flag ) + Initialize_Reference_IDCT(); + else + Initialize_Fast_IDCT(); + +} + +/* mostly IMPLEMENTATION specific routines */ +static void Initialize_Sequence() +{ + int cc, size; + static int Table_6_20[3] = {6,8,12}; + + /* check scalability mode of enhancement layer */ + if ( Two_Streams && (enhan.scalable_mode!=SC_SNR) + && + (base.scalable_mode!=SC_DP) ) + { + Error("unsupported scalability mode\n"); + } + /* force MPEG-1 parameters for proper decoder behavior */ + /* see ISO/IEC 13818-2 section D.9.14 */ + if ( !base.MPEG2_Flag ) + { + progressive_sequence = 1; + progressive_frame = 1; + picture_structure = FRAME_PICTURE; + frame_pred_frame_dct = 1; + chroma_format = CHROMA420; + matrix_coefficients = 5; + } + + /* round to nearest multiple of coded macroblocks */ + /* ISO/IEC 13818-2 section 6.3.3 sequence_header() */ + mb_width = (horizontal_size+15)/16; + mb_height = (base.MPEG2_Flag && !progressive_sequence) ? 2*((vertical_size+31)/32) + : (vertical_size+15)/16; + + Coded_Picture_Width = 16*mb_width; + Coded_Picture_Height = 16*mb_height; + + /* ISO/IEC 13818-2 sections 6.1.1.8, 6.1.1.9, and 6.1.1.10 */ + Chroma_Width = (chroma_format==CHROMA444) ? Coded_Picture_Width + : Coded_Picture_Width>>1; + Chroma_Height = (chroma_format!=CHROMA420) ? Coded_Picture_Height + : Coded_Picture_Height>>1; + + /* derived based on Table 6-20 in ISO/IEC 13818-2 section 6.3.17 */ + block_count = Table_6_20[chroma_format-1]; + + for (cc=0; cc<3; cc++) + { + if ( cc==0 ) + size = Coded_Picture_Width*Coded_Picture_Height; + else + size = Chroma_Width*Chroma_Height; + + if ( !(backward_reference_frame[cc] = (unsigned char *)malloc(size)) ) + Error("backward_reference_frame[] malloc failed\n"); + + if ( !(forward_reference_frame[cc] = (unsigned char *)malloc(size)) ) + Error("forward_reference_frame[] malloc failed\n"); + + if ( !(auxframe[cc] = (unsigned char *)malloc(size)) ) + Error("auxframe[] malloc failed\n"); + + if ( Ersatz_Flag ) + if ( !(substitute_frame[cc] = (unsigned char *)malloc(size)) ) + Error("substitute_frame[] malloc failed\n"); + + + if ( base.scalable_mode==SC_SPAT ) + { + /* this assumes lower layer is 4:2:0 */ + if ( !(llframe0[cc] = (unsigned char *)malloc((lower_layer_prediction_horizontal_size*lower_layer_prediction_vertical_size)/(cc?4:1)))) + Error("llframe0 malloc failed\n"); + if ( !(llframe1[cc] = (unsigned char *)malloc((lower_layer_prediction_horizontal_size*lower_layer_prediction_vertical_size)/(cc?4:1)))) + Error("llframe1 malloc failed\n"); + } + } + + /* SCALABILITY: Spatial */ + if ( base.scalable_mode==SC_SPAT ) + { + if ( !(lltmp = (short *)malloc(lower_layer_prediction_horizontal_size*((lower_layer_prediction_vertical_size*vertical_subsampling_factor_n)/vertical_subsampling_factor_m)*sizeof(short)))) + Error("lltmp malloc failed\n"); + } + +#ifdef DISPLAY + if (Output_Type==T_X11) + { + Initialize_Display_Process(""); + Initialize_Dither_Matrix(); + } +#endif /* DISPLAY */ + +} + +extern void Error(char *text) +{ + fprintf(stderr,text); + exit(1); +} + +/* Trace_Flag output */ +void Print_Bits(int code, int bits, int len) +{ + int i; + for (i=0; i<len; i++) + printf("%d",(code>>(bits-1-i))&1); +} + +static int Headers() +{ + int ret; + + ld = &base; + + /* return when end of sequence (0) or picture + header has been parsed (1) */ + + ret = Get_Hdr(); + + + if (Two_Streams) + { + ld = &enhan; + if (Get_Hdr()!=ret && !Quiet_Flag) + fprintf(stderr,"streams out of sync\n"); + ld = &base; + } + + return ret; +} + + + +static int Decode_Bitstream() +{ + int ret; + int Bitstream_Framenum; + + Bitstream_Framenum = 0; + + for(;;) + { + +#ifdef VERIFY + Clear_Verify_Headers(); +#endif /* VERIFY */ + + ret = Headers(); + + if ( ret==1 ) + { + ret = video_sequence(&Bitstream_Framenum); + } + else + return(ret); + } + +} + + +static void Deinitialize_Sequence() +{ + int i; + + /* clear flags */ + base.MPEG2_Flag=0; + + for(i=0;i<3;i++) + { + free(backward_reference_frame[i]); + free(forward_reference_frame[i]); + free(auxframe[i]); + + if ( base.scalable_mode==SC_SPAT ) + { + free(llframe0[i]); + free(llframe1[i]); + } + } + + if ( base.scalable_mode==SC_SPAT ) + free(lltmp); + +#ifdef DISPLAY + if ( Output_Type==T_X11 ) + Terminate_Display_Process(); +#endif +} + + +static int video_sequence(int *Bitstream_Framenumber) +{ + int Bitstream_Framenum; + int Sequence_Framenum; + int Return_Value; + + Bitstream_Framenum = *Bitstream_Framenumber; + Sequence_Framenum=0; + + Initialize_Sequence(); + + /* decode picture whose header has already been parsed in + Decode_Bitstream() */ + + + Decode_Picture(Bitstream_Framenum, Sequence_Framenum); + + /* update picture numbers */ + if ( !Second_Field ) + { + Bitstream_Framenum++; + Sequence_Framenum++; + } + + /* loop through the rest of the pictures in the sequence */ + while ((Return_Value=Headers())) + { + Decode_Picture(Bitstream_Framenum, Sequence_Framenum); + + if ( !Second_Field ) + { + Bitstream_Framenum++; + Sequence_Framenum++; + } + } + + /* put last frame */ + if (Sequence_Framenum!=0) + { + Output_Last_Frame_of_Sequence(Bitstream_Framenum); + } + + Deinitialize_Sequence(); + +#ifdef VERIFY + Clear_Verify_Headers(); +#endif /* VERIFY */ + + *Bitstream_Framenumber = Bitstream_Framenum; + return(Return_Value); +} +} // End "C" extern + +namespace gdcm +{ +/** + * \brief routine for MPEG decompression + * @param fp pointer to an already open file descriptor + * 8 significant bits per pixel + * @param image_buffer to receive uncompressed pixels + * @param length length + * @return 1 on success, 0 on error + */ + +bool ReadMPEGFile (std::ifstream *fp, void *image_buffer, size_t length) +{ + int ret, code; + +#if 0 + fp->read((char*)image_buffer, length); + + ofstream out("/tmp/etiam.mpeg"); + out.write((char*)image_buffer, length); + out.close(); +#endif + +// Clear_Options(); + + /* decode command line arguments */ +// Process_Options(argc,argv); + +#ifdef DEBUG + Print_Options(); +#endif + + ld = &base; /* select base layer context */ + + /* open MPEG base layer bitstream file(s) */ + /* NOTE: this is either a base layer stream or a spatial enhancement stream */ +#if 0 + if ((base.Infile=open(Main_Bitstream_Filename,O_RDONLY|O_BINARY))<0) + { + fprintf(stderr,"Base layer input file %s not found\n", Main_Bitstream_Filename); + exit(1); + } +#else + base.Infile = -1; //DEBUG +#endif + + + if ( base.Infile != 0 ) + { + Initialize_Buffer(); + + if ( Show_Bits(8)==0x47 ) + { + sprintf(Error_Text,"Decoder currently does not parse transport streams\n"); + Error(Error_Text); + } + + next_start_code(); + code = Show_Bits(32); + + switch(code) + { + case SEQUENCE_HEADER_CODE: + break; + case PACK_START_CODE: + System_Stream_Flag = 1; + case VIDEO_ELEMENTARY_STREAM: + System_Stream_Flag = 1; + break; + default: + sprintf(Error_Text,"Unable to recognize stream type\n"); + Error(Error_Text); + break; + } + + //lseek(base.Infile, 0l, SEEK_SET); + //fp->seekg(mpeg_start, ios_base::beg); + Initialize_Buffer(); + } + + if ( base.Infile!=0 ) + { + //lseek(base.Infile, 0l, SEEK_SET); + //fp->seekg(mpeg_start, ios_base::beg); + } + + Initialize_Buffer(); + + if ( Two_Streams ) + { + abort(); + ld = &enhan; /* select enhancement layer context */ + + if ( (enhan.Infile = open(Enhancement_Layer_Bitstream_Filename,O_RDONLY|O_BINARY))<0) + { + sprintf(Error_Text,"enhancment layer bitstream file %s not found\n", + Enhancement_Layer_Bitstream_Filename); + + Error(Error_Text); + } + + Initialize_Buffer(); + ld = &base; + } + + Initialize_Decoder(); + + ret = Decode_Bitstream(); + + //close(base.Infile); + + if ( Two_Streams ) + { + abort(); + close(enhan.Infile); + } + + return ret; +} + +} // end namespace gdcm diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmOrientation.cxx b/Utilities/ITK/Utilities/gdcm/src/gdcmOrientation.cxx new file mode 100644 index 0000000000000000000000000000000000000000..da703f192cdeccb2af486d8270542aa667493ef7 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmOrientation.cxx @@ -0,0 +1,698 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmOrientation.cxx,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:39 $ + Version: $Revision: 1.3 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#include "gdcmOrientation.h" +#include "gdcmFile.h" +#include "gdcmDebug.h" +#include <math.h> // for sqrt + +namespace gdcm +{ +//-------------------------------------------------------------------- +// THERALYS Algorithm to determine the most similar basic orientation +// +// Transliterated from original Python code. +// Kept as close as possible to the original code +// in order to speed up any further modif of Python code :-( +//----------------------------------------------------------------------- + +/** + * \brief THERALYS' Algorithm to determine the most similar basic orientation + * (Axial, Coronal, Sagital) of the image + * \note Should be run on the first gdcm::File of a 'coherent' Serie + * @return orientation code + * # 0 : Not Applicable (neither 0020,0037 Image Orientation Patient + * # nor 0020,0032 Image Position found) + * # 1 : Axial + * # -1 : Axial invert + * # 2 : Coronal + * # -2 : Coronal invert + * # 3 : Sagital + * # -3 : Sagital invert + * # 4 : Heart Axial + * # -4 : Heart Axial invert + * # 5 : Heart Coronal + * # -5 : Heart Coronal invert + * # 6 : Heart Sagital + * # -6 : Heart Sagital invert + */ + +static const char *OrientationTypeStrings[] = { + "Not Applicable", + "Axial", + "Coronal", + "Sagital", + "Heart Axial", + "Heart Coronal", + "Heart Sagital", + "Axial invert", + "Coronal invert", + "Sagital invert", + "Heart Axial invert", + "Heart Coronal invert", + "Heart Sagital invert", + NULL +}; + +/// \brief returns human readable interpretation of the most +/// similar basic orientation (Axial, Coronal, Sagital, ...) of the image +const char* Orientation::GetOrientationTypeString(OrientationType const o) +{ + int k = (int)o; + if (k < 0) + k = -k + 6; + + return OrientationTypeStrings[k]; +} + +/// \brief returns of the most similar basic orientation +/// (Axial, Coronal, Sagital, ...) of the image +OrientationType Orientation::GetOrientationType( File *f ) +{ + float iop[6]; + bool succ = f->GetImageOrientationPatient( iop ); + if ( !succ ) + { + gdcmErrorMacro( "No Image Orientation (0020,0037)/(0020,0032) found in the file, cannot proceed." ) + return NotApplicable; + } + vector3D ori1; + vector3D ori2; + + ori1.x = iop[0]; ori1.y = iop[1]; ori1.z = iop[2]; + ori2.x = iop[3]; ori2.y = iop[4]; ori2.z = iop[5]; + + // two perpendicular vectors describe one plane + double dicPlane[6][2][3] = + { { { 1, 0, 0 },{ 0, 1, 0 } }, // Axial + { { 1, 0, 0 },{ 0, 0, -1 } }, // Coronal + { { 0, 1, 0 },{ 0, 0, -1 } }, // Sagittal + { { 0.8, 0.5, 0.0 },{-0.1, 0.1 , -0.95 } }, // Axial - HEART + { { 0.8, 0.5, 0.0 },{-0.6674, 0.687, 0.1794} }, // Coronal - HEART + { {-0.1, 0.1, -0.95},{-0.6674, 0.687, 0.1794} } // Sagittal - HEART + }; + + vector3D refA; + vector3D refB; + int i = 0; + Res res; // [ <result> , <memory of the last succes calcule> ] + res.first = 0; + res.second = 99999; + + for (int numDicPlane=0; numDicPlane<6; numDicPlane++) + { + ++i; + // refA=plane[0] + refA.x = dicPlane[numDicPlane][0][0]; + refA.y = dicPlane[numDicPlane][0][1]; + refA.z = dicPlane[numDicPlane][0][2]; + // refB=plane[1] + refB.x = dicPlane[numDicPlane][1][0]; + refB.y = dicPlane[numDicPlane][1][1]; + refB.z = dicPlane[numDicPlane][1][2]; + res=VerfCriterion( i, CalculLikelyhood2Vec(refA,refB,ori1,ori2), res ); + res=VerfCriterion( -i, CalculLikelyhood2Vec(refB,refA,ori1,ori2), res ); + } + // res thought looks like is a float value, but is indeed an int + // try casting it to int first then enum value to please VS7: + int int_res = (int)res.first; + gdcmAssertMacro( int_res <= 6 && int_res >= -6); + return (OrientationType)int_res; +} + +Res +Orientation::VerfCriterion(int typeCriterion, double criterionNew, Res const &in) +{ + Res res; + double type = in.first; + double criterion = in.second; + if (/*criterionNew < 0.1 && */criterionNew < criterion) + { + type = typeCriterion; + criterion = criterionNew; + } + res.first = type; + res.second = criterion; + return res; +} + +inline double square_dist(vector3D const &v1, vector3D const &v2) +{ + double res; + res = (v1.x - v2.x)*(v1.x - v2.x) + + (v1.y - v2.y)*(v1.y - v2.y) + + (v1.z - v2.z)*(v1.z - v2.z); + return res; +} + +//------------------------- Purpose : ----------------------------------- +//- This function determines the orientation similarity of two planes. +// Each plane is described by two vectors. +//------------------------- Parameters : -------------------------------- +//- <refA> : - type : vector 3D (double) +//- <refB> : - type : vector 3D (double) +// - Description of the first plane +//- <ori1> : - type : vector 3D (double) +//- <ori2> : - type : vector 3D (double) +// - Description of the second plane +//------------------------- Return : ------------------------------------ +// double : 0 if the planes are perpendicular. While the difference of +// the orientation between the planes are big more enlarge is +// the criterion. +//------------------------- Other : ------------------------------------- +// The calculus is based with vectors normalice +double +Orientation::CalculLikelyhood2Vec(vector3D const &refA, vector3D const &refB, + vector3D const &ori1, vector3D const &ori2 ) +{ + + vector3D ori3 = ProductVectorial(ori1,ori2); + vector3D refC = ProductVectorial(refA,refB); + double res = square_dist(refC, ori3); + + return sqrt(res); +} + +//------------------------- Purpose : ----------------------------------- +//- Calculus of the poduct vectorial between two vectors 3D +//------------------------- Parameters : -------------------------------- +//- <vec1> : - type : vector 3D (double) +//- <vec2> : - type : vector 3D (double) +//------------------------- Return : ------------------------------------ +// (vec) : - Vector 3D +//------------------------- Other : ------------------------------------- +vector3D +Orientation::ProductVectorial(vector3D const &vec1, vector3D const &vec2) +{ + vector3D vec3; + vec3.x = vec1.y*vec2.z - vec1.z*vec2.y; + vec3.y = -( vec1.x*vec2.z - vec1.z*vec2.x); + vec3.z = vec1.x*vec2.y - vec1.y*vec2.x; + + return vec3; +} + + + +// --------------------------------------------------------------------------- +// Here is the original Python code, kindly supplied by THERALYS +// +// C++ code doesn't give good results +// --> FIXME + +/* + +def TypeOrientation(self,file0): +""" +# ------------------------- Purpose : ----------------------------------- +# - This function compare the orientation of the given image and the +# basics orientations (Axial, Cornal, Sagital) +# ------------------------- Parameters : -------------------------------- +# - <file0> : - type : string +# - The name of the first image file of the serie +# ------------------------- Return : ------------------------------------ +# 1 : Axial +# -1 : Axial invert +# 2 : Coronal +# -2 : Coronal invert +# 3 : Sagital +# -3 : Sagital invert +# 4 : Heart Axial +# -4 : Heart Axial invert +# 5 : Heart Coronal +# -5 : Heart Coronal invert +# 6 : Heart Sagital +# -6 : Heart Sagital invert +# + # ------------------------- Other : ------------------------------------- +# This method finds the most similar basic orientation. +""" +try: + toRead = gdcm.File(file0) + ValDict = GetValuesDict(toRead) + try: + imageOrientation=ValDict["Image Orientation (Patient)"] + except KeyError: + imageOrientation=ValDict["Image Orientation"] + + ori1=[float(split(imageOrientation,"\\")[0]),\ + float(split(imageOrientation,"\\")[1]),\ + float(split(imageOrientation,"\\")[2])] + ori2=[float(split(imageOrientation,"\\")[3]),\ + float(split(imageOrientation,"\\")[4]),\ + float(split(imageOrientation,"\\")[5])] + +## two vectors perpendicular describe one plane + dicPlane=[ [ [1,0,0],[0,1,0] ], ## Axial + [ [1,0,0],[0,0,-1] ], ## Coronal + [ [0,1,0],[0,0,-1] ], ## Sagittal + [ [ 0.8 , 0.5 , 0.0 ],[-0.1 , 0.1 , -0.95] ],## Axial - HEART + [ [ 0.8 , 0.5 , 0.0 ],[-0.6674 , 0.687 , 0.1794] ],## Coronal - HEART + [ [-0.1 , 0.1 , -0.95],[-0.6674 , 0.687 , 0.1794] ] ] ## Sagittal - HEART + + i=0 + res=[0,99999] ## [ <result> , <memory of the last succes calcule> ] + for plane in dicPlane: + i=i+1 + refA=plane[0] + refB=plane[1] + res=self.VerfCriterion( i , self.CalculLikelyhood2Vec(refA,refB,ori1,ori2) , res ) + res=self.VerfCriterion( -i , self.CalculLikelyhood2Vec(refB,refA,ori1,ori2) , res ) + return res[0] + + except KeyError: + return 0 + + + def VerfCriterion(self,typeCriterion,criterionNew,res): + type = res[0] + criterion = res[1] +# if criterionNew<0.1 and criterionNew<criterion: + if criterionNew<criterion: + criterion=criterionNew + type=typeCriterion + return [ type , criterion ] + + + def CalculLikelyhood2Vec(self,refA,refB,ori1,ori2): +""" + # ------------------------- Purpose : ----------------------------------- + # - This function determine the orientation similarity of two planes. + # Each plane is described by two vector. + # ------------------------- Parameters : -------------------------------- + # - <refA> : - type : vector 3D (float) + # - <refB> : - type : vector 3D (float) + # - Description of the first plane + # - <ori1> : - type : vector 3D (float) + # - <ori2> : - type : vector 3D (float) + # - Description of the second plane + # ------------------------- Return : ------------------------------------ + # float : 0 if the planes are perpendicular. + # While the difference of the orientation between the planes + # are big more enlarge is + # the criterion. + # ------------------------- Other : ------------------------------------- + # The calculus is based with vectors normalice + """ + + ori3=self.ProductVectorial(ori1,ori2) + refC=self.ProductVectorial(refA,refB) + res=math.pow(refC[0]-ori3[0],2) + math.pow(refC[1]-ori3[1],2) + math.pow(refC[2]-ori3[2],2) + return math.sqrt(res) + + def ProductVectorial(self,vec1,vec2): + """ + # ------------------------- Purpose : ----------------------------------- + # - Calculus of the poduct vectorial between two vectors 3D + # ------------------------- Parameters : -------------------------------- + # - <vec1> : - type : vector 3D (float) + # - <vec2> : - type : vector 3D (float) + # ------------------------- Return : ------------------------------------ + # (vec) : - Vector 3D + # ------------------------- Other : ------------------------------------- + """ + vec3=[0,0,0] + vec3[0]=vec1[1]*vec2[2] - vec1[2]*vec2[1] + vec3[1]=-( vec1[0]*vec2[2] - vec1[2]*vec2[0]) + vec3[2]=vec1[0]*vec2[1] - vec1[1]*vec2[0] + return vec3 + + def GetValuesDict(image): + """ + Returns a dictionnary containing values associated with Field Names + dict["Dicom Field Name"]="Dicom field value" + """ + val=image.GetFirstEntry() + dic={} + while(val): + if isinstance(val,gdcm.ValEntryPtr): + dic[val.GetName()]=val.GetValue() + val=image.GetNextEntry() + return dic + +*/ + + +// ------------------------------------------------------------------------ +/* +2.2.2 Orientation of DICOM images + + +http://www.dclunie.com/medical-image-faq/html/part2.html#DICOMOrientation +says : + +A question that is frequently asked in comp.protocols.dicom is how to determine + which side of an image is which (e.g. left, right) and so on. + The short answer is that for projection radiographs this is specified + explicitly using the "Patient Orientation" attribute, and for cross-sectional + images it needs to be derived from the "Image Orientation (Patient)" direction + cosines. In the standard these are explained as follows: + + * "C.7.6.1.1.1 Patient Orientation. + The Patient Orientation (0020,0020) relative to the image + plane shall be specified by two values that designate the + anatomical direction of the positive row axis (left to right) + and the positive column axis (top to bottom). + The first entry is the direction of the rows, given by the + direction of the last pixel in the first row from the first + pixel in that row. + The second entry is the direction of the columns, given by + the direction of the last pixel in the first column from the + first pixel in that column. + Anatomical direction shall be designated by the capital + letters: A (anterior), P (posterior), R (right),L (left), + H (head), F (foot). + Each value of the orientation attribute shall contain at + least one of these characters. + If refinements in the orientation descriptions are to be + specified, then they shall be designated by one or two + additional letters in each value. + Within each value, the letters shall be ordered with the + principal orientation designated in the first character." + + * "C.7.6.2.1.1 Image Position And Image Orientation. + The "Image Position (Patient)" (0020,0032) specifies the x, y, + and z coordinates of the upper left hand corner of the image; + it is the center of the first voxel transmitted. + The "Image Orientation (Patient)" (0020,0037) specifies the + direction cosines of the first row and the first column + with respect to the patient. + These Attributes shall be provided as a pair. + Row value for the x, y, and z axes respectively followed by + the Column value for the x, y, and z axes respectively. + The direction of the axes is defined fully by the patient's + orientation. + The x-axis is increasing to the left hand side of the patient. + The y-axis is increasing to the posterior side of the patient. + The z-axis is increasing toward the head of the patient. + The patient based coordinate system is a right handed system, + i.e. the vector cross product of a unit vector along the + positive x-axis and a unit vector along the positive y-axis + is equal to a unit vector along the positive z-axis." + +Some simple code to take one of the direction cosines (vectors) from the +Image Orientation (Patient) attribute and generate strings equivalent to one +of the values of Patient Orientation looks like this (noting that if the vector +is not aligned exactly with one of the major axes, the resulting string will +have multiple letters in as described under "refinements" in C.7.6.1.1.1): + +*/ + +/** + * \brief Computes the Patient Orientation relative to the image plane + * from the 'Image Orientation (Patient)' + * - or from 0020 0035Image Orientation (RET) - + * - The first entry is the direction of the rows, given by the + * direction of the last pixel in the first row from the first + * pixel in that row. + * - The second entry is the direction of the columns, given by + * the direction of the last pixel in the first column from the + * first pixel in that column. + * Anatomical direction is designated by the capital + * letters: A (anterior), P (posterior), R (right),L (left), + * H (head), F (foot). + * - Refinements in the orientation descriptions are designated + * by one or two additional letters in each value. + * Use it when "Patient Orientation" (0020,0020) is not found + * @return orientation string as "rowsOrientation\columnsOrientation" + */ +std::string Orientation::GetOrientation ( File *f ) +{ + float iop[6]; + if ( !f->GetImageOrientationPatient( iop ) ) + return GDCM_UNFOUND; + + std::string orientation; + orientation = GetSingleOrientation ( iop ) + + "\\" + + GetSingleOrientation ( iop + 3 ); + return orientation; +} + + +std::string Orientation::GetSingleOrientation ( float *iop) +{ + std::string orientation; + + char orientationX = iop[0] < 0 ? 'R' : 'L'; + char orientationY = iop[1] < 0 ? 'A' : 'P'; + char orientationZ = iop[2] < 0 ? 'F' : 'H'; + + double absX = iop[0]; + if (absX < 0) absX = -absX; + double absY = iop[1]; + if (absY < 0) absY = -absY; + double absZ = iop[2]; + if (absZ < 0) absZ = -absZ; + + for (int i=0; i<3; ++i) + { + if (absX>.0001 && absX>absY && absX>absZ) + { + orientation = orientation + orientationX; + absX=0; + } + else if (absY>.0001 && absY>absX && absY>absZ) + { + orientation = orientation + orientationY; + absY=0; + } + else if (absZ>.0001 && absZ>absX && absZ>absY) + { + orientation = orientation + orientationZ; + absZ=0; + } + else + break; + } + return orientation; +} + + +/*------------------------------------------------------------------- + +Some more stuff, from XMedcon + +---> Personal remark from JPRx : +--> patient_position (0x0018,0x5100) can be "HFS ", "FFS ", "HFP ", "FFP " +--> or, not so common, +// HFDR = Head First-Decubitus Right +// HFDL = Head First-Decubitus Left +// FFDR = Feet First-Decubitus Right +// FFDL = Feet First-Decubitus Left +--> the cosines may have any value -1.< <+1., for MR images ! + +enum patient_slice_orientation_type + { + patient_slice_orientation_unknown = 0, + supine_headfirst_transaxial, + supine_headfirst_sagittal, + supine_headfirst_coronal, + supine_feetfirst_transaxial, + supine_feetfirst_sagittal, + supine_feetfirst_coronal, + prone_headfirst_transaxial, + prone_headfirst_sagittal, + prone_headfirst_coronal, + prone_feetfirst_transaxial, + prone_feetfirst_sagittal, + prone_feetfirst_coronal + }; + +void GetImageOrientationPatient(gdcm::File &h,F32 image_orientation_patient[6]) +{ + h.GetImageOrientationPatient(image_orientation_patient); +} + +#if 0 +// +// this is all completely cribbed from the xmedcon library, since +// we're trying to do what it does, mostly. +patient_slice_orientation_type +GetPatSliceOrient(gdcm::File &h) +{ + F32 image_orientation_patient[6]; + + // protected, do it the hard way + // h.GetImageOrientationPatient(image_orientation_patient); + GetImageOrientationPatient(h,image_orientation_patient); + + enum { headfirst, feetfirst } patient_orientation; + enum { supine, prone } patient_rotation; + enum { transaxial, sagittal, coronal } slice_orientation; + + std::string patient_position = h.GetEntryByNumber(0x0018,0x5100); + if(patient_position == "gdcm::Unfound") + { + patient_position = "HF"; + } + if(patient_position.find("HF") != std::string::npos) + { + patient_orientation = headfirst; + } + else if(patient_position.find("FF") != std::string::npos) + { + patient_orientation = feetfirst; + } + + if(patient_position.find("S") != std::string::npos) + { + patient_rotation = supine; + } + else if(patient_position.find("P") != std::string::npos) + { + patient_rotation = prone; + } + + if((image_orientation_patient[0] == 1 || image_orientation_patient[0] == -1) && + (image_orientation_patient[4] == +1 || image_orientation_patient[4] == -1)) + { + slice_orientation = transaxial; + } + else if((image_orientation_patient[1] == 1 || image_orientation_patient[1] == -1) && + (image_orientation_patient[5] == +1 || image_orientation_patient[5] == -1)) + { + slice_orientation = sagittal; + } + else if((image_orientation_patient[0] == 1 || image_orientation_patient[0] == -1) && + (image_orientation_patient[5] == +1 || image_orientation_patient[5] == -1)) + { + slice_orientation = coronal; + } + // + // combine results + patient_slice_orientation_type patient_slice_orientation = + patient_slice_orientation_unknown; + switch (patient_rotation) + { + case supine: + switch (patient_orientation) + { + case headfirst: + switch (slice_orientation) + { + case transaxial: + patient_slice_orientation = supine_headfirst_transaxial; + break; + case sagittal: + patient_slice_orientation = supine_headfirst_sagittal; + break; + case coronal: + patient_slice_orientation = supine_headfirst_coronal; + break; + } + break; + case feetfirst: + switch (slice_orientation) + { + case transaxial: + patient_slice_orientation = supine_feetfirst_transaxial; + break; + case sagittal: + patient_slice_orientation = supine_feetfirst_sagittal; + break; + case coronal: + patient_slice_orientation = supine_feetfirst_coronal; + break; + } + break; + } + break; + case prone: + switch (patient_orientation) + { + case headfirst: + switch (slice_orientation) + { + case transaxial: + patient_slice_orientation = prone_headfirst_transaxial; + break; + case sagittal: + patient_slice_orientation = prone_headfirst_sagittal; + break; + case coronal: + patient_slice_orientation = prone_headfirst_coronal; + break; + } + break; + case feetfirst: + switch (slice_orientation) + { + case transaxial: + patient_slice_orientation = prone_feetfirst_transaxial; + break; + case sagittal: + patient_slice_orientation = prone_feetfirst_sagittal; + break; + case coronal: + patient_slice_orientation = prone_feetfirst_coronal; + break; + } + break; + } + break; + } + if(patient_slice_orientation != patient_slice_orientation_unknown) + return patient_slice_orientation; + // + // this is what xmedcon does + if ((image_orientation_patient[0] == +1) && + (image_orientation_patient[4] == +1)) + patient_slice_orientation = supine_headfirst_transaxial; + else if ((image_orientation_patient[0] == -1) && + (image_orientation_patient[4] == +1)) + patient_slice_orientation = supine_feetfirst_transaxial; + else if ((image_orientation_patient[0] == -1) && + (image_orientation_patient[4] == -1)) + patient_slice_orientation = prone_headfirst_transaxial; + else if ((image_orientation_patient[0] == +1) && + (image_orientation_patient[4] == -1)) + patient_slice_orientation = prone_feetfirst_transaxial; + + else if ((image_orientation_patient[1] == +1) && + (image_orientation_patient[5] == -1)) + patient_slice_orientation = supine_headfirst_sagittal; + else if ((image_orientation_patient[1] == +1) && + (image_orientation_patient[5] == +1)) + patient_slice_orientation = supine_feetfirst_sagittal; + else if ((image_orientation_patient[1] == -1) && + (image_orientation_patient[5] == -1)) + patient_slice_orientation = prone_headfirst_sagittal; + else if ((image_orientation_patient[1] == -1) && + (image_orientation_patient[5] == +1)) + patient_slice_orientation = prone_feetfirst_sagittal; + + else if ((image_orientation_patient[0] == +1) && + (image_orientation_patient[5] == -1)) + patient_slice_orientation = supine_headfirst_coronal; + else if ((image_orientation_patient[0] == -1) && + (image_orientation_patient[5] == +1)) + patient_slice_orientation = supine_feetfirst_coronal; + else if ((image_orientation_patient[0] == -1) && + (image_orientation_patient[5] == -1)) + patient_slice_orientation = prone_headfirst_coronal; + else if ((image_orientation_patient[0] == +1) && + (image_orientation_patient[5] == +1)) + patient_slice_orientation = prone_feetfirst_coronal; + return patient_slice_orientation; +} +#else + +-------------------------------------------------------------------------*/ + +} // end namespace gdcm diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmOrientation.h b/Utilities/ITK/Utilities/gdcm/src/gdcmOrientation.h new file mode 100644 index 0000000000000000000000000000000000000000..0002acc70237dca3a993197318fcb76aae75029e --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmOrientation.h @@ -0,0 +1,118 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmOrientation.h,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:39 $ + Version: $Revision: 1.3 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#ifndef GDCMORIENTATION_H +#define GDCMORIENTATION_H + +#include "gdcmBase.h" +#include <map> + +namespace gdcm +{ +typedef struct +{ + double x; + double y; + double z; +} vector3D; + +typedef std::pair<double, double> Res; +class File; + +typedef enum { + NotApplicable = 0, + Axial = 1, + AxialInvert = -1, + Coronal = 2, + CoronalInvert = -2, + Sagital = 3, + SagitalInvert = -3, + HeartAxial = 4, + HeartAxialInvert = -4, + HeartCoronal = 5, + HeartCoronalInvert = -5, + HeartSagital = 6, + HeartSagitalInvert = -6 +} OrientationType; + +//----------------------------------------------------------------------------- +/** + * \brief Orientation class for dealing with DICOM image orientation + * + * A gentle reminder for non-medical user: + * PatientPosition (0x0010,0x5100) tells us the way the patient was introduced in the imager + * - HFS : Head First Supine + * - FFS : Feet First Supine + * - HFP : Head First Prone + * - FFP : Feet First Prone + * Note: HFP and FFP are not very common values, since the position must + * be pretty unconfortable for the Patient -the patient is lying on his belly; but, if he has handcuffs there is no other way ...- + * + * ImageOrientationPatient (0x0020,0x0037) gives 6 cosines (2 for each plane) + * Patient Orientation (as found in the optional 0x0020,0x0020, or computed by + * std::string Orientation::GetOrientation ( File *f ), tells us about the direction of X and Y axes. + * + * The values can be + * - A/P anterior/posterior + * - L/R left/right + * - H/F head/feet + * One can see it as "values within a 'Patient referential". + * + * Example #1: + * Imagine the patient, in "HFS" position. + * Full body sagital images are requested. + * All the cosines will be -1, 0, or +1; + * "Patient Orientation" (deduced) will be "A/F". + * Positive X axis is oriented 'towards patient's nose + * Positive Y axis is oriented 'towards patient's feet + * + * Example #2: + * Imagine now that patient has a stiffneck and his head is *turned* 30 degrees towards the left. + * Head sagital images are requested. + * One of the cosines will be almost 0.5 + * Deduced "Patient Orientation" will be "AL\F" + * (main X axis orientation is towards patient's nose, and a little bit towards the left) + * but the image looks *perfectly* sagital (for the head, not for the patient) ! + * + * Imagine the patient's stiffneck causes head to be *bended* 30 degrees towards the left AND *turned* left. + * Sagital images are requested... + * You'll probabely have 3 letters for X axis and Y axis, and the image remains *perfectly* sagital ! + * The values are given within the 'Patient referential', *not* within the 'Organ referential' ... + */ + +class GDCM_EXPORT Orientation : public Base +{ +public: + Orientation() {} + ~Orientation() {} + + OrientationType GetOrientationType( File *file ); + std::string GetOrientation ( File *file ); + + static const char* GetOrientationTypeString(OrientationType const o); + +private: + Res VerfCriterion(int typeCriterion, double criterionNew, Res const &res); + double CalculLikelyhood2Vec(vector3D const &refA, vector3D const &refB, + vector3D const &ori1, vector3D const &ori2); + vector3D ProductVectorial(vector3D const &vec1, vector3D const &vec2); + std::string GetSingleOrientation ( float *iop); +}; +} // end namespace gdcm +//----------------------------------------------------------------------------- +#endif diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmPixelReadConvert.cxx b/Utilities/ITK/Utilities/gdcm/src/gdcmPixelReadConvert.cxx new file mode 100644 index 0000000000000000000000000000000000000000..6f73af3275d4904b8d650e878890e84c556196d8 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmPixelReadConvert.cxx @@ -0,0 +1,1508 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmPixelReadConvert.cxx,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:39 $ + Version: $Revision: 1.6 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#include "gdcmPixelReadConvert.h" +#include "gdcmDebug.h" +#include "gdcmFile.h" +#include "gdcmGlobal.h" +#include "gdcmTS.h" +#include "gdcmDocEntry.h" +#include "gdcmRLEFramesInfo.h" +#include "gdcmJPEGFragmentsInfo.h" + +#include <fstream> +#include <stdio.h> //for sscanf + +#if defined(__BORLANDC__) + #include <mem.h> // for memset +#endif + +namespace gdcm +{ + +//bool ReadMPEGFile (std::ifstream *fp, void *image_buffer, size_t lenght); +bool gdcm_read_JPEG2000_file (void* raw, + char *inputdata, size_t inputlength); +//----------------------------------------------------------------------------- +#define str2num(str, typeNum) *((typeNum *)(str)) + +//----------------------------------------------------------------------------- +// Constructor / Destructor +/// Constructor +PixelReadConvert::PixelReadConvert() +{ + RGB = 0; + RGBSize = 0; + Raw = 0; + RawSize = 0; + LutRGBA = 0; + LutRedData = 0; + LutGreenData = 0; + LutBlueData = 0; + RLEInfo = 0; + JPEGInfo = 0; + UserFunction = 0; + FileInternal = 0; +} + +/// Canonical Destructor +PixelReadConvert::~PixelReadConvert() +{ + Squeeze(); +} + +//----------------------------------------------------------------------------- +// Public +/** + * \brief Predicate to know whether the image[s] (once Raw) is RGB. + * \note See comments of \ref ConvertHandleColor + */ +bool PixelReadConvert::IsRawRGB() +{ + if ( IsMonochrome + || PlanarConfiguration == 2 + || IsPaletteColor ) + { + return false; + } + return true; +} +/** + * \brief Gets various usefull informations from the file header + * @param file gdcm::File pointer + */ +void PixelReadConvert::GrabInformationsFromFile( File *file ) +{ + // Number of Bits Allocated for storing a Pixel is defaulted to 16 + // when absent from the file. + BitsAllocated = file->GetBitsAllocated(); + if ( BitsAllocated == 0 ) + { + BitsAllocated = 16; + } + + // Number of "Bits Stored", defaulted to number of "Bits Allocated" + // when absent from the file. + BitsStored = file->GetBitsStored(); + if ( BitsStored == 0 ) + { + BitsStored = BitsAllocated; + } + + // High Bit Position, defaulted to "Bits Allocated" - 1 + HighBitPosition = file->GetHighBitPosition(); + if ( HighBitPosition == 0 ) + { + HighBitPosition = BitsAllocated - 1; + } + + XSize = file->GetXSize(); + YSize = file->GetYSize(); + ZSize = file->GetZSize(); + SamplesPerPixel = file->GetSamplesPerPixel(); + //PixelSize = file->GetPixelSize(); Useless + PixelSign = file->IsSignedPixelData(); + SwapCode = file->GetSwapCode(); + + IsPrivateGETransferSyntax = IsMPEG + = IsJPEG2000 = IsJPEGLS = IsJPEGLossy + = IsJPEGLossless = IsRLELossless + = false; + + std::string ts = file->GetTransferSyntax(); + IsRaw = + ( ! file->IsDicomV3() ) + || Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::ImplicitVRLittleEndian + || Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::ImplicitVRBigEndianPrivateGE + || Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::ExplicitVRLittleEndian + || Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::ExplicitVRBigEndian + || Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::DeflatedExplicitVRLittleEndian; + + IsMPEG = Global::GetTS()->IsMPEG(ts); + IsJPEG2000 = Global::GetTS()->IsJPEG2000(ts); + IsJPEGLS = Global::GetTS()->IsJPEGLS(ts); + IsJPEGLossy = Global::GetTS()->IsJPEGLossy(ts); + IsJPEGLossless = Global::GetTS()->IsJPEGLossless(ts); + IsRLELossless = Global::GetTS()->IsRLELossless(ts); + + PixelOffset = file->GetPixelOffset(); + PixelDataLength = file->GetPixelAreaLength(); + RLEInfo = file->GetRLEInfo(); + JPEGInfo = file->GetJPEGInfo(); + + IsMonochrome = file->IsMonochrome(); + IsMonochrome1 = file->IsMonochrome1(); + IsPaletteColor = file->IsPaletteColor(); + IsYBRFull = file->IsYBRFull(); + + PlanarConfiguration = file->GetPlanarConfiguration(); + + ///////////////////////////////////////////////////////////////// + // LUT section: + HasLUT = file->HasLUT(); + if ( HasLUT ) + { + // Just in case some access to a File element requires disk access. + LutRedDescriptor = file->GetEntryValue( 0x0028, 0x1101 ); + LutGreenDescriptor = file->GetEntryValue( 0x0028, 0x1102 ); + LutBlueDescriptor = file->GetEntryValue( 0x0028, 0x1103 ); + + // FIXME : The following comment is probabely meaningless, since LUT are *always* + // loaded at parsing time, whatever their length is. + + // Depending on the value of Document::MAX_SIZE_LOAD_ELEMENT_VALUE + // [ refer to invocation of Document::SetMaxSizeLoadEntry() in + // Document::Document() ], the loading of the value (content) of a + // [Bin|Val]Entry occurence migth have been hindered (read simply NOT + // loaded). Hence, we first try to obtain the LUTs data from the file + // and when this fails we read the LUTs data directly from disk. + // \TODO Reading a [Bin|Val]Entry directly from disk is a kludge. + // We should NOT bypass the [Bin|Val]Entry class. Instead + // an access to an UNLOADED content of a [Bin|Val]Entry occurence + // (e.g. BinEntry::GetBinArea()) should force disk access from + // within the [Bin|Val]Entry class itself. The only problem + // is that the [Bin|Val]Entry is unaware of the FILE* is was + // parsed from. Fix that. FIXME. + + // //// Red round + file->LoadEntryBinArea(0x0028, 0x1201); + LutRedData = (uint8_t*)file->GetEntryBinArea( 0x0028, 0x1201 ); + if ( ! LutRedData ) + { + gdcmWarningMacro("Unable to read Red Palette Color Lookup Table data"); + } + + // //// Green round: + file->LoadEntryBinArea(0x0028, 0x1202); + LutGreenData = (uint8_t*)file->GetEntryBinArea(0x0028, 0x1202 ); + if ( ! LutGreenData) + { + gdcmWarningMacro("Unable to read Green Palette Color Lookup Table data"); + } + + // //// Blue round: + file->LoadEntryBinArea(0x0028, 0x1203); + LutBlueData = (uint8_t*)file->GetEntryBinArea( 0x0028, 0x1203 ); + if ( ! LutBlueData ) + { + gdcmWarningMacro("Unable to read Blue Palette Color Lookup Table data"); + } + } + FileInternal = file; + + ComputeRawAndRGBSizes(); +} + +/// \brief Reads from disk and decompresses Pixels +bool PixelReadConvert::ReadAndDecompressPixelData( std::ifstream *fp ) +{ + // ComputeRawAndRGBSizes is already made by + // ::GrabInformationsFromfile. So, the structure sizes are + // correct + Squeeze(); + + ////////////////////////////////////////////////// + //// First stage: get our hands on the Pixel Data. + if ( !fp ) + { + gdcmWarningMacro( "Unavailable file pointer." ); + return false; + } + + fp->seekg( PixelOffset, std::ios::beg ); + if ( fp->fail() || fp->eof() ) + { + gdcmWarningMacro( "Unable to find PixelOffset in file." ); + return false; + } + + AllocateRaw(); + + ////////////////////////////////////////////////// + //// Second stage: read from disk and decompress. + if ( BitsAllocated == 12 ) // We suppose 'BitsAllocated' = 12 only exist for uncompressed files + { + ReadAndDecompress12BitsTo16Bits( fp); + } + else if ( IsRaw ) + { + // This problem can be found when some obvious informations are found + // after the field containing the image data. In this case, these + // bad data are added to the size of the image (in the PixelDataLength + // variable). But RawSize is the right size of the image ! + if ( PixelDataLength != RawSize ) + { + gdcmWarningMacro( "Mismatch between PixelReadConvert : " + << PixelDataLength << " and RawSize : " << RawSize ); + } + if ( PixelDataLength > RawSize ) + { + fp->read( (char*)Raw, RawSize); + } + else + { + fp->read( (char*)Raw, PixelDataLength); + } + + if ( fp->fail() || fp->eof()) + { + gdcmWarningMacro( "Reading of Raw pixel data failed." ); + return false; + } + } + else if ( IsRLELossless ) + { + if ( ! RLEInfo->DecompressRLEFile + ( fp, Raw, XSize, YSize, ZSize, BitsAllocated ) ) + { + gdcmWarningMacro( "RLE decompressor failed." ); + return false; + } + } + else if ( IsMPEG ) + { + //gdcmWarningMacro( "Sorry, MPEG not yet taken into account" ); + //return false; + // fp has already been seek to start of mpeg + //ReadMPEGFile(fp, (char*)Raw, PixelDataLength); + return true; + } + else + { + // Default case concerns JPEG family + if ( ! ReadAndDecompressJPEGFile( fp ) ) + { + gdcmWarningMacro( "JPEG decompressor ( ReadAndDecompressJPEGFile()" + << " method ) failed." ); + return false; + } + } + + //////////////////////////////////////////// + //// Third stage: twigle the bytes and bits. + ConvertReorderEndianity(); + ConvertReArrangeBits(); + ConvertFixGreyLevels(); + if (UserFunction) // user is allowed to Mirror, TopDown, Rotate,...the image + UserFunction( Raw, FileInternal); + ConvertHandleColor(); + + return true; +} + +/// Deletes Pixels Area +void PixelReadConvert::Squeeze() +{ + if ( RGB ) + delete [] RGB; + RGB = 0; + + if ( Raw ) + delete [] Raw; + Raw = 0; + + if ( LutRGBA ) + delete [] LutRGBA; + LutRGBA = 0; +} + +/** + * \brief Build the RGB image from the Raw image and the LUTs. + */ +bool PixelReadConvert::BuildRGBImage() +{ + if ( RGB ) + { + // The job is already done. + return true; + } + + if ( ! Raw ) + { + // The job can't be done + return false; + } + + BuildLUTRGBA(); + if ( ! LutRGBA ) + { + // The job can't be done + return false; + } + + gdcmDebugMacro( "--> BuildRGBImage" ); + + // Build RGB Pixels + AllocateRGB(); + + int j; + if ( BitsAllocated <= 8 ) + { + uint8_t *localRGB = RGB; + for (size_t i = 0; i < RawSize; ++i ) + { + j = Raw[i] * 4; + *localRGB++ = LutRGBA[j]; + *localRGB++ = LutRGBA[j+1]; + *localRGB++ = LutRGBA[j+2]; + } + } + + else // deal with 16 bits pixels and 16 bits Palette color + { + uint16_t *localRGB = (uint16_t *)RGB; + for (size_t i = 0; i < RawSize/2; ++i ) + { + j = ((uint16_t *)Raw)[i] * 4; + *localRGB++ = ((uint16_t *)LutRGBA)[j]; + *localRGB++ = ((uint16_t *)LutRGBA)[j+1]; + *localRGB++ = ((uint16_t *)LutRGBA)[j+2]; + } + } + + return true; +} + +//----------------------------------------------------------------------------- +// Protected + +//----------------------------------------------------------------------------- +// Private +/** + * \brief Read from file a 12 bits per pixel image and decompress it + * into a 16 bits per pixel image. + */ +void PixelReadConvert::ReadAndDecompress12BitsTo16Bits( std::ifstream *fp ) + throw ( FormatError ) +{ + int nbPixels = XSize * YSize; + uint16_t *localDecompres = (uint16_t*)Raw; + + for( int p = 0; p < nbPixels; p += 2 ) + { + uint8_t b0, b1, b2; + + fp->read( (char*)&b0, 1); + if ( fp->fail() || fp->eof() ) + { + throw FormatError( "PixelReadConvert::ReadAndDecompress12BitsTo16Bits()", + "Unfound first block" ); + } + + fp->read( (char*)&b1, 1 ); + if ( fp->fail() || fp->eof()) + { + throw FormatError( "PixelReadConvert::ReadAndDecompress12BitsTo16Bits()", + "Unfound second block" ); + } + + fp->read( (char*)&b2, 1 ); + if ( fp->fail() || fp->eof()) + { + throw FormatError( "PixelReadConvert::ReadAndDecompress12BitsTo16Bits()", + "Unfound second block" ); + } + + // Two steps are necessary to please VC++ + // + // 2 pixels 12bit = [0xABCDEF] + // 2 pixels 16bit = [0x0ABD] + [0x0FCE] + // A B D + *localDecompres++ = ((b0 >> 4) << 8) + ((b0 & 0x0f) << 4) + (b1 & 0x0f); + // F C E + *localDecompres++ = ((b2 & 0x0f) << 8) + ((b1 >> 4) << 4) + (b2 >> 4); + + /// \todo JPR Troubles expected on Big-Endian processors ? + } +} + +/** + * \brief Reads from disk the Pixel Data of JPEG Dicom encapsulated + * file and decompress it. + * @param fp File Pointer + * @return Boolean + */ +bool PixelReadConvert::ReadAndDecompressJPEGFile( std::ifstream *fp ) +{ + if ( IsJPEG2000 ) + { + // make sure this is the right JPEG compression + assert( !IsJPEGLossless || !IsJPEGLossy || !IsJPEGLS ); + // FIXME this is really ugly but it seems I have to load the complete + // jpeg2000 stream to use jasper: + // I don't think we'll ever be able to deal with multiple fragments properly + + unsigned long inputlength = 0; + JPEGFragment *jpegfrag = JPEGInfo->GetFirstFragment(); + while( jpegfrag ) + { + inputlength += jpegfrag->GetLength(); + jpegfrag = JPEGInfo->GetNextFragment(); + } + gdcmAssertMacro( inputlength != 0); + uint8_t *inputdata = new uint8_t[inputlength]; + char *pinputdata = (char*)inputdata; + jpegfrag = JPEGInfo->GetFirstFragment(); + while( jpegfrag ) + { + fp->seekg( jpegfrag->GetOffset(), std::ios::beg); + fp->read(pinputdata, jpegfrag->GetLength()); + pinputdata += jpegfrag->GetLength(); + jpegfrag = JPEGInfo->GetNextFragment(); + } + // Warning the inputdata buffer is delete in the function + if ( ! gdcm_read_JPEG2000_file( Raw, + (char*)inputdata, inputlength ) ) + { + return true; + } + // wow what happen, must be an error + gdcmWarningMacro( "gdcm_read_JPEG2000_file() failed "); + return false; + } + else if ( IsJPEGLS ) + { + // make sure this is the right JPEG compression + assert( !IsJPEGLossless || !IsJPEGLossy || !IsJPEG2000 ); + // WARNING : JPEG-LS is NOT the 'classical' Jpeg Lossless : + // [JPEG-LS is the basis for new lossless/near-lossless compression + // standard for continuous-tone images intended for JPEG2000. The standard + // is based on the LOCO-I algorithm (LOw COmplexity LOssless COmpression + // for Images) developed at Hewlett-Packard Laboratories] + // + // see http://datacompression.info/JPEGLS.shtml + // +#if 0 + std::cerr << "count:" << JPEGInfo->GetFragmentCount() << std::endl; + unsigned long inputlength = 0; + JPEGFragment *jpegfrag = JPEGInfo->GetFirstFragment(); + while( jpegfrag ) + { + inputlength += jpegfrag->GetLength(); + jpegfrag = JPEGInfo->GetNextFragment(); + } + gdcmAssertMacro( inputlength != 0); + uint8_t *inputdata = new uint8_t[inputlength]; + char *pinputdata = (char*)inputdata; + jpegfrag = JPEGInfo->GetFirstFragment(); + while( jpegfrag ) + { + fp->seekg( jpegfrag->GetOffset(), std::ios::beg); + fp->read(pinputdata, jpegfrag->GetLength()); + pinputdata += jpegfrag->GetLength(); + jpegfrag = JPEGInfo->GetNextFragment(); + } + + //fp->read((char*)Raw, PixelDataLength); + + std::ofstream out("/tmp/jpegls.jpg"); + out.write((char*)inputdata, inputlength); + out.close(); + delete[] inputdata; +#endif + + gdcmWarningMacro( "Sorry, JPEG-LS not yet taken into account" ); + fp->seekg( JPEGInfo->GetFirstFragment()->GetOffset(), std::ios::beg); +// if ( ! gdcm_read_JPEGLS_file( fp,Raw ) ) + return false; + } + else + { + // make sure this is the right JPEG compression + assert( !IsJPEGLS || !IsJPEG2000 ); + // Precompute the offset localRaw will be shifted with + int length = XSize * YSize * SamplesPerPixel; + int numberBytes = BitsAllocated / 8; + + JPEGInfo->DecompressFromFile(fp, Raw, BitsStored, numberBytes, length ); + return true; + } +} + +/** + * \brief Build Red/Green/Blue/Alpha LUT from File when : + * - (0028,0004) : Photometric Interpretation == [PALETTE COLOR ] + * and + * - (0028,1101),(0028,1102),(0028,1102) + * xxx Palette Color Lookup Table Descriptor are found + * and + * - (0028,1201),(0028,1202),(0028,1202) + * xxx Palette Color Lookup Table Data - are found + * \warning does NOT deal with : + * - 0028 1100 Gray Lookup Table Descriptor (Retired) + * - 0028 1221 Segmented Red Palette Color Lookup Table Data + * - 0028 1222 Segmented Green Palette Color Lookup Table Data + * - 0028 1223 Segmented Blue Palette Color Lookup Table Data + * no known Dicom reader deals with them :-( + * @return a RGBA Lookup Table + */ +void PixelReadConvert::BuildLUTRGBA() +{ + + // Note to code reviewers : + // The problem is *much more* complicated, since a lot of manufacturers + // Don't follow the norm : + // have a look at David Clunie's remark at the end of this .cxx file. + if ( LutRGBA ) + + { + return; + } + // Not so easy : see + // http://www.barre.nom.fr/medical/dicom2/limitations.html#Color%20Lookup%20Tables + + if ( ! IsPaletteColor ) + { + return; + } + + if ( LutRedDescriptor == GDCM_UNFOUND + || LutGreenDescriptor == GDCM_UNFOUND + || LutBlueDescriptor == GDCM_UNFOUND ) + { + gdcmWarningMacro( "(At least) a LUT Descriptor is missing" ); + return; + } + + //////////////////////////////////////////// + // Extract the info from the LUT descriptors + int lengthR; // Red LUT length in Bytes + int debR; // Subscript of the first Lut Value + int nbitsR; // Lut item size (in Bits) + int nbRead; // nb of items in LUT descriptor (must be = 3) + + nbRead = sscanf( LutRedDescriptor.c_str(), + "%d\\%d\\%d", + &lengthR, &debR, &nbitsR ); + if ( nbRead != 3 ) + { + gdcmWarningMacro( "Wrong Red LUT descriptor" ); + } + int lengthG; // Green LUT length in Bytes + int debG; // Subscript of the first Lut Value + int nbitsG; // Lut item size (in Bits) + + nbRead = sscanf( LutGreenDescriptor.c_str(), + "%d\\%d\\%d", + &lengthG, &debG, &nbitsG ); + if ( nbRead != 3 ) + { + gdcmWarningMacro( "Wrong Green LUT descriptor" ); + } + + int lengthB; // Blue LUT length in Bytes + int debB; // Subscript of the first Lut Value + int nbitsB; // Lut item size (in Bits) + nbRead = sscanf( LutRedDescriptor.c_str(), + "%d\\%d\\%d", + &lengthB, &debB, &nbitsB ); + if ( nbRead != 3 ) + { + gdcmWarningMacro( "Wrong Blue LUT descriptor" ); + } + + gdcmDebugMacro(" lengthR " << lengthR << " debR " + << debR << " nbitsR " << nbitsR); + gdcmDebugMacro(" lengthG " << lengthG << " debG " + << debG << " nbitsG " << nbitsG); + gdcmDebugMacro(" lengthB " << lengthB << " debB " + << debB << " nbitsB " << nbitsB); + + if ( !lengthR ) // if = 2^16, this shall be 0 see : CP-143 + lengthR=65536; + if ( !lengthG ) // if = 2^16, this shall be 0 + lengthG=65536; + if ( !lengthB ) // if = 2^16, this shall be 0 + lengthB=65536; + + //////////////////////////////////////////////////////// + + if ( ( ! LutRedData ) || ( ! LutGreenData ) || ( ! LutBlueData ) ) + { + gdcmWarningMacro( "(At least) a LUT is missing" ); + return; + } + + // ------------------------------------------------------------- + + if ( BitsAllocated <= 8 ) + { + // forge the 4 * 8 Bits Red/Green/Blue/Alpha LUT + LutRGBA = new uint8_t[ 1024 ]; // 256 * 4 (R, G, B, Alpha) + if ( !LutRGBA ) + return; + LutItemNumber = 256; + LutItemSize = 8; + memset( LutRGBA, 0, 1024 ); + + int mult; + if ( ( nbitsR == 16 ) && ( BitsAllocated == 8 ) ) + { + // when LUT item size is different than pixel size + mult = 2; // high byte must be = low byte + } + else + { + // See PS 3.3-2003 C.11.1.1.2 p 619 + mult = 1; + } + + // if we get a black image, let's just remove the '+1' + // from 'i*mult+1' and check again + // if it works, we shall have to check the 3 Palettes + // to see which byte is ==0 (first one, or second one) + // and fix the code + // We give up the checking to avoid some (useless ?) overhead + // (optimistic asumption) + int i; + uint8_t *a; + + //take "Subscript of the first Lut Value" (debR,debG,debB) into account! + + //FIXME : +1 : to get 'low value' byte + // Trouble expected on Big Endian Processors ? + // 16 BIts Per Pixel Palette Color to be swapped? + + a = LutRGBA + 0 + debR; + for( i=0; i < lengthR; ++i ) + { + *a = LutRedData[i*mult+1]; + a += 4; + } + + a = LutRGBA + 1 + debG; + for( i=0; i < lengthG; ++i) + { + *a = LutGreenData[i*mult+1]; + a += 4; + } + + a = LutRGBA + 2 + debB; + for(i=0; i < lengthB; ++i) + { + *a = LutBlueData[i*mult+1]; + a += 4; + } + + a = LutRGBA + 3 ; + for(i=0; i < 256; ++i) + { + *a = 1; // Alpha component + a += 4; + } + } + else + { + // Probabely the same stuff is to be done for 16 Bits Pixels + // with 65536 entries LUT ?!? + // Still looking for accurate info on the web :-( + + gdcmWarningMacro( "Sorry Palette Color Lookup Tables not yet dealt with" + << " for 16 Bits Per Pixel images" ); + + // forge the 4 * 16 Bits Red/Green/Blue/Alpha LUT + + LutRGBA = (uint8_t *)new uint16_t[ 65536*4 ]; // 2^16 * 4 (R, G, B, Alpha) + if ( !LutRGBA ) + return; + memset( LutRGBA, 0, 65536*4*2 ); // 16 bits = 2 bytes ;-) + + LutItemNumber = 65536; + LutItemSize = 16; + + int i; + uint16_t *a16; + + //take "Subscript of the first Lut Value" (debR,debG,debB) into account! + + a16 = (uint16_t*)LutRGBA + 0 + debR; + for( i=0; i < lengthR; ++i ) + { + *a16 = ((uint16_t*)LutRedData)[i]; + a16 += 4; + } + + a16 = (uint16_t*)LutRGBA + 1 + debG; + for( i=0; i < lengthG; ++i) + { + *a16 = ((uint16_t*)LutGreenData)[i]; + a16 += 4; + } + + a16 = (uint16_t*)LutRGBA + 2 + debB; + for(i=0; i < lengthB; ++i) + { + *a16 = ((uint16_t*)LutBlueData)[i]; + a16 += 4; + } + + a16 = (uint16_t*)LutRGBA + 3 ; + for(i=0; i < 65536; ++i) + { + *a16 = 1; // Alpha component + a16 += 4; + } +/* Just to 'see' the LUT, at debug time +// Don't remove this commented out code. + + a16=(uint16_t*)LutRGBA; + for (int j=0;j<65536;j++) + { + std::cout << *a16 << " " << *(a16+1) << " " + << *(a16+2) << " " << *(a16+3) << std::endl; + a16+=4; + } +*/ + } +} + +/** + * \brief Swap the bytes, according to \ref SwapCode. + */ +void PixelReadConvert::ConvertSwapZone() +{ + unsigned int i; + + // If this file is 'ImplicitVR BigEndian PrivateGE Transfer Syntax', + // then the header is in little endian format and the pixel data is in + // big endian format. When reading the header, GDCM has already established + // a byte swapping code suitable for this machine to read the + // header. In TS::ImplicitVRBigEndianPrivateGE, this code will need + // to be switched in order to read the pixel data. This must be + // done REGARDLESS of the processor endianess! + // + // Example: Assume we are on a little endian machine. When + // GDCM reads the header, the header will match the machine + // endianess and the swap code will be established as a no-op. + // When GDCM reaches the pixel data, it will need to switch the + // swap code to do big endian to little endian conversion. + // + // Now, assume we are on a big endian machine. When GDCM reads the + // header, the header will be recognized as a different endianess + // than the machine endianess, and a swap code will be established + // to convert from little endian to big endian. When GDCM readers + // the pixel data, the pixel data endianess will now match the + // machine endianess. But we currently have a swap code that + // converts from little endian to big endian. In this case, we + // need to switch the swap code to a no-op. + // + // Therefore, in either case, if the file is in + // 'ImplicitVR BigEndian PrivateGE Transfer Syntax', then GDCM needs to switch + // the byte swapping code when entering the pixel data. + + int tempSwapCode = SwapCode; + if ( IsPrivateGETransferSyntax ) + { + gdcmWarningMacro(" IsPrivateGETransferSyntax found; turn the SwapCode"); + // PrivateGETransferSyntax only exists for 'true' Dicom images + // we assume there is no 'exotic' 32 bits endianess! + if (SwapCode == 1234) + { + tempSwapCode = 4321; + } + else if (SwapCode == 4321) + { + tempSwapCode = 1234; + } + } + + if ( BitsAllocated == 16 ) + { + uint16_t *im16 = (uint16_t*)Raw; + switch( tempSwapCode ) + { + case 1234: + break; + case 3412: + case 2143: + case 4321: + for( i = 0; i < RawSize / 2; i++ ) + { + im16[i]= (im16[i] >> 8) | (im16[i] << 8 ); + } + break; + default: + gdcmWarningMacro("SwapCode value (16 bits) not allowed." + << tempSwapCode); + } + } + else if ( BitsAllocated == 32 ) + { + uint32_t s32; + uint16_t high; + uint16_t low; + uint32_t *im32 = (uint32_t*)Raw; + switch ( tempSwapCode ) + { + case 1234: + break; + case 4321: + for( i = 0; i < RawSize / 4; i++ ) + { + low = im32[i] & 0x0000ffff; // 4321 + high = im32[i] >> 16; + high = ( high >> 8 ) | ( high << 8 ); + low = ( low >> 8 ) | ( low << 8 ); + s32 = low; + im32[i] = ( s32 << 16 ) | high; + } + break; + case 2143: + for( i = 0; i < RawSize / 4; i++ ) + { + low = im32[i] & 0x0000ffff; // 2143 + high = im32[i] >> 16; + high = ( high >> 8 ) | ( high << 8 ); + low = ( low >> 8 ) | ( low << 8 ); + s32 = high; + im32[i] = ( s32 << 16 ) | low; + } + break; + case 3412: + for( i = 0; i < RawSize / 4; i++ ) + { + low = im32[i] & 0x0000ffff; // 3412 + high = im32[i] >> 16; + s32 = low; + im32[i] = ( s32 << 16 ) | high; + } + break; + default: + gdcmWarningMacro("SwapCode value (32 bits) not allowed." << tempSwapCode ); + } + } +} + +/** + * \brief Deal with endianness i.e. re-arange bytes inside the integer + */ +void PixelReadConvert::ConvertReorderEndianity() +{ + if ( BitsAllocated != 8 ) + { + ConvertSwapZone(); + } + + // Special kludge in order to deal with xmedcon broken images: + if ( BitsAllocated == 16 + && BitsStored < BitsAllocated + && !PixelSign ) + { + int l = (int)( RawSize / ( BitsAllocated / 8 ) ); + uint16_t *deb = (uint16_t *)Raw; + for(int i = 0; i<l; i++) + { + if ( *deb == 0xffff ) + { + *deb = 0; + } + deb++; + } + } +} + +/** + * \brief Deal with Grey levels i.e. re-arange them + * to have low values = dark, high values = bright + */ +void PixelReadConvert::ConvertFixGreyLevels() +{ + if (!IsMonochrome1) + return; + + uint32_t i; // to please M$VC6 + int16_t j; + + if (!PixelSign) + { + if ( BitsAllocated == 8 ) + { + uint8_t *deb = (uint8_t *)Raw; + for (i=0; i<RawSize; i++) + { + *deb = 255 - *deb; + deb++; + } + return; + } + + if ( BitsAllocated == 16 ) + { + uint16_t mask =1; + for (j=0; j<BitsStored-1; j++) + { + mask = (mask << 1) +1; // will be fff when BitsStored=12 + } + + uint16_t *deb = (uint16_t *)Raw; + for (i=0; i<RawSize/2; i++) + { + *deb = mask - *deb; + deb++; + } + return; + } + } + else + { + if ( BitsAllocated == 8 ) + { + uint8_t smask8 = 255; + uint8_t *deb = (uint8_t *)Raw; + for (i=0; i<RawSize; i++) + { + *deb = smask8 - *deb; + deb++; + } + return; + } + if ( BitsAllocated == 16 ) + { + uint16_t smask16 = 65535; + uint16_t *deb = (uint16_t *)Raw; + for (i=0; i<RawSize/2; i++) + { + *deb = smask16 - *deb; + deb++; + } + return; + } + } +} + +/** + * \brief Re-arrange the bits within the bytes. + * @return Boolean always true + */ +bool PixelReadConvert::ConvertReArrangeBits() throw ( FormatError ) +{ + + if ( BitsStored != BitsAllocated ) + { + int l = (int)( RawSize / ( BitsAllocated / 8 ) ); + if ( BitsAllocated == 16 ) + { + // pmask : to mask the 'unused bits' (may contain overlays) + uint16_t pmask = 0xffff; + pmask = pmask >> ( BitsAllocated - BitsStored ); + + uint16_t *deb = (uint16_t*)Raw; + + if ( !PixelSign ) // Pixels are unsigned + { + for(int i = 0; i<l; i++) + { + *deb = (*deb >> (BitsStored - HighBitPosition - 1)) & pmask; + deb++; + } + } + else // Pixels are signed + { + // smask : to check the 'sign' when BitsStored != BitsAllocated + uint16_t smask = 0x0001; + smask = smask << ( 16 - (BitsAllocated - BitsStored + 1) ); + // nmask : to propagate sign bit on negative values + int16_t nmask = (int16_t)0x8000; + nmask = nmask >> ( BitsAllocated - BitsStored - 1 ); + + for(int i = 0; i<l; i++) + { + *deb = *deb >> (BitsStored - HighBitPosition - 1); + if ( *deb & smask ) + { + *deb = *deb | nmask; + } + else + { + *deb = *deb & pmask; + } + deb++; + } + } + } + else if ( BitsAllocated == 32 ) + { + // pmask : to mask the 'unused bits' (may contain overlays) + uint32_t pmask = 0xffffffff; + pmask = pmask >> ( BitsAllocated - BitsStored ); + + uint32_t *deb = (uint32_t*)Raw; + + if ( !PixelSign ) + { + for(int i = 0; i<l; i++) + { + *deb = (*deb >> (BitsStored - HighBitPosition - 1)) & pmask; + deb++; + } + } + else + { + // smask : to check the 'sign' when BitsStored != BitsAllocated + uint32_t smask = 0x00000001; + smask = smask >> ( 32 - (BitsAllocated - BitsStored +1 )); + // nmask : to propagate sign bit on negative values + int32_t nmask = 0x80000000; + nmask = nmask >> ( BitsAllocated - BitsStored -1 ); + + for(int i = 0; i<l; i++) + { + *deb = *deb >> (BitsStored - HighBitPosition - 1); + if ( *deb & smask ) + *deb = *deb | nmask; + else + *deb = *deb & pmask; + deb++; + } + } + } + else + { + gdcmWarningMacro("Weird image (BitsAllocated !=8, 12, 16, 32)"); + throw FormatError( "Weird image !?" ); + } + } + return true; +} + +/** + * \brief Convert (Red plane, Green plane, Blue plane) to RGB pixels + * \warning Works on all the frames at a time + */ +void PixelReadConvert::ConvertRGBPlanesToRGBPixels() +{ + gdcmWarningMacro("--> ConvertRGBPlanesToRGBPixels"); + + uint8_t *localRaw = Raw; + uint8_t *copyRaw = new uint8_t[ RawSize ]; + memmove( copyRaw, localRaw, RawSize ); + + int l = XSize * YSize * ZSize; + + uint8_t *a = copyRaw; + uint8_t *b = copyRaw + l; + uint8_t *c = copyRaw + l + l; + + for (int j = 0; j < l; j++) + { + *(localRaw++) = *(a++); + *(localRaw++) = *(b++); + *(localRaw++) = *(c++); + } + delete[] copyRaw; +} + +/** + * \brief Convert (cY plane, cB plane, cR plane) to RGB pixels + * \warning Works on all the frames at a time + */ +void PixelReadConvert::ConvertYcBcRPlanesToRGBPixels() +{ + // Remarks for YBR newbees : + // YBR_FULL works very much like RGB, i.e. three samples per pixel, + // just the color space is YCbCr instead of RGB. This is particularly useful + // for doppler ultrasound where most of the image is grayscale + // (i.e. only populates the Y components) and Cb and Cr are mostly zero, + // except for the few patches of color on the image. + // On such images, RLE achieves a compression ratio that is much better + // than the compression ratio on an equivalent RGB image. + + gdcmWarningMacro("--> ConvertYcBcRPlanesToRGBPixels"); + + uint8_t *localRaw = Raw; + uint8_t *copyRaw = new uint8_t[ RawSize ]; + memmove( copyRaw, localRaw, RawSize ); + + // to see the tricks about YBR_FULL, YBR_FULL_422, + // YBR_PARTIAL_422, YBR_ICT, YBR_RCT have a look at : + // ftp://medical.nema.org/medical/dicom/final/sup61_ft.pdf + // and be *very* affraid + // + int l = XSize * YSize; + int nbFrames = ZSize; + + uint8_t *a = copyRaw + 0; + uint8_t *b = copyRaw + l; + uint8_t *c = copyRaw + l+ l; + int32_t R, G, B; + + /// We replaced easy to understand but time consuming floating point + /// computations by the 'well known' integer computation counterpart + /// Refer to : + /// http://lestourtereaux.free.fr/papers/data/yuvrgb.pdf + /// for code optimisation. + + for ( int i = 0; i < nbFrames; i++ ) + { + for ( int j = 0; j < l; j++ ) + { + R = 38142 *(*a-16) + 52298 *(*c -128); + G = 38142 *(*a-16) - 26640 *(*c -128) - 12845 *(*b -128); + B = 38142 *(*a-16) + 66093 *(*b -128); + + R = (R+16384)>>15; + G = (G+16384)>>15; + B = (B+16384)>>15; + + if (R < 0) R = 0; + if (G < 0) G = 0; + if (B < 0) B = 0; + if (R > 255) R = 255; + if (G > 255) G = 255; + if (B > 255) B = 255; + + *(localRaw++) = (uint8_t)R; + *(localRaw++) = (uint8_t)G; + *(localRaw++) = (uint8_t)B; + a++; + b++; + c++; + } + } + delete[] copyRaw; +} + +/// \brief Deals with the color decoding i.e. handle: +/// - R, G, B planes (as opposed to RGB pixels) +/// - YBR (various) encodings. +/// - LUT[s] (or "PALETTE COLOR"). + +void PixelReadConvert::ConvertHandleColor() +{ + ////////////////////////////////// + // Deal with the color decoding i.e. handle: + // - R, G, B planes (as opposed to RGB pixels) + // - YBR (various) encodings. + // - LUT[s] (or "PALETTE COLOR"). + // + // The classification in the color decoding schema is based on the blending + // of two Dicom tags values: + // * "Photometric Interpretation" for which we have the cases: + // - [Photo A] MONOCHROME[1|2] pictures, + // - [Photo B] RGB or YBR_FULL_422 (which acts as RGB), + // - [Photo C] YBR_* (with the above exception of YBR_FULL_422) + // - [Photo D] "PALETTE COLOR" which indicates the presence of LUT[s]. + // * "Planar Configuration" for which we have the cases: + // - [Planar 0] 0 then Pixels are already RGB + // - [Planar 1] 1 then we have 3 planes : R, G, B, + // - [Planar 2] 2 then we have 1 gray Plane and 3 LUTs + // + // Now in theory, one could expect some coherence when blending the above + // cases. For example we should not encounter files belonging at the + // time to case [Planar 0] and case [Photo D]. + // Alas, this was only theory ! Because in practice some odd (read ill + // formated Dicom) files (e.g. gdcmData/US-PAL-8-10x-echo.dcm) we encounter: + // - "Planar Configuration" = 0, + // - "Photometric Interpretation" = "PALETTE COLOR". + // Hence gdcm will use the folowing "heuristic" in order to be tolerant + // towards Dicom-non-conformant files: + // << whatever the "Planar Configuration" value might be, a + // "Photometric Interpretation" set to "PALETTE COLOR" forces + // a LUT intervention >> + // + // Now we are left with the following handling of the cases: + // - [Planar 0] OR [Photo A] no color decoding (since respectively + // Pixels are already RGB and monochrome pictures have no color :), + // - [Planar 1] AND [Photo B] handled with ConvertRGBPlanesToRGBPixels() + // - [Planar 1] AND [Photo C] handled with ConvertYcBcRPlanesToRGBPixels() + // - [Planar 2] OR [Photo D] requires LUT intervention. + + gdcmDebugMacro("--> ConvertHandleColor " + << "Planar Configuration " << PlanarConfiguration ); + + if ( ! IsRawRGB() ) + { + // [Planar 2] OR [Photo D]: LUT intervention done outside + gdcmDebugMacro("--> RawRGB : LUT intervention done outside"); + return; + } + + if ( PlanarConfiguration == 1 ) + { + if ( IsYBRFull ) + { + // [Planar 1] AND [Photo C] (remember YBR_FULL_422 acts as RGB) + gdcmDebugMacro("--> YBRFull"); + ConvertYcBcRPlanesToRGBPixels(); + } + else + { + // [Planar 1] AND [Photo C] + gdcmDebugMacro("--> YBRFull"); + ConvertRGBPlanesToRGBPixels(); + } + return; + } + + // When planarConf is 0, and RLELossless (forbidden by Dicom norm) + // pixels need to be RGB-fyied anyway + + if (IsRLELossless) + { + gdcmDebugMacro("--> RLE Lossless"); + ConvertRGBPlanesToRGBPixels(); + } + + // In *normal *case, when planarConf is 0, pixels are already in RGB +} + +/// Computes the Pixels Size +void PixelReadConvert::ComputeRawAndRGBSizes() +{ + int bitsAllocated = BitsAllocated; + // Number of "Bits Allocated" is fixed to 16 when it's 12, since + // in this case we will expand the image to 16 bits (see + // \ref ReadAndDecompress12BitsTo16Bits() ) + if ( BitsAllocated == 12 ) + { + bitsAllocated = 16; + } + + RawSize = XSize * YSize * ZSize + * ( bitsAllocated / 8 ) + * SamplesPerPixel; + if ( HasLUT ) + { + RGBSize = 3 * RawSize; // works for 8 and 16 bits per Pixel + } + else + { + RGBSize = RawSize; + } +} + +/// Allocates room for RGB Pixels +void PixelReadConvert::AllocateRGB() +{ + if ( RGB ) + delete [] RGB; + RGB = new uint8_t[RGBSize]; +} + +/// Allocates room for RAW Pixels +void PixelReadConvert::AllocateRaw() +{ + if ( Raw ) + delete [] Raw; + Raw = new uint8_t[RawSize]; +} + +//----------------------------------------------------------------------------- +// Print +/** + * \brief Print self. + * @param indent Indentation string to be prepended during printing. + * @param os Stream to print to. + */ +void PixelReadConvert::Print( std::ostream &os, std::string const &indent ) +{ + os << indent + << "--- Pixel information -------------------------" + << std::endl; + os << indent + << "Pixel Data: offset " << PixelOffset + << " x(" << std::hex << PixelOffset << std::dec + << ") length " << PixelDataLength + << " x(" << std::hex << PixelDataLength << std::dec + << ")" << std::endl; + + if ( IsRLELossless ) + { + if ( RLEInfo ) + { + RLEInfo->Print( os, indent ); + } + else + { + gdcmWarningMacro("Set as RLE file but NO RLEinfo present."); + } + } + + if ( IsJPEG2000 || IsJPEGLossless || IsJPEGLossy || IsJPEGLS ) + { + if ( JPEGInfo ) + { + JPEGInfo->Print( os, indent ); + } + else + { + gdcmWarningMacro("Set as JPEG file but NO JPEGinfo present."); + } + } +} + +//----------------------------------------------------------------------------- +} // end namespace gdcm + +// Note to developpers : +// Here is a very detailled post from David Clunie, on the troubles caused +// 'non standard' LUT and LUT description +// We shall have to take it into accound in our code. +// Some day ... + + +/* +Subject: Problem with VOI LUTs in Agfa and Fuji CR and GE DX images, was Re: VOI LUT issues +Date: Sun, 06 Feb 2005 17:13:40 GMT +From: David Clunie <dclunie@dclunie.com> +Reply-To: dclunie@dclunie.com +Newsgroups: comp.protocols.dicom +References: <1107553502.040221.189550@o13g2000cwo.googlegroups.com> + +> THE LUT that comes with [my] image claims to be 16-bit, but none of the +> values goes higher than 4095. That being said, though, none of my +> original pixel values goes higher than that, either. I have read +> elsewhere on this group that when that happens you are supposed to +> adjust the LUT. Can someone be more specific? There was a thread from +> 2002 where Marco and David were mentioning doing precisely that. +> +> Thanks +> +> -carlos rodriguez + + +You have encountered the well known "we know what the standard says but +we are going to ignore it and do what we have been doing for almost +a decade regardless" CR vendor bug. Agfa started this, but they are not +the only vendor doing this now; GE and Fuji may have joined the club. + +Sadly, one needs to look at the LUT Data, figure out what the maximum +value actually encoded is, and find the next highest power of 2 (e.g. +212 in this case), to figure out what the range of the data is +supposed to be. I have assumed that if the maximum value in the LUT +data is less than a power of 2 minus 1 (e.g. 0xebc) then the intent +of the vendor was not to use the maximum available grayscale range +of the display (e.g. the maximum is 0xfff in this case). An alternative +would be to scale to the actual maximum rather than a power of two. + +Very irritating, and in theory not totally reliable if one really +intended the full 16 bits and only used, say 15, but that is extremely +unlikely since everything would be too dark, and this heuristic +seems to work OK. + +There has never been anything in the standard that describes having +to go through these convolutions. Since the only value in the +standard that describes the bit depth of the LUT values is LUT +Descriptor value 3 and that is (usually) always required to be +either 8 or 16, it mystifies me how the creators' of these images +imagine that the receiver is going to divine the range that is intended. Further, the standard is quite explicit that this 3rd +value defines the range of LUT values, but as far as I am aware, all +the vendors are ignoring the standard and indeed sending a third value +of 16 in all cases. + +This problem is not confined to CR, and is also seen with DX products. + +Typically I have seen: + +- Agfa CR, which usually (always ?) sends LUTs, values up to 0x0fff +- Fuji CR, which occasionally send LUTs, values up to 0x03ff +- GE DX, for presentation, which always have LUTs, up to 0x3fff + +Swissray, Siemens, Philips, Canon and Kodak never seem to send VOI LUTs +at this point (which is a whole other problem). Note that the presence +or absence of a VOI LUT as opposed to window values may be configurable +on the modality in some cases, and I have just looked at what I happen +to have received from a myriad of sites over whose configuration I have +no control. This may be why the majority of Fuji images have no VOI LUTs, +but a few do (or it may be the Siemens system that these Fuji images went +through that perhaps added it). I do have some test Hologic DX images that +are not from a clinical site that do actually get this right (a value +of 12 for the third value and a max of 0xfff). + +Since almost every vendor that I have encountered that encodes LUTs +makes this mistake, perhaps it is time to amend the standard to warn +implementor's of receivers and/or sanction this bad behavior. We have +talked about this in the past in WG 6 but so far everyone has been +reluctant to write into the standard such a comment. Maybe it is time +to try again, since if one is not aware of this problem, one cannot +effectively implement display using VOI LUTs, and there is a vast +installed base to contend with. + +I did not check presentation states, in which VOI LUTs could also be +encountered, for the prevalence of this mistake, nor did I look at the +encoding of Modality LUT's, which are unusual. Nor did I check digital +mammography images. I would be interested to hear from anyone who has. + +David + +PS. The following older thread in this newsgroup discusses this: + +"http://groups-beta.google.com/group/comp.protocols.dicom/browse_frm/t hread/6a033444802a35fc/0f0a9a1e35c1468e?q=voi+lut&_done=%2Fgroup%2Fcom p.protocols.dicom%2Fsearch%3Fgroup%3Dcomp.protocols.dicom%26q%3Dvoi+lu t%26qt_g%3D1%26searchnow%3DSearch+this+group%26&_doneTitle=Back+to+Sea rch&&d#0f0a9a1e35c1468e" + +PPS. From a historical perspective, the following may be of interest. + +In the original standard in 1993, all that was said about this was a +reference to the corresponding such where Modality LUTs are described +that said: + +"The third value specifies the number of bits for each entry in the +LUT Data. It shall take the value 8 or 16. The LUT Data shall be stored +in a format equivalent to 8 or 16 bits allocated and high bit equal +1-bits allocated." + +Since the high bit hint was not apparently explicit enough, a very +early CP, CP 15 (submitted by Agfa as it happens), replaced this with: + +"The third value conveys the range of LUT entry values. It shall take +the value 8 or 16, corresponding with the LUT entry value range of +256 or 65536. + +Note: The third value is not required for describing the + LUT data and is only included for informational usage + and for maintaining compatibility with ACRNEMA 2.0. + +The LUT Data contains the LUT entry values." + +That is how it read in the 1996, 1998 and 1999 editions. + +By the 2000 edition, Supplement 33 that introduced presentation states +extensively reworked this entire section and tried to explain this in +different words: + +"The output range is from 0 to 2^n-1 where n is the third value of LUT +Descriptor. This range is always unsigned." + +and also added a note to spell out what the output range meant in the +VOI LUT section: + +"9. The output of the Window Center/Width or VOI LUT transformation +is either implicitly scaled to the full range of the display device +if there is no succeeding transformation defined, or implicitly scaled +to the full input range of the succeeding transformation step (such as +the Presentation LUT), if present. See C.11.6.1." + +It still reads this way in the 2004 edition. + +Note that LUTs in other applications than the general VOI LUT allow for +values other than 8 or 16 in the third value of LUT descriptor to permit +ranges other than 0 to 255 or 65535. + +In addition, the DX Image Module specializes the VOI LUT +attributes as follows, in PS 3.3 section C.8.11.3.1.5 (added in Sup 32): + +"The third value specifies the number of bits for each entry in the LUT +Data (analogous to �bits stored�). It shall be between 10-16. The LUT +Data shall be stored in a format equivalent to 16 �bits allocated� and +�high bit� equal to �bits stored� - 1. The third value conveys the range +of LUT entry values. These unsigned LUT entry values shall range between +0 and 2^n-1, where n is the third value of the LUT Descriptor." + +So in the case of the GE DX for presentation images, the third value of +LUT descriptor is allowed to be and probably should be 14 rather than 16. + +*/ diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmPixelReadConvert.h b/Utilities/ITK/Utilities/gdcm/src/gdcmPixelReadConvert.h new file mode 100644 index 0000000000000000000000000000000000000000..d8e8f2270eb734a3580793569a3cbf3ad2396031 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmPixelReadConvert.h @@ -0,0 +1,171 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmPixelReadConvert.h,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:39 $ + Version: $Revision: 1.4 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + + +#ifndef GDCMPIXELREADCONVERT_H +#define GDCMPIXELREADCONVERT_H + +#include "gdcmBase.h" +#include "gdcmException.h" +#include <fstream> + +namespace gdcm +{ +class File; +class RLEFramesInfo; +class JPEGFragmentsInfo; + +typedef void (*VOID_FUNCTION_PUINT8_PFILE_POINTER)(uint8_t *, File *); + +/** + * \brief Utility container for gathering the various forms the pixel data + * migth take during the user demanded processes. + * WARNING : *none* of these functions may be invoked by gdcm user + * (internal use only) + */ +class GDCM_EXPORT PixelReadConvert : public Base +{ +friend class FileHelper; + +private: + PixelReadConvert(); + virtual ~PixelReadConvert(); + + void Print( std::ostream &os = std::cout, std::string const &indent = "" ); + + // Getter accessors: + /// \brief returns pixel area holding RGB Pixels, made from Grey level + LUT + uint8_t *GetRGB() { return RGB; } + /// \brief returns pixel area length -RGB Pixels, (from Grey level + LUT)- + size_t GetRGBSize() { return RGBSize; } + /// \brief returns pixel area holding native RGB Pixels or Grey level + uint8_t *GetRaw() { return Raw; } + /// \brief returns pixel area size -native RGB Pixels or Grey level- + size_t GetRawSize() { return RawSize; } + /// \brief returns Red Green Blue Alpha LUT + uint8_t *GetLutRGBA() { return LutRGBA; } + /// \brief returns Lut Item Number + int GetLutItemNumber() { return LutItemNumber; } + /// \brief returns Lut Item Size + int GetLutItemSize() { return LutItemSize; } + // Predicates: + bool IsRawRGB(); + +// In progress + void GrabInformationsFromFile( File *file ); + bool ReadAndDecompressPixelData( std::ifstream *fp ); + void Squeeze(); + bool BuildRGBImage(); + void BuildLUTRGBA(); +/// \brief Allow user to pass his own function to modify pixels +/// (e.g; mirror, upsidedown, ...) just after reading + void SetUserFunction( VOID_FUNCTION_PUINT8_PFILE_POINTER userFunc ) + { UserFunction = userFunc; } + + // Use the fp: + void ReadAndDecompress12BitsTo16Bits( std::ifstream *fp ) + throw ( FormatError ); + bool ReadAndDecompressJPEGFile( std::ifstream *fp ); + + // In place (within Decompressed and with no fp access) decompression + // or convertion: + void ConvertSwapZone(); + void ConvertReorderEndianity(); + bool ConvertReArrangeBits() throw ( FormatError ); + void ConvertFixGreyLevels(); + void ConvertRGBPlanesToRGBPixels(); + void ConvertYcBcRPlanesToRGBPixels(); + void ConvertHandleColor(); + + void ComputeRawAndRGBSizes(); + void AllocateRGB(); + void AllocateRaw(); + +// Variables +/** + * \brief Pixel data represented as RGB after LUT color interpretation. + * 'uint8_t' is just to avoid warnings at compile time. + * feel free to cast it as uint16_t if you need + */ + uint8_t *RGB; + /// Size of RGB image. + size_t RGBSize; + /// Pixel data after decompression and bit/byte rearrangement. + uint8_t *Raw; + /// Size of Decompressed image. + size_t RawSize; + /// \brief Red/Green/Blue/Alpha LookUpTable build out of the + /// Red/Green/Blue LUT descriptors (see \ref BuildLUTRGBA ). + uint8_t *LutRGBA; + int LutItemNumber; + int LutItemSize; + + // *ALL* the following info belong to the FileHelper + // One should think there is an analyze error in the model ! + + size_t PixelOffset; + size_t PixelDataLength; + int XSize; + int YSize; + int ZSize; + int BitsAllocated; + int BitsStored; + int HighBitPosition; + int SamplesPerPixel; + //int PixelSize; // useless + bool PixelSign; + int SwapCode; + + // cache whether this is a strange GE transfer syntax (which has + // one transfer syntax for the header and another for the pixel data). + bool IsPrivateGETransferSyntax; + + bool IsRaw; + bool IsJPEG2000; + bool IsJPEGLS; + bool IsJPEGLossless; + bool IsJPEGLossy; + bool IsJPEG; + bool IsRLELossless; + bool IsMPEG; + + RLEFramesInfo *RLEInfo; + JPEGFragmentsInfo *JPEGInfo; + + // For handling color stage + int PlanarConfiguration; + bool IsMonochrome; + bool IsMonochrome1; + bool IsPaletteColor; + bool IsYBRFull; + bool HasLUT; + // The 3 LUT descriptors may be different: + std::string LutRedDescriptor; + std::string LutGreenDescriptor; + std::string LutBlueDescriptor; + uint8_t *LutRedData; + uint8_t *LutGreenData; + uint8_t *LutBlueData; + + File *FileInternal; // must be passed to User Function + VOID_FUNCTION_PUINT8_PFILE_POINTER UserFunction; +}; +} // end namespace gdcm + +//----------------------------------------------------------------------------- +#endif diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmPixelWriteConvert.cxx b/Utilities/ITK/Utilities/gdcm/src/gdcmPixelWriteConvert.cxx new file mode 100644 index 0000000000000000000000000000000000000000..032a833c38921397456530e365bb1be5f3878dda --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmPixelWriteConvert.cxx @@ -0,0 +1,120 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmPixelWriteConvert.cxx,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:39 $ + Version: $Revision: 1.3 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#include "gdcmDebug.h" +#include "gdcmPixelWriteConvert.h" + +namespace gdcm +{ +//----------------------------------------------------------------------------- +// Constructor / Destructor +/** + * \brief Constructor + */ +PixelWriteConvert::PixelWriteConvert() +{ + ReadData = 0; + ReadDataSize = 0; + + UserData = 0; + UserDataSize = 0; +} + +/** + * \brief Destructor + */ +PixelWriteConvert::~PixelWriteConvert() +{ +} + +//----------------------------------------------------------------------------- +// Public +/** + * \brief sets Read Data (and size) + * @param data data (uint8_t is for prototyping. if your data is not uint8_t + * just cast the pointer for calling the method) + * @param size data size, in bytes + */ +void PixelWriteConvert::SetReadData(uint8_t *data, size_t size) +{ + ReadData = data; + ReadDataSize = size; +} + +/** + * \brief Sets the internal pointer to the caller's inData + * image representation, BUT WITHOUT COPYING THE DATA. + * - 'image' Pixels are presented as C-like 2D arrays : line per line. + * - 'volume'Pixels are presented as C-like 3D arrays : plane per plane + * \warning Since the pixels are not copied, it is the caller's responsability + * not to deallocate its data before gdcm uses them (e.g. with + * the Write() method ) + * @param data data (uint8_t is for prototyping. if your data is not uint8_t + * just cast the pointer for calling the method) + * @param size size, in bytes. + */ +void PixelWriteConvert::SetUserData(uint8_t *data, size_t size) +{ + UserData = data; + UserDataSize = size; +} + +/** + * \brief Get Data (UserData or ReadData) + * @return data (uint8_t is for prototyping. if your data is + * *not* uint8_t, just cast the returned pointer) + */ +uint8_t *PixelWriteConvert::GetData() +{ + if ( UserData ) + { + return UserData; + } + else + { + return ReadData; + } +} + +/** + * \brief Get Data Size (UserData or ReadData) + * @return size, in bytes. + */ +size_t PixelWriteConvert::GetDataSize() +{ + if ( UserData ) + { + return UserDataSize; + } + else + { + return ReadDataSize; + } +} + +//----------------------------------------------------------------------------- +// Protected + +//----------------------------------------------------------------------------- +// Private + +//----------------------------------------------------------------------------- +// Print + +//----------------------------------------------------------------------------- +} // end namespace gdcm diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmPixelWriteConvert.h b/Utilities/ITK/Utilities/gdcm/src/gdcmPixelWriteConvert.h new file mode 100644 index 0000000000000000000000000000000000000000..d32ddeeb4928676301ba759ee52b4821ba594089 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmPixelWriteConvert.h @@ -0,0 +1,74 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmPixelWriteConvert.h,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:39 $ + Version: $Revision: 1.3 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + + +#ifndef GDCMPIXELWRITECONVERT_H +#define GDCMPIXELWRITECONVERT_H + +#include "gdcmCommon.h" +#include "gdcmBase.h" + +namespace gdcm +{ +/** + * \brief Utility container for gathering the various forms the pixel data + * migth take during the user requiered processes. + * \warning None of the methods may be called by end user (they have no + * meaning outside the class FileHelper) + */ +class GDCM_EXPORT PixelWriteConvert : public Base +{ +friend class FileHelper; + +private: + PixelWriteConvert(); + virtual ~PixelWriteConvert(); + + // Set/Get of images and their size + void SetReadData(uint8_t *data, size_t size); + /// \brief returns ReadData + uint8_t *GetReadData() { return ReadData; } + /// \brief returns ReadDataSize + size_t GetReadDataSize() { return ReadDataSize; } + + /// \brief Set UserData + void SetUserData(uint8_t *data, size_t size); + /// \brief returns UserData + uint8_t *GetUserData() { return UserData; } + /// \brief returns UserDataSize + size_t GetUserDataSize() { return UserDataSize; } + + // Get the used image and its size + uint8_t *GetData(); + size_t GetDataSize(); + +// Variables + /// Pixel data represented as RGB after LUT color interpretation. + uint8_t *ReadData; + /// Size of RGB image. + size_t ReadDataSize; + + /// User pixel data + uint8_t *UserData; + /// Size of User image. + size_t UserDataSize; +}; +} // end namespace gdcm + +//----------------------------------------------------------------------------- +#endif diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmRLEFrame.cxx b/Utilities/ITK/Utilities/gdcm/src/gdcmRLEFrame.cxx new file mode 100644 index 0000000000000000000000000000000000000000..6f1768f8b7ea9b41602206b7452045168f551650 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmRLEFrame.cxx @@ -0,0 +1,160 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmRLEFrame.cxx,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:39 $ + Version: $Revision: 1.4 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#include "gdcmRLEFrame.h" +#include "gdcmDebug.h" + +namespace gdcm +{ +//------------------------------------------------------------------------- +// Constructor / Destructor + +//----------------------------------------------------------------------------- +// Public +void RLEFrame::SetOffset(unsigned int id,long offset) +{ + gdcmAssertMacro(id<15); + Offset[id] = offset; +} + +long RLEFrame::GetOffset(unsigned int id) +{ + gdcmAssertMacro(id<15); + return Offset[id]; +} + +void RLEFrame::SetLength(unsigned int id,long length) +{ + gdcmAssertMacro(id<15); + Length[id] = length; +} + +long RLEFrame::GetLength(unsigned int id) +{ + gdcmAssertMacro(id<15); + return Length[id]; +} + +uint8_t *RLEFrame::ReadAndDecompressRLEFrame( uint8_t *subRaw, + long rawSegmentSize, + std::ifstream *fp ) +{ + // Loop on the fragments + for( unsigned int k = 1; k <= NumberOfFragments; k++ ) + { + // First thing need to reset file to proper position: + fp->seekg(Offset[k], std::ios::beg); + ReadAndDecompressRLEFragment(subRaw, Length[k], + rawSegmentSize, fp); + subRaw += rawSegmentSize; + } + + return subRaw; +} + +/** + * \brief Implementation of the RLE decoding algorithm for decompressing + * a RLE fragment. [refer to PS 3.5-2003, section G.3.2 p 86] + * @param subRaw Sub region where the decoded fragment should be placed. + * @param fragmentSize The length of the binary fragment as found on the disk. + * @param rawSegmentSize The expected length of the fragment ONCE Raw. + * @param fp File Pointer: on entry the position should be the one of + * the fragment to be decoded. + */ +bool RLEFrame::ReadAndDecompressRLEFragment( uint8_t *subRaw, + long fragmentSize, + long rawSegmentSize, + std::ifstream *fp ) +{ + int8_t count; + long numberOfOutputBytes = 0; + long numberOfReadBytes = 0; + + while( numberOfOutputBytes < rawSegmentSize ) + { + fp->read( (char*)&count, 1 ); + numberOfReadBytes += 1; + if ( count >= 0 ) + // Note: count <= 127 comparison is always true due to limited range + // of data type int8_t [since the maximum of an exact width + // signed integer of width N is 2^(N-1) - 1, which for int8_t + // is 127]. + { + fp->read( (char*)subRaw, count + 1); + numberOfReadBytes += count + 1; + subRaw += count + 1; + numberOfOutputBytes += count + 1; + } + else + { + if ( count <= -1 && count >= -127 ) + { + int8_t newByte; + fp->read( (char*)&newByte, 1); + numberOfReadBytes += 1; + for( int i = 0; i < -count + 1; i++ ) + { + subRaw[i] = newByte; + } + subRaw += -count + 1; + numberOfOutputBytes += -count + 1; + } + } + // if count = 128 output nothing + + if ( numberOfReadBytes > fragmentSize ) + { + gdcmWarningMacro( "Read more bytes (" << numberOfReadBytes + << " ) than the segment size. (" + << fragmentSize << ")" ); + return false; + } + } + return true; +} + +//----------------------------------------------------------------------------- +// Protected + +//----------------------------------------------------------------------------- +// Private + +//----------------------------------------------------------------------------- +// Print +/** + * \brief Print self. + * @param indent Indentation string to be prepended during printing. + * @param os Stream to print to. + */ +void RLEFrame::Print( std::ostream &os, std::string const &indent ) +{ + os << indent + << "--- fragments" + << std::endl; + for ( unsigned int i = 0; i < NumberOfFragments; i++ ) + { + os << indent + << " offset : " << Offset[i] + << " length : " << Length[i] + << std::endl; + } +} + +//----------------------------------------------------------------------------- +} // end namespace gdcm + diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmRLEFrame.h b/Utilities/ITK/Utilities/gdcm/src/gdcmRLEFrame.h new file mode 100644 index 0000000000000000000000000000000000000000..112d129a832c0b7c5857042d9fbb8cdb2dd9d82d --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmRLEFrame.h @@ -0,0 +1,73 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmRLEFrame.h,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:39 $ + Version: $Revision: 1.4 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + + +#ifndef GDCMRLEFRAME_H +#define GDCMRLEFRAME_H + +#include "gdcmCommon.h" + +#include <iostream> +#include <fstream> + +namespace gdcm +{ +/** + * \brief Utility class for summerizing the informations of a SINGLE RLE + * frame of an "Encapsulated RLE Compressed Image" (refer to + * PS 3.5-2003 annex G). + * This information is a mix of: + * - the RLE Header (see PS 3.5-2003 section G5) and + * - the lengths of each RLE segment [ which can be decuded from + * both the above RLE Header and the itemlength of the frame). + * + * Each instance of this class (they can be as many instances for + * a given Document as they are frames and they are collected in + * a \ref RLEFramesInfo ) describes : + * - the total number of segments (up to 15), + * - the offsets of each segment of the frame, + * - the (corresponding) lengths of each segment of the frame. + */ +class GDCM_EXPORT RLEFrame +{ +friend class File; +friend class RLEFramesInfo; +private: + RLEFrame() { NumberOfFragments = 0; } + void Print( std::ostream &os = std::cout, std::string const &indent = "" ); + + void SetNumberOfFragments(unsigned int number) + { NumberOfFragments = number; } + unsigned int GetNumberOfFragments() { return NumberOfFragments; } + void SetOffset(unsigned int id, long offset); + long GetOffset(unsigned int id); + void SetLength(unsigned int id, long length); + long GetLength(unsigned int id); + + uint8_t *ReadAndDecompressRLEFrame( uint8_t *subRaw,long rawSegmentSize, + std::ifstream *fp ); + bool ReadAndDecompressRLEFragment( uint8_t *subRaw, long fragmentSize, + long rawSegmentSize, std::ifstream *fp ); + + unsigned int NumberOfFragments; + long Offset[15]; + long Length[15]; +}; +} // end namespace gdcm +//----------------------------------------------------------------------------- +#endif diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmRLEFramesInfo.cxx b/Utilities/ITK/Utilities/gdcm/src/gdcmRLEFramesInfo.cxx new file mode 100644 index 0000000000000000000000000000000000000000..c767c8784ea458e183f0d8cb078b441ed54e750e --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmRLEFramesInfo.cxx @@ -0,0 +1,188 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmRLEFramesInfo.cxx,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:39 $ + Version: $Revision: 1.4 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#include "gdcmRLEFramesInfo.h" +#include "gdcmDebug.h" +#include "gdcmUtil.h" + +#if defined(__BORLANDC__) + #include <mem.h> // for memset +#endif + +namespace gdcm +{ +//------------------------------------------------------------------------- +// Constructor / Destructor +RLEFramesInfo::~RLEFramesInfo() +{ + for(RLEFrameList::iterator it = Frames.begin(); it != Frames.end(); ++it) + { + delete (*it); + } + Frames.clear(); +} + +//----------------------------------------------------------------------------- +// Public +void RLEFramesInfo::AddFrame(RLEFrame *frame) +{ + Frames.push_back(frame); +} + +RLEFrame *RLEFramesInfo::GetFirstFrame() +{ + ItFrames = Frames.begin(); + if (ItFrames != Frames.end()) + return *ItFrames; + return NULL; +} + +RLEFrame *RLEFramesInfo::GetNextFrame() +{ + gdcmAssertMacro (ItFrames != Frames.end()); + + ++ItFrames; + if (ItFrames != Frames.end()) + return *ItFrames; + return NULL; +} + +/** + * \brief Reads from disk the Pixel Data of 'Run Length Encoded' + * Dicom encapsulated file and decompress it. + * @param fp already open File Pointer + * from which the pixel data should be read + * @param raw raw + * @param xSize x Size + * @param ySize y Size + * @param zSize z Size + * @param bitsAllocated Bits allocated + * @return Boolean + */ +bool RLEFramesInfo::DecompressRLEFile( std::ifstream *fp , uint8_t *raw, + int xSize, int ySize, int zSize, + int bitsAllocated ) +{ + uint8_t *subRaw = raw; + long rawSegmentSize = xSize * ySize; + + // Loop on the frame[s] + for(RLEFrameList::iterator it = Frames.begin(); it != Frames.end(); ++it) + { + subRaw = (*it)->ReadAndDecompressRLEFrame( subRaw, rawSegmentSize, fp); + } + + if ( bitsAllocated == 16 ) + { + // Try to deal with RLE 16 Bits + ConvertRLE16BitsFromRLE8Bits( raw, xSize, ySize, zSize ); + } + + return true; +} + +/** + * \brief We assume Raw contains the decoded RLE pixels but as + * 8 bits per pixel. We convert those pixels to 16 bits + * per pixel. + * @param raw raw + * @param xSize x Size + * @param ySize y Size + * @param numberOfFrames number of frames + * @return Boolean always true + */ +bool RLEFramesInfo::ConvertRLE16BitsFromRLE8Bits(uint8_t *raw, int xSize, + int ySize, int numberOfFrames) +{ + size_t pixelNumber = xSize * ySize; + size_t rawSize = pixelNumber * numberOfFrames * 2; + + // We assumed Raw contains the decoded RLE pixels but as + // 8 bits per pixel. In order to convert those pixels to 16 bits + // per pixel we cannot work in place within Raw and hence + // we copy it in a safe place, say copyRaw. + + uint8_t *copyRaw = new uint8_t[rawSize]; + memmove( copyRaw, raw, rawSize ); + + uint8_t *x = raw; + uint8_t *a; + uint8_t *b; + + // Warning : unckecked patch to see the behaviour on Big Endian Processors + + if ( !Util::IsCurrentProcessorBigEndian() ) + { + a = copyRaw; // beginning of 'low bytes' + b = a + pixelNumber; // beginning of 'hight bytes' + } + else + { + b = copyRaw; // beginning of 'low bytes' + a = b + pixelNumber; // beginning of 'hight bytes' + } + + // Re order bytes + for ( int i = 0; i < numberOfFrames; i++ ) + { + for ( unsigned int j = 0; j < pixelNumber; j++ ) + { + *(x++) = *(b++); + *(x++) = *(a++); + } + } + + delete[] copyRaw; + + return true; +} + +//----------------------------------------------------------------------------- +// Protected + +//----------------------------------------------------------------------------- +// Private + +//----------------------------------------------------------------------------- +// Print +/** + * \brief Print self. + * @param indent Indentation string to be prepended during printing. + * @param os Stream to print to. + */ +void RLEFramesInfo::Print( std::ostream &os, std::string indent ) +{ + os << std::endl; + os << indent + << "----------------- RLE frames --------------------------------" + << std::endl; + os << indent + << "Total number of Frames : " << Frames.size() + << std::endl; + int frameNumber = 0; + for(RLEFrameList::iterator it = Frames.begin(); it != Frames.end(); ++it) + { + os << indent + << " frame number :" << frameNumber++ + << std::endl; + (*it)->Print( os, indent + " " ); + } +} + +//----------------------------------------------------------------------------- +} // end namespace gdcm diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmRLEFramesInfo.h b/Utilities/ITK/Utilities/gdcm/src/gdcmRLEFramesInfo.h new file mode 100644 index 0000000000000000000000000000000000000000..bc3a8f8cc81bb3944d00c8eee248ef94537abc5b --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmRLEFramesInfo.h @@ -0,0 +1,69 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmRLEFramesInfo.h,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:39 $ + Version: $Revision: 1.4 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + + +#ifndef GDCMRLEFRAMESINFO_H +#define GDCMRLEFRAMESINFO_H + +#include "gdcmRLEFrame.h" + +#include <list> + +namespace gdcm +{ +/** + * \brief Utility class for gathering the informations of the collection + * of RLE frame[s] (see \ref RLEFrame) when handling + * "Encapsulated RLE Compressed Images" (see PS 3.5-2003 annex G). + * Note: a classical image can be considered as the degenerated case + * of a multiframe image. In this case the collection is limited + * to a single individual frame. + * The informations on each frame are obtained during the pixel parsing + * of a gdcm::File (refer to + * \ref File::ComputeRLEInfo() ). + * They shall be used when (if necessary) decoding the frames. + * + * This class is simply a stl list<> of \ref RLEFrame. + */ +class GDCM_EXPORT RLEFramesInfo +{ +friend class PixelReadConvert; +friend class File; + +private: + ~RLEFramesInfo(); + void Print( std::ostream &os = std::cout, std::string indent = "" ); + bool DecompressRLEFile( std::ifstream *fp, uint8_t *subRaw, int xSize, + int ySize, int zSize, int bitsAllocated ); + bool ConvertRLE16BitsFromRLE8Bits( uint8_t *subRaw, int xSize, int ySize, + int numberOfFrames ); + + void AddFrame(RLEFrame *frame); + + RLEFrame *GetFirstFrame(); + RLEFrame *GetNextFrame(); + + typedef std::list<RLEFrame *> RLEFrameList; + + RLEFrameList Frames; + RLEFrameList::iterator ItFrames; +}; +} // end namespace gdcm + +//----------------------------------------------------------------------------- +#endif diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmSQItem.cxx b/Utilities/ITK/Utilities/gdcm/src/gdcmSQItem.cxx new file mode 100644 index 0000000000000000000000000000000000000000..0a8634e94cc8f083c791e808aa2ec67c61e78d9a --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmSQItem.cxx @@ -0,0 +1,333 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmSQItem.cxx,v $ + Language: C++ + Date: $Date: 2006/02/20 15:56:57 $ + Version: $Revision: 1.8 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#include "gdcmSQItem.h" +#include "gdcmSeqEntry.h" +#include "gdcmValEntry.h" +#include "gdcmBinEntry.h" +#include "gdcmGlobal.h" +#include "gdcmDictSet.h" +#include "gdcmUtil.h" +#include "gdcmDebug.h" + +#include <fstream> + +namespace gdcm +{ +//----------------------------------------------------------------------------- +// Constructor / Destructor +/** + * \brief Constructor from a given SQItem + */ +SQItem::SQItem(int depthLevel ) + : DocEntrySet( ) +{ + SQDepthLevel = depthLevel; + SQItemNumber = 0; +} + +/** + * \brief Canonical destructor. + */ +SQItem::~SQItem() +{ + ClearEntry(); +} + +//----------------------------------------------------------------------------- +// Public +/* + * \brief canonical Writer + * @param fp file pointer to an already open file. + * @param filetype type of the file (ACR, ImplicitVR, ExplicitVR, ...) + */ +void SQItem::WriteContent(std::ofstream *fp, FileType filetype) +{ + int j; + uint16_t item[4] = { 0xfffe, 0xe000, 0xffff, 0xffff }; + uint16_t itemt[4]= { 0xfffe, 0xe00d, 0x0000, 0x0000 }; + + //we force the writting of an 'Item' Start Element + // because we want to write the Item as a 'No Length' item + for(j=0;j<4;++j) + { + binary_write( *fp, item[j]); // fffe e000 ffff ffff + } + + for (ListDocEntry::iterator it = DocEntries.begin(); + it != DocEntries.end(); + ++it) + { + // we skip delimitors (start and end one) because + // we force them as 'no length' + if ( (*it)->GetGroup() == 0xfffe ) + { + continue; + } + + // Fix in order to make some MR PHILIPS images e-film readable + // see gdcmData/gdcm-MR-PHILIPS-16-Multi-Seq.dcm: + // we just *always* ignore spurious fffe|0000 tag ! + if ( (*it)->GetGroup() == 0xfffe && (*it)->GetElement() == 0x0000 ) + { + break; // FIXME : break or continue; ?!? + // --> makes no difference since the only bugged file we have + // contains 'impossible tag' fffe|0000 in last position ! + } + + (*it)->WriteContent(fp, filetype); + } + + //we force the writting of an 'Item Delimitation' item + // because we wrote the Item as a 'no Length' item + for(j=0;j<4;++j) + { + binary_write( *fp, itemt[j]); // fffe e000 0000 0000 + } +} + +/** + * \brief Compute the full length of the SQItem (not only value length) + * depending on the VR. + */ +uint32_t SQItem::ComputeFullLength() +{ + uint32_t l = 8; // Item Starter length + for (ListDocEntry::iterator it = DocEntries.begin(); + it != DocEntries.end(); + ++it) + { + // we skip delimitors (start and end one) because + // we force them as 'no length' + if ( (*it)->GetGroup() == 0xfffe ) + { + continue; + } + l += (*it)->ComputeFullLength(); + } + l += 8; // 'Item Delimitation' item + return l; +} + +/** + * \brief Inserts *in the right place* any Entry (Dicom Element) + * into the Sequence Item + * @param entry Entry to add + * @return always true + */ +bool SQItem::AddEntry(DocEntry *entry) +{ + if (DocEntries.empty() ) + { + DocEntries.push_back(entry); + return true; + } + + ListDocEntry::iterator insertSpot; + ListDocEntry::iterator it = DocEntries.end(); + do + { + it--; + + if ( (*it)->IsItemDelimitor() ) + { + continue; + } + if ( (*it)->GetGroup() < entry->GetGroup() ) + break; + else + if ( (*it)->GetGroup() == entry->GetGroup() && + (*it)->GetElement() < entry->GetElement() ) + break; + } while (it != DocEntries.begin() ); + + insertSpot = it++; + insertSpot++; // ?!? + DocEntries.insert(insertSpot, entry); + return true; +} + +/** + * \brief Clear the std::list from given entry AND delete the entry. + * @param entryToRemove Entry to remove AND delete. + * @return true if the entry was found and removed; false otherwise + */ +bool SQItem::RemoveEntry( DocEntry *entryToRemove ) +{ + for(ListDocEntry::iterator it = DocEntries.begin(); + it != DocEntries.end(); + ++it) + { + if ( *it == entryToRemove ) + { + DocEntries.erase(it); + gdcmWarningMacro( "One element erased: " << entryToRemove->GetKey() ); + delete entryToRemove; + return true; + } + } + gdcmWarningMacro( "Entry not found: " << entryToRemove->GetKey() ); + return false ; +} + +/** + * \brief Clear the std::list from given entry BUT keep the entry. + * @param entryToRemove Entry to remove. + * @return true if the entry was found and removed; false otherwise + */ +bool SQItem::RemoveEntryNoDestroy(DocEntry *entryToRemove) +{ + for(ListDocEntry::iterator it = DocEntries.begin(); + it != DocEntries.end(); + ++it) + { + if ( *it == entryToRemove ) + { + DocEntries.erase(it); + gdcmWarningMacro( "One element removed, no destroyed: " + << entryToRemove->GetKey() ); + return true; + } + } + + gdcmWarningMacro( "Entry not found:" << entryToRemove->GetKey() ); + return false ; +} + +/** + * \brief Remove all entry in the Sequence Item + */ +void SQItem::ClearEntry() +{ + for(ListDocEntry::iterator cc = DocEntries.begin(); + cc != DocEntries.end(); + ++cc) + { + delete *cc; + } + DocEntries.clear(); +} + +/** + * \brief Clear the std::list from given Sequence Item BUT keep the entries + */ +void SQItem::ClearEntryNoDestroy() +{ + DocEntries.clear(); +} + + +/** + * \brief Move all the entries from a given Sequence Item + */ +void SQItem::MoveObject(SQItem *source) +{ + DocEntries = source->DocEntries; + source->ClearEntryNoDestroy(); +} + +/** + * \brief Get the first Dicom entry while visiting the SQItem + * \return The first DocEntry if found, otherwhise 0 + */ +DocEntry *SQItem::GetFirstEntry() +{ + ItDocEntries = DocEntries.begin(); + if ( ItDocEntries != DocEntries.end() ) + return *ItDocEntries; + return 0; +} + +/** + * \brief Get the next Dicom entry while visiting the SQItem + * \return The next DocEntry if found, otherwhise NULL + */ +DocEntry *SQItem::GetNextEntry() +{ + ++ItDocEntries; + if ( ItDocEntries != DocEntries.end() ) + return *ItDocEntries; + return NULL; +} + +/** + * \brief Gets a Dicom Element inside a SQ Item Entry + * @param group Group number of the Entry + * @param elem Element number of the Entry + * @return Entry whose (group,elem) was passed. 0 if not found + */ +DocEntry *SQItem::GetDocEntry(uint16_t group, uint16_t elem) +{ + for(ListDocEntry::iterator i = DocEntries.begin(); + i != DocEntries.end(); + ++i) + { + if ( (*i)->GetGroup() == group && (*i)->GetElement() == elem ) + return *i; + } + return NULL; +} + +//----------------------------------------------------------------------------- +// Protected + +//----------------------------------------------------------------------------- +// Private + +//----------------------------------------------------------------------------- +// Print +/* + * \brief canonical Printer + * @param os Stream to print to. + * @param indent Indentation string to be prepended during printing. + */ +void SQItem::Print(std::ostream &os, std::string const &) +{ + itksys_ios::ostringstream s; + + if (SQDepthLevel > 0) + { + for (int i = 0; i < SQDepthLevel; ++i) + { + s << " | " ; + } + } + os << s.str() << " --- SQItem number " << SQItemNumber << std::endl; + for (ListDocEntry::iterator i = DocEntries.begin(); + i != DocEntries.end(); + ++i) + { + DocEntry *Entry = *i; + bool PrintEndLine = true; + + os << s.str(); + Entry->SetPrintLevel(PrintLevel); + Entry->Print(os); + if ( dynamic_cast<SeqEntry*>(Entry) ) + { + PrintEndLine = false; + } + if (PrintEndLine) + { + os << std::endl; + } + } +} + +//----------------------------------------------------------------------------- +} // end namespace gdcm diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmSQItem.h b/Utilities/ITK/Utilities/gdcm/src/gdcmSQItem.h new file mode 100644 index 0000000000000000000000000000000000000000..ad1b315ad3e4a3640147e29a1ed9173698690eb1 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmSQItem.h @@ -0,0 +1,98 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmSQItem.h,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:39 $ + Version: $Revision: 1.5 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ +#ifndef GDCMSQITEM_H +#define GDCMSQITEM_H + +#include "gdcmDocEntrySet.h" +#include "gdcmElementSet.h" + +#include <list> +#include <fstream> + +namespace gdcm +{ +class DocEntry; + +//----------------------------------------------------------------------------- +typedef std::list<DocEntry *> ListDocEntry; + +//----------------------------------------------------------------------------- +/** + * \brief a SeqEntry is composed by a set of SQItems. + * Each SQItem is composed by a set of DocEntry + * A DocEntry may be a SeqEntry + * ... and so forth + */ +class GDCM_EXPORT SQItem : public DocEntrySet +{ +public: + SQItem(int depthLevel); + ~SQItem(); + + virtual void Print(std::ostream &os = std::cout, std::string const &indent = "" ); + void WriteContent(std::ofstream *fp, FileType filetype); + uint32_t ComputeFullLength(); + + bool AddEntry(DocEntry *Entry); // add to the List + bool RemoveEntry(DocEntry *EntryToRemove); + bool RemoveEntryNoDestroy(DocEntry *EntryToRemove); + void ClearEntry(); + void ClearEntryNoDestroy(); + void MoveObject(SQItem *source); + + DocEntry *GetFirstEntry(); + DocEntry *GetNextEntry(); + + DocEntry *GetDocEntry(uint16_t group, uint16_t elem); + + bool IsEmpty() { return DocEntries.empty(); } + + /// \brief returns the ordinal position of a given SQItem + int GetSQItemNumber() { return SQItemNumber; } + /// \brief Sets the ordinal position of a given SQItem + void SetSQItemNumber(int itemNumber) { SQItemNumber = itemNumber; } + + /// \brief Accessor on \ref SQDepthLevel. + int GetDepthLevel() { return SQDepthLevel; } + + /// \brief Accessor on \ref SQDepthLevel. + void SetDepthLevel(int depth) { SQDepthLevel = depth; } + +protected: +// Variables that need to be accessed in subclasses + /// \brief Chained list of Doc Entries + ListDocEntry DocEntries; + /// Iterator, used to visit the entries + ListDocEntry::iterator ItDocEntries; + /// Iterator, used to visit the Val Entries (for Python users) + ListDocEntry::iterator ItValEntries; + +private: + /// \brief Sequences can be nested. This \ref SQDepthLevel represents + /// the level of the nesting of instances of this class. + /// \ref SQDepthLevel and its \ref SeqEntry::SQDepthLevel + /// counterpart are only defined on printing purposes + /// (see \ref Print). + int SQDepthLevel; + + /// \brief SQ Item ordinal number + int SQItemNumber; +}; +} // end namespace gdcm +//----------------------------------------------------------------------------- +#endif diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmSeqEntry.cxx b/Utilities/ITK/Utilities/gdcm/src/gdcmSeqEntry.cxx new file mode 100644 index 0000000000000000000000000000000000000000..d0404440ae372fb417cd5714f784a38bfa120af0 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmSeqEntry.cxx @@ -0,0 +1,269 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmSeqEntry.cxx,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:39 $ + Version: $Revision: 1.4 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#include "gdcmSeqEntry.h" +#include "gdcmSQItem.h" +#include "gdcmValEntry.h" +#include "gdcmTS.h" +#include "gdcmGlobal.h" +#include "gdcmUtil.h" +#include "gdcmDebug.h" + +#include <iostream> +#include <iomanip> +#include <fstream> + +namespace gdcm +{ +//----------------------------------------------------------------------------- +// Constructor / Destructor +/** + * \brief Constructor from a given SeqEntry + */ +SeqEntry::SeqEntry( DictEntry *e ) + : DocEntry(e) +{ + Length = 0; + ReadLength = 0xffffffff; + SQDepthLevel = -1; + + DelimitorMode = false; + SeqTerm = NULL; +} + +/** + * \brief Constructor from a given DocEntry + * @param e Pointer to existing Doc entry + * @param depth depth level of the current Seq entry + */ +SeqEntry::SeqEntry( DocEntry *e, int depth ) + : DocEntry( e->GetDictEntry() ) +{ + Length = 0; + ReadLength = 0xffffffff; + SQDepthLevel = depth; + + ImplicitVR = e->IsImplicitVR(); + Offset = e->GetOffset(); + SeqTerm = NULL; +} + +/** + * \brief Canonical destructor. + */ +SeqEntry::~SeqEntry() +{ + ClearSQItem(); +} + +//----------------------------------------------------------------------------- +// Public +/* + * \brief canonical Writer + * @param fp pointer to an already open file + * @param filetype type of the file (ACR, ImplicitVR, ExplicitVR, ...) + */ +void SeqEntry::WriteContent(std::ofstream *fp, FileType filetype) +{ + uint16_t seq_term_gr = 0xfffe; + uint16_t seq_term_el = 0xe0dd; + uint32_t seq_term_lg = 0x00000000; + + // ignore 'Zero length' Sequences + if ( GetReadLength() == 0 ) + return; + + DocEntry::WriteContent(fp, filetype); + for(ListSQItem::iterator cc = Items.begin(); + cc != Items.end(); + ++cc) + { + (*cc)->WriteContent(fp, filetype); + } + + // we force the writting of a Sequence Delimitation item + // because we wrote the Sequence as a 'no Length' sequence + binary_write(*fp, seq_term_gr); + binary_write(*fp, seq_term_el); + binary_write(*fp, seq_term_lg); +} + +/** + * \brief Compute the full length of the SeqEntry (not only value + * length) depending on the VR. + */ +uint32_t SeqEntry::ComputeFullLength() +{ + uint32_t l = 12; // Tag (4) + VR (explicit) 4 + 4 (length); + for(ListSQItem::iterator cc = Items.begin(); + cc != Items.end(); + ++cc) + { + l += (*cc)->ComputeFullLength(); + } + l += 8; // seq_term Tag (4) + seq_term_lg (4) + return l; +} + +/** + * \brief adds the passed ITEM to the ITEM chained List for this SeQuence. + * @param sqItem SQItem to be pushed back in the SeqEntry + * @param itemNumber ordinal number of the SQItem + * \note NOT end-user intendend method ! + */ +void SeqEntry::AddSQItem(SQItem *sqItem, int itemNumber) +{ +// FIXME : SQItemNumber is supposed to be the ordinal number of the SQItem +// within the Sequence. +// Either only 'push_back' is allowed, +// and we just have to do something like SeqEntry::lastNb++ +// Or we can add (or remove) anywhere, and SQItemNumber will be broken + sqItem->SetSQItemNumber(itemNumber); + Items.push_back(sqItem); +} + +/** + * \brief Remove all SQItem. + */ +void SeqEntry::ClearSQItem() +{ + for(ListSQItem::iterator cc = Items.begin(); cc != Items.end(); ++cc) + { + delete *cc; + } + if (SeqTerm) + { + delete SeqTerm; + } +} + +/** + * \brief Get the first entry while visiting the SeqEntry + * \return The first SQItem if found, otherwhise NULL + */ +SQItem *SeqEntry::GetFirstSQItem() +{ + ItSQItem = Items.begin(); + if (ItSQItem != Items.end()) + return *ItSQItem; + return NULL; +} + +/** + * \brief Get the next SQItem while visiting the SeqEntry + * \note : meaningfull only if GetFirstEntry already called + * \return The next SQItem if found, otherwhise NULL + */ + +SQItem *SeqEntry::GetNextSQItem() +{ + gdcmAssertMacro (ItSQItem != Items.end()) + { + ++ItSQItem; + if (ItSQItem != Items.end()) + return *ItSQItem; + } + return NULL; +} + +/** + * \brief return a pointer to the SQItem referenced by its ordinal number. + * Returns the first item when argument is negative. + * Returns the last item when argument is bigger than the total + * item number. + */ +SQItem *SeqEntry::GetSQItem(int nb) +{ + if (nb<0) + { + return *(Items.begin()); + } + int count = 0 ; + for(ListSQItem::iterator cc = Items.begin(); + cc != Items.end(); + count ++, ++cc) + { + if (count == nb) + { + return *cc; + } + } + return *(Items.end()); +} + +/** + * \brief returns the number of SQItems within the current Sequence + */ +unsigned int SeqEntry::GetNumberOfSQItems() +{ + return Items.size(); +} + +//----------------------------------------------------------------------------- +// Protected + +//----------------------------------------------------------------------------- +// Private + +//----------------------------------------------------------------------------- +// Print +/** + * \brief canonical Printer + */ +void SeqEntry::Print( std::ostream &os, std::string const & ) +{ + // First, Print the Dicom Element itself. + os << "S "; + DocEntry::Print(os); + os << std::endl; + + if (GetReadLength() == 0) + return; + + // Then, Print each SQ Item + for(ListSQItem::iterator cc = Items.begin(); cc != Items.end(); ++cc) + { + (*cc)->SetPrintLevel(PrintLevel); + (*cc)->Print(os); + } + + // at end, print the sequence terminator item, if any + if (DelimitorMode) + { + int i; + for ( i = 0; i < SQDepthLevel; i++ ) + os << " | " ; + os << " --- " << std::endl; + for ( i = 0; i < SQDepthLevel; i++ ) + os << " | " ; + if (SeqTerm != NULL) + { + SeqTerm->SetPrintLevel(PrintLevel); + SeqTerm->Print(os); + os << std::endl; + } + else + { + // fuse + gdcmWarningMacro(" -------- should have a sequence terminator item"); + } + } +} + +//----------------------------------------------------------------------------- +} // end namespace gdcm diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmSeqEntry.h b/Utilities/ITK/Utilities/gdcm/src/gdcmSeqEntry.h new file mode 100644 index 0000000000000000000000000000000000000000..95e1df3c28f4fe54ea6a092b0f863200e5d61c06 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmSeqEntry.h @@ -0,0 +1,95 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmSeqEntry.h,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:39 $ + Version: $Revision: 1.4 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#ifndef GDCMSQDOCENTRY_H +#define GDCMSQDOCENTRY_H + +#include "gdcmDocEntry.h" + +#include <list> + +namespace gdcm +{ +class SQItem; +//----------------------------------------------------------------------------- +typedef std::list<SQItem *> ListSQItem; + +//----------------------------------------------------------------------------- +/** + * \brief a SeqEntry (as opposed to a ValEntry) is a non elementary DocEntry. + * It is composed by a set of SQItems. + * Each SQItem is composed by a set of DocEntry + * A DocEntry may be a SeqEntry + * ... and so forth + */ +class GDCM_EXPORT SeqEntry : public DocEntry +{ +public: + SeqEntry( DictEntry *e); + SeqEntry( DocEntry *d, int depth ); + ~SeqEntry(); + + void Print(std::ostream &os = std::cout, std::string const &indent = "" ); + void WriteContent(std::ofstream *fp, FileType filetype); + uint32_t ComputeFullLength(); + + void AddSQItem(SQItem *it, int itemNumber); + void ClearSQItem(); + SQItem *GetFirstSQItem(); + SQItem *GetNextSQItem(); + SQItem *GetSQItem(int itemNumber); + unsigned int GetNumberOfSQItems(); + + /// Sets the delimitor mode + void SetDelimitorMode(bool dm) { DelimitorMode = dm; } + /// Sets the Sequence Delimitation Item + void SetDelimitationItem(DocEntry *e) { SeqTerm = e; } + + /// Gets the Sequence Delimitation Item + DocEntry *GetDelimitationItem() { return SeqTerm;} + + /// Gets the depth level + int GetDepthLevel() const { return SQDepthLevel; } + /// Sets the depth level of a Sequence Entry embedded in a SeQuence + void SetDepthLevel(int depth) { SQDepthLevel = depth; } + +protected: + +private: +// Variables + /// If this Sequence is in delimitor mode (length =0xffffffff) or not + bool DelimitorMode; + + /// Chained list of SQ Items + ListSQItem Items; + /// iterator on the SQItems of the current SeqEntry + ListSQItem::iterator ItSQItem; + + /// sequence terminator item + DocEntry *SeqTerm; + + /// \brief Defines the depth level of this \ref SeqEntry inside + /// the (optionaly) nested sequences. \ref SQDepthLevel + /// and its \ref SQItem::SQDepthLevel counterpart + /// are only defined on printing purposes (see \ref Print). + int SQDepthLevel; +}; +} // end namespace gdcm +//----------------------------------------------------------------------------- +#endif + diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmSerieHelper.cxx b/Utilities/ITK/Utilities/gdcm/src/gdcmSerieHelper.cxx new file mode 100644 index 0000000000000000000000000000000000000000..bf9d89ea2e45583c86846a28c294a8cd74f2dfd9 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmSerieHelper.cxx @@ -0,0 +1,948 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmSerieHelper.cxx,v $ + Language: C++ + Date: $Date: 2006/02/20 18:29:58 $ + Version: $Revision: 1.21 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#include "gdcmSerieHelper.h" +#include "gdcmDirList.h" +#include "gdcmFile.h" +#include "gdcmDictEntry.h" // for TranslateToKey +#include "gdcmDebug.h" +#include "gdcmUtil.h" + +#include <math.h> +#include <vector> +#include <algorithm> +#include <map> +#include <stdio.h> //for sscanf + +namespace gdcm +{ + +//----------------------------------------------------------------------------- +// Constructor / Destructor +/** + * \brief Constructor from a given SerieHelper + */ +SerieHelper::SerieHelper() +{ + m_UseSeriesDetails = false; + ClearAll(); + UserLessThanFunction = 0; + DirectOrder = true; +} + +/** + * \brief Canonical destructor. + */ +SerieHelper::~SerieHelper() +{ + ClearAll(); +} + +/** + * \brief Preventively, clear everything at constructor time. + * ( use it at destructor time.) + */ +void SerieHelper::ClearAll() +{ + // For all the 'Single SerieUID' Filesets that may already exist + FileList *l = GetFirstSingleSerieUIDFileSet(); + while (l) + { + // For all the gdcm::File of a File set + for (gdcm::FileList::iterator it = l->begin(); + it != l->end(); + ++it) + { + delete *it; // remove each entry + } + l->clear(); + delete l; // remove the container + l = GetNextSingleSerieUIDFileSet(); + } + // Need to clear that too: + SingleSerieUIDFileSetHT.clear(); +} + +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- + +// Public +/** + * \brief add a gdcm::File to the Fileset corresponding to its Serie UID + * @param filename Name of the file to deal with + */ +void SerieHelper::AddFileName(std::string const &filename) +{ + // Create a DICOM file + File *header = new File (); + header->SetLoadMode(LoadMode); + header->SetFileName( filename ); + header->Load(); + + if ( header->IsReadable() ) + { + if ( !AddFile( header ) ) + { + // at least one rule was unmatched we need to deallocate the file: + delete header; + } + } + else + { + gdcmWarningMacro("Could not read file: " << filename ); + delete header; + } +} + +/** + * \brief add a gdcm::File to the first (and supposed to be unique) file set + * of the gdcm::SerieHelper. + * \warning : this method should be used by aware users only! + * Passing a gdcm::File* has the same effect than passing a file name! + * \todo : decide which one is wrong (the method, or the commentary)! + * the following comment doesn't match the method :-( + * User is supposed to know the files he want to deal with + * and consider them they belong to the same Serie + * (even if their Serie UID is different) + * user will probabely OrderFileList() this list (actually, ordering + * user choosen gdm::File is the sole interest of this method) + * Moreover, using vtkGdcmReader::SetCoherentFileList() will avoid + * vtkGdcmReader parsing twice the same files. + * *no* coherence check is performed, but those specified + * by SerieHelper::AddRestriction() + * @param header gdcm::File* of the file to deal with + * @return true if file was added, false if file was rejected + */ +bool SerieHelper::AddFile(File *header) +{ + int allrules = 1; + // First step the user has defined a set of rules for the DICOM + // he is looking for. + // make sure the file correspond to his set of rules: + + std::string s; + for(SerieExRestrictions::iterator it2 = ExRestrictions.begin(); + it2 != ExRestrictions.end(); + ++it2) + { + const ExRule &r = *it2; + s = header->GetEntryValue( r.group, r.elem ); + if ( !Util::CompareDicomString(s, r.value.c_str(), r.op) ) + { + // Argh ! This rule is unmatched; let's just quit + allrules = 0; + break; + } + } + + if ( allrules ) // all rules are respected: + { + // Allright! we have a found a DICOM that matches the user expectation. + // Let's add it to the specific 'id' which by default is uid (Serie UID) + // but can be `refined` by user with more paramater (see AddRestriction(g,e)) + + std::string id = CreateUniqueSeriesIdentifier( header ); + // if id == GDCM_UNFOUND then consistently we should find GDCM_UNFOUND + // no need here to do anything special + + if ( SingleSerieUIDFileSetHT.count(id) == 0 ) + { + gdcmDebugMacro(" New Serie UID :[" << id << "]"); + // create a std::list in 'id' position + SingleSerieUIDFileSetHT[id] = new FileList; + } + // Current Serie UID and DICOM header seems to match add the file: + SingleSerieUIDFileSetHT[id]->push_back( header ); + } + else + { + // one rule not matched, tell user: + return false; + } + return true; +} + +/** + * \brief add a rule for restricting a DICOM file to be in the serie we are + * trying to find. For example you can select only the DICOM files from a + * directory which would have a particular EchoTime==4.0. + * This method is a user level, value is not required to be formatted as a DICOM + * string + * \todo find a trick to allow user to say if he wants the Rectrictions + * to be *ored* (and not only *anded*) + * @param group Group number of the target tag. + * @param elem Element number of the target tag. + * @param value value to be checked to exclude File + * @param op operator we want to use to check + */ +void SerieHelper::AddRestriction(uint16_t group, uint16_t elem, + std::string const &value, int op) +{ + ExRule r; + r.group = group; + r.elem = elem; + r.value = value; + r.op = op; + ExRestrictions.push_back( r ); +} + +void SerieHelper::AddRestriction(uint16_t group, uint16_t elem) +{ + ExRule r; + r.group = group; + r.elem = elem; + ExRefine.push_back( r ); +} + +#ifndef GDCM_LEGACY_REMOVE +/** + * \brief add a rule for restricting a DICOM file to be in the serie we are + * trying to find. For example you can select only the DICOM files from a + * directory which would have a particular EchoTime==4.0. + * This method is a user level, value is not required to be formatted as a DICOM + * string + * @param group Group number of the target tag. + * @param elem Element number of the target tag. + * @param value value to be checked to exclude File + * @deprecated use : AddRestriction(uint16_t group, uint16_t elem, + * std::string const &value, int op); + */ +void SerieHelper::AddRestriction(TagKey const &key, std::string const &value) +{ + Rule r; + r.first = key; + r.second = value; + Restrictions.push_back( r ); +} +#endif + +/** + * \brief Sets the root Directory + * @param dir Name of the directory to deal with + * @param recursive whether we want explore recursively the root Directory + */ +void SerieHelper::SetDirectory(std::string const &dir, bool recursive) +{ + DirList dirList(dir, recursive); // OS specific + + DirListType filenames_list = dirList.GetFilenames(); + for( DirListType::const_iterator it = filenames_list.begin(); + it != filenames_list.end(); ++it) + { + AddFileName( *it ); + } +} + +/** + * \brief Sorts the given Fileset + * \warning This could be implemented in a 'Strategy Pattern' approach + * But as I don't know how to do it, I leave it this way + * BTW, this is also a Strategy, I don't know this is + * the best approach :) + */ +void SerieHelper::OrderFileList(FileList *fileSet) +{ + + if ( SerieHelper::UserLessThanFunction ) + { + UserOrdering( fileSet ); + return; + } + else if ( ImagePositionPatientOrdering( fileSet ) ) + { + return ; + } + else if ( ImageNumberOrdering(fileSet ) ) + { + return ; + } + else + { + FileNameOrdering(fileSet ); + } +} + +/** + * \brief Elementary coherence checking of the files with the same Serie UID + * Only sizes and pixel type are checked right now ... + */ +bool SerieHelper::IsCoherent(FileList *fileSet) +{ + if(fileSet->size() == 1) + return true; + + FileList::const_iterator it = fileSet->begin(); + + int nX = (*it)->GetXSize(); + int nY = (*it)->GetYSize(); + int pixelSize = (*it)->GetPixelSize(); + bool signedPixelData = (*it)->IsSignedPixelData(); + it ++; + for ( ; + it != fileSet->end(); + ++it) + { + if ( (*it)->GetXSize() != nX ) + return false; + if ( (*it)->GetYSize() != nY ) + return false; + if ( (*it)->GetPixelSize() != pixelSize ) + return false; + if ( (*it)->IsSignedPixelData() != signedPixelData ) + return false; + // probabely more is to be checked (?) + } + return true; +} + +#ifndef GDCM_LEGACY_REMOVE +/** + * \brief accessor (DEPRECATED : use GetFirstSingleSerieUIDFileSet ) + * Warning : 'coherent' means here they have the same Serie UID + * @return The first FileList if found, otherwhise NULL + */ +FileList *SerieHelper::GetFirstCoherentFileList() +{ + ItFileSetHt = SingleSerieUIDFileSetHT.begin(); + if ( ItFileSetHt != SingleSerieUIDFileSetHT.end() ) + return ItFileSetHt->second; + return NULL; +} + +/** + * \brief accessor (DEPRECATED : use GetNextSingleSerieUIDFileSet ) + * Warning : 'coherent' means here they have the same Serie UID + * \note : meaningfull only if GetFirstCoherentFileList() already called + * @return The next FileList if found, otherwhise NULL + */ +FileList *SerieHelper::GetNextCoherentFileList() +{ + gdcmAssertMacro (ItFileSetHt != SingleSerieUIDFileSetHT.end()); + + ++ItFileSetHt; + if ( ItFileSetHt != SingleSerieUIDFileSetHT.end() ) + return ItFileSetHt->second; + return NULL; +} + +/** + * \brief accessor (DEPRECATED : use GetSingleSerieUIDFileSet ) + * Warning : 'coherent' means here they have the same Serie UID + * @param SerieUID SerieUID + * \return pointer to the FileList if found, otherwhise NULL + */ +FileList *SerieHelper::GetCoherentFileList(std::string SerieUID) +{ + if ( SingleSerieUIDFileSetHT.count(SerieUID) == 0 ) + return 0; + return SingleSerieUIDFileSetHT[SerieUID]; +} +#endif + + +/** + * \brief Get the first Fileset while visiting the SingleSerieUIDFileSetmap + * @return The first FileList (SingleSerieUIDFileSet) if found, otherwhise 0 + */ +FileList *SerieHelper::GetFirstSingleSerieUIDFileSet() +{ + ItFileSetHt = SingleSerieUIDFileSetHT.begin(); + if ( ItFileSetHt != SingleSerieUIDFileSetHT.end() ) + return ItFileSetHt->second; + return NULL; +} + +/** + * \brief Get the next Fileset while visiting the SingleSerieUIDFileSetmap + * \note : meaningfull only if GetNextSingleSerieUIDFileSet() already called + * @return The next FileList (SingleSerieUIDFileSet) if found, otherwhise 0 + */ +FileList *SerieHelper::GetNextSingleSerieUIDFileSet() +{ + gdcmAssertMacro (ItFileSetHt != SingleSerieUIDFileSetHT.end()); + + ++ItFileSetHt; + if ( ItFileSetHt != SingleSerieUIDFileSetHT.end() ) + return ItFileSetHt->second; + return NULL; +} + +/** + * \brief Get the SingleSerieUIDFileSet according to its Serie UID + * @param SerieUID SerieUID to retrieve + * \return pointer to the FileList (SingleSerieUIDFileSet) if found, otherwhise 0 + */ +FileList *SerieHelper::GetSingleSerieUIDFileSet(std::string SerieUID) +{ + if ( SingleSerieUIDFileSetHT.count(SerieUID) == 0 ) + return 0; + return SingleSerieUIDFileSetHT[SerieUID]; +} + +/** + * \brief Splits a Single SerieUID Fileset according to the Orientations + * @param fileSet File Set to be splitted + * \return std::map of 'Xcoherent' File sets + */ + +XCoherentFileSetmap SerieHelper::SplitOnOrientation(FileList *fileSet) +{ + XCoherentFileSetmap CoherentFileSet; + + int nb = fileSet->size(); + if (nb == 0 ) + return CoherentFileSet; + float iop[6]; + std::string strOrient; + itksys_ios::ostringstream ossOrient; + + FileList::const_iterator it = fileSet->begin(); + it ++; + for ( ; + it != fileSet->end(); + ++it) + { + // Information is in : + // 0020 0037 : Image Orientation (Patient) or + // 0020 0035 : Image Orientation (RET) + + // Let's build again the 'cosines' string, to be sure of it's format + (*it)->GetImageOrientationPatient(iop); + + ossOrient << iop[0]; + for (int i = 1; i < 6; i++) + { + ossOrient << "\\"; + ossOrient << iop[i]; + } + strOrient = ossOrient.str(); + ossOrient.str(""); + if ( CoherentFileSet.count(strOrient) == 0 ) + { + gdcmDebugMacro(" New Orientation :[" << strOrient << "]"); + // create a File set in 'orientation' position + CoherentFileSet[strOrient] = new FileList; + } + // Current Orientation and DICOM header match; add the file: + CoherentFileSet[strOrient]->push_back( (*it) ); + } + return CoherentFileSet; +} + +/** + * \brief Splits a 'Single SerieUID' Fileset according to the Positions + * @param fileSet File Set to be splitted + * \return std::map of 'Xcoherent' File sets + */ + +XCoherentFileSetmap SerieHelper::SplitOnPosition(FileList *fileSet) +{ + XCoherentFileSetmap CoherentFileSet; + + int nb = fileSet->size(); + if (nb == 0 ) + return CoherentFileSet; + float pos[3]; + std::string strImPos; // read on disc + itksys_ios::ostringstream ossPosition; + std::string strPosition; // re computed + FileList::const_iterator it = fileSet->begin(); + it ++; + for ( ; + it != fileSet->end(); + ++it) + { + // Information is in : + // 0020,0032 : Image Position Patient + // 0020,0030 : Image Position (RET) + + strImPos = (*it)->GetEntryValue(0x0020,0x0032); + if ( strImPos == GDCM_UNFOUND) + { + gdcmWarningMacro( "Unfound Image Position Patient (0020,0032)"); + strImPos = (*it)->GetEntryValue(0x0020,0x0030); // For ACR-NEMA images + if ( strImPos == GDCM_UNFOUND ) + { + gdcmWarningMacro( "Unfound Image Position (RET) (0020,0030)"); + // User wants to split on the 'Position' + // No 'Position' info found. + // We return an empty Htable ! + return CoherentFileSet; + } + } + + if ( sscanf( strImPos.c_str(), "%f \\%f \\%f ", + &pos[0], &pos[1], &pos[2]) != 3 ) + { + gdcmWarningMacro( "Wrong number for Position : [" + << strImPos << "]" ); + return CoherentFileSet; + } + + // Let's build again the 'position' string, to be sure of it's format + + ossPosition << pos[0]; + for (int i = 1; i < 3; i++) + { + ossPosition << "\\"; + ossPosition << pos[i]; + } + strPosition = ossPosition.str(); + ossPosition.str(""); + + if ( CoherentFileSet.count(strPosition) == 0 ) + { + gdcmDebugMacro(" New Position :[" << strPosition << "]"); + // create a File set in 'position' position + CoherentFileSet[strPosition] = new FileList; + } + // Current Position and DICOM header match; add the file: + CoherentFileSet[strPosition]->push_back( (*it) ); + } + return CoherentFileSet; +} + +/** + * \brief Splits a 'Single SerieUID' File set Coherent according to the + * value of a given Tag + * @param fileSet File Set to be splitted + * @param group group number of the target Element + * @param elem element number of the target Element + * \return std::map of 'Xcoherent' File sets + */ + +XCoherentFileSetmap SerieHelper::SplitOnTagValue(FileList *fileSet, + uint16_t group, uint16_t element) +{ + XCoherentFileSetmap CoherentFileSet; + + int nb = fileSet->size(); + if (nb == 0 ) + return CoherentFileSet; + + std::string strTagValue; // read on disc + + FileList::const_iterator it = fileSet->begin(); + it ++; + for ( ; + it != fileSet->end(); + ++it) + { + // Information is in : + // 0020,0032 : Image Position Patient + // 0020,0030 : Image Position (RET) + + strTagValue = (*it)->GetEntryValue(group,element); + + if ( CoherentFileSet.count(strTagValue) == 0 ) + { + gdcmDebugMacro(" New Tag Value :[" << strTagValue << "]"); + // create a File set in 'position' position + CoherentFileSet[strTagValue] = new FileList; + } + // Current Tag value and DICOM header match; add the file: + CoherentFileSet[strTagValue]->push_back( (*it) ); + } + return CoherentFileSet; +} + +//----------------------------------------------------------------------------- +// Protected + +//----------------------------------------------------------------------------- +// Private +/** + * \brief sorts the images, according to their Patient Position. + * + * We may order, considering : + * -# Image Position Patient + * -# Image Number + * -# file name + * -# More to come :-) + * \note : FileList = std::vector<File* > + * @param fileList Coherent File list (same Serie UID) to sort + * @return false only if the header is bugged ! + */ +bool SerieHelper::ImagePositionPatientOrdering( FileList *fileList ) +//based on Jolinda Smith's algorithm +{ + //iop is calculated based on the file file + float cosines[6]; + double normal[3]; + double ipp[3]; + double dist; + double min = 0, max = 0; + bool first = true; + + std::multimap<double,File *> distmultimap; + // Use a multimap to sort the distances from 0,0,0 + for ( FileList::const_iterator + it = fileList->begin(); + it != fileList->end(); ++it ) + { + if ( first ) + { + (*it)->GetImageOrientationPatient( cosines ); + + // You only have to do this once for all slices in the volume. Next, + // for each slice, calculate the distance along the slice normal + // using the IPP ("Image Position Patient") tag. + // ("dist" is initialized to zero before reading the first slice) : + normal[0] = cosines[1]*cosines[5] - cosines[2]*cosines[4]; + normal[1] = cosines[2]*cosines[3] - cosines[0]*cosines[5]; + normal[2] = cosines[0]*cosines[4] - cosines[1]*cosines[3]; + + ipp[0] = (*it)->GetXOrigin(); + ipp[1] = (*it)->GetYOrigin(); + ipp[2] = (*it)->GetZOrigin(); + + dist = 0; + for ( int i = 0; i < 3; ++i ) + { + dist += normal[i]*ipp[i]; + } + + distmultimap.insert(std::pair<const double,File *>(dist, *it)); + + max = min = dist; + first = false; + } + else + { + ipp[0] = (*it)->GetXOrigin(); + ipp[1] = (*it)->GetYOrigin(); + ipp[2] = (*it)->GetZOrigin(); + + dist = 0; + for ( int i = 0; i < 3; ++i ) + { + dist += normal[i]*ipp[i]; + } + + distmultimap.insert(std::pair<const double,File *>(dist, *it)); + + min = (min < dist) ? min : dist; + max = (max > dist) ? max : dist; + } + } + + // Find out if min/max are coherent + if ( min == max ) + { + gdcmWarningMacro("Looks like all images have the exact same image position" + << ". No PositionPatientOrdering sort performed" ); + return false; + } + + // Check to see if image shares a common position + bool ok = true; + for (std::multimap<double, File *>::iterator it2 = distmultimap.begin(); + it2 != distmultimap.end(); + ++it2) + { + if (distmultimap.count((*it2).first) != 1) + { + gdcmErrorMacro("File: " + << ((*it2).second->GetFileName()) + << " Distance: " + << (*it2).first + << " position is not unique"); + + ok = false; + } + } + if (!ok) + { + return false; + } + + fileList->clear(); // doesn't delete list elements, only nodes + + if (DirectOrder) + { + for (std::multimap<double, File *>::iterator it3 = distmultimap.begin(); + it3 != distmultimap.end(); + ++it3) + { + fileList->push_back( (*it3).second ); + } + } + else // user asked for reverse order + { + std::multimap<double, File *>::const_iterator it4; + it4 = distmultimap.end(); + do + { + it4--; + fileList->push_back( (*it4).second ); + } while (it4 != distmultimap.begin() ); + } + + distmultimap.clear(); + + return true; +} + +//----------------------------------------------------------------------------- +static bool ImageNumberLessThan(File *file1, File *file2) +{ + return file1->GetImageNumber() < file2->GetImageNumber(); +} +static bool ImageNumberGreaterThan (File *file1, File *file2) +{ + return file1->GetImageNumber() > file2->GetImageNumber(); +} +static bool FileNameLessThan (File *file1, File *file2) +{ + return file1->GetFileName() < file2->GetFileName(); +} +static bool FileNameGreaterThan (File *file1, File *file2) +{ + return file1->GetFileName() > file2->GetFileName(); +} + +class SortFunctor +{ +public: + bool operator() (File *file1, File *file2) + { + return (SortFunction)(file1, file2); + } + BOOL_FUNCTION_PFILE_PFILE_POINTER SortFunction; + SortFunctor() + { + SortFunction = 0; + } + SortFunctor(SortFunctor const &sf) + { + SortFunction = sf.SortFunction; + } + void operator=(BOOL_FUNCTION_PFILE_PFILE_POINTER sf) + { + SortFunction = sf; + } +}; + +//----------------------------------------------------------------------------- +// Sort +/** + * \brief Sort FileList. + */ +static void Sort(FileList *fileList, SortFunctor &sf) +{ + std::sort(fileList->begin(), fileList->end(), sf ); +} + + +/** + * \brief sorts the images, according to their Image Number + * \note Works only on bona fide files (i.e image number is a character string + * corresponding to an integer) + * within a bona fide serie (i.e image numbers are consecutive) + * @param fileList File set (same Serie UID) to sort + * @return false if non bona fide stuff encountered + */ +bool SerieHelper::ImageNumberOrdering(FileList *fileList) +{ + int min, max, pos; + int n = fileList->size(); + + FileList::const_iterator it = fileList->begin(); + min = max = (*it)->GetImageNumber(); + + for (; it != fileList->end(); ++it, ++n) + { + pos = (*it)->GetImageNumber(); + min = (min < pos) ? min : pos; + max = (max > pos) ? max : pos; + } + + // Find out if image numbers are coherent (consecutive) + if ( min == max || max == 0 || max >= (n+min) ) + { + gdcmWarningMacro( " 'Image numbers' not coherent. " + << " No ImageNumberOrdering sort performed."); + return false; + } + SortFunctor sf; + if (DirectOrder) + sf = ImageNumberLessThan; + else + sf = ImageNumberGreaterThan; + Sort(fileList, sf); + + return true; +} +/** + * \brief sorts the images, according to their File Name + * @param fileList Coherent File list (same Serie UID) to sort + * @return false only if the header is bugged ! + */ +bool SerieHelper::FileNameOrdering(FileList *fileList) +{ + SortFunctor sf; + if (DirectOrder) + sf = FileNameLessThan; + else + sf = FileNameGreaterThan; + Sort(fileList, sf); + + return true; +} + +/** + * \brief sorts the images, according to user supplied function + * @param fileList Coherent File list (same Serie UID) to sort + * @return false only if the header is bugged ! + */ +bool SerieHelper::UserOrdering(FileList *fileList) +{ + SortFunctor sf; + sf = SerieHelper::UserLessThanFunction; + Sort(fileList,sf); + if (!DirectOrder) + { + std::reverse(fileList->begin(), fileList->end()); + } + return true; +} + +//----------------------------------------------------------------------------- +// Print +/** + * \brief Canonical printer. + */ +void SerieHelper::Print(std::ostream &os, std::string const &indent) +{ + // For all the Coherent File lists of the gdcm::Serie + SingleSerieUIDFileSetmap::iterator itl = SingleSerieUIDFileSetHT.begin(); + if ( itl == SingleSerieUIDFileSetHT.end() ) + { + gdcmWarningMacro( "No SingleSerieUID File set found" ); + return; + } + while (itl != SingleSerieUIDFileSetHT.end()) + { + os << "Serie UID :[" << itl->first << "]" << std::endl; + + // For all the files of a SingleSerieUID File set + for (FileList::iterator it = (itl->second)->begin(); + it != (itl->second)->end(); + ++it) + { + os << indent << " --- " << (*it)->GetFileName() << std::endl; + } + ++itl; + } +} + +void SerieHelper::CreateDefaultUniqueSeriesIdentifier() +{ + // If the user requests, additional information can be appended + // to the SeriesUID to further differentiate volumes in the DICOM + // objects being processed. + + // 0020 0011 Series Number + // A scout scan prior to a CT volume scan can share the same + // SeriesUID, but they will sometimes have a different Series Number + AddRestriction( 0x0020, 0x0011); + // 0018 0024 Sequence Name + // For T1-map and phase-contrast MRA, the different flip angles and + // directions are only distinguished by the Sequence Name + AddRestriction(0x0018, 0x0024); + // 0018 0050 Slice Thickness + // On some CT systems, scout scans and subsequence volume scans will + // have the same SeriesUID and Series Number - YET the slice + // thickness will differ from the scout slice and the volume slices. + AddRestriction(0x0018, 0x0050); + // 0028 0010 Rows + // If the 2D images in a sequence don't have the same number of rows, + // then it is difficult to reconstruct them into a 3D volume. + AddRestriction(0x0028, 0x0010); + // 0028 0011 Columns + // If the 2D images in a sequence don't have the same number of columns, + // then it is difficult to reconstruct them into a 3D volume. + AddRestriction(0x0028, 0x0011); +} + +/** + * \brief Heuristics to *try* to build a Serie Identifier that would ensure + * all the images are coherent. + * + * By default, uses the SeriesUID. If UseSeriesDetails(true) has been called, + * then additional identifying information is used. + * We allow user to add his own critierions, using AddSeriesDetail + * (he knows more than we do about his images!) + * ex : in tagging series, the only pertnent tag is + * 0018|1312 [In-plane Phase Encoding Direction] value : ROW/COLUMN + * @param inFile gdcm::File we want to build a Serie Identifier for. + * @return the SeriesIdentifier + */ +std::string SerieHelper::CreateUniqueSeriesIdentifier( File *inFile ) +{ + if( inFile->IsReadable() ) + { + // 0020 000e UI REL Series Instance UID + std::string uid = inFile->GetEntryValue (0x0020, 0x000e); + std::string id = uid.c_str(); + if(m_UseSeriesDetails) + { + for(SerieExRestrictions::iterator it2 = ExRefine.begin(); + it2 != ExRefine.end(); + ++it2) + { + const ExRule &r = *it2; + std::string s = inFile->GetEntryValue( r.group, r.elem ); + if( s == gdcm::GDCM_UNFOUND ) + { + s = ""; + } + if( id == uid && !s.empty() ) + { + id += "."; // add separator + } + id += s; + } + } + // Eliminate non-alnum characters, including whitespace... + // that may have been introduced by concats. + for(unsigned int i=0; i<id.size(); i++) + { + while(i<id.size() + && !( id[i] == '.' + || (id[i] >= 'a' && id[i] <= 'z') + || (id[i] >= '0' && id[i] <= '9') + || (id[i] >= 'A' && id[i] <= 'Z'))) + { + id.erase(i, 1); + } + } + return id; + } + else // Could not open inFile + { + gdcmWarningMacro("Could not parse series info."); + std::string id = gdcm::GDCM_UNFOUND; + return id; + } +} + + +//----------------------------------------------------------------------------- +} // end namespace gdcm diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmSerieHelper.h b/Utilities/ITK/Utilities/gdcm/src/gdcmSerieHelper.h new file mode 100644 index 0000000000000000000000000000000000000000..b7fa4ba568587fa3000a75bf5a763eb529b8d8f7 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmSerieHelper.h @@ -0,0 +1,223 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmSerieHelper.h,v $ + Language: C++ + Date: $Date: 2006/02/20 18:29:59 $ + Version: $Revision: 1.11 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#ifndef GDCMSERIEHELPER_H +#define GDCMSERIEHELPER_H + +#include "gdcmCommon.h" +#include "gdcmDebug.h" // for LEGACY + +#include <vector> +#include <iostream> +#include <map> +#include <stdio.h> // for sscanf + +namespace gdcm +{ +class File; + + typedef std::vector<File* > FileList; +#ifndef GDCM_LEGACY_REMOVE +typedef std::vector<File* > GdcmFileList; +#endif + + /// \brief XCoherent stands for 'Extra Coherent', + /// (The name 'Coherent' would be enough but it was used before; + /// I don't want to put a bomb in the code) + /// Any 'better name' is welcome ! + typedef std::map<std::string, FileList *> XCoherentFileSetmap; + + typedef bool (*BOOL_FUNCTION_PFILE_PFILE_POINTER)(File *, File *); + +//----------------------------------------------------------------------------- +/** + * \brief + * This class should be used for a stack of 2D dicom images. + * + * - It allows to explore (recursively or not) a directory and + * makes a set of 'Coherent Files' lists (coherent : same SerieUID) + * - It allows : + * - - to sort any of the Coherent File list on the image position. + * - - to split any of the Single SerieUID Filesets (better use this name than + * 'Coherent File List' : it's NOT a std::list, files are NOT coherent ...) + * into several XCoherent Filesets + * XCoherent stands for 'Extra Coherent' (same orientation, or same position) + */ +class GDCM_EXPORT SerieHelper +{ +public: + /// SingleSerieUIDFileSetmap replaces the former CoherentFileListmap + /// ( List were actually std::vectors, and wher no coherent at all : + /// They were only Single SeriesInstanceUID File sets) + typedef std::map<std::string, FileList *> SingleSerieUIDFileSetmap; + + typedef std::vector<File* > FileVector; + + SerieHelper(); + ~SerieHelper(); + void Print(std::ostream &os = std::cout, std::string const &indent = "" ); + + /// \todo should return bool or throw error ? + void AddFileName(std::string const &filename); + bool AddFile(File *header); +#ifndef GDCM_LEGACY_REMOVE + bool AddGdcmFile(File* header) { return AddFile(header); } +#endif + + void SetDirectory(std::string const &dir, bool recursive=false); + bool IsCoherent(FileList *fileSet); + void OrderFileList(FileList *fileSet); + void Clear() { ClearAll(); } + + /// \brief Gets the FIRST Single SerieUID Fileset. + /// Deprecated; kept not to break the API + /// \note Caller must call OrderFileList first + /// @return the (first) Single SerieUID Fileset + const FileList &GetFileList() + { return *SingleSerieUIDFileSetHT.begin()->second; } + + GDCM_LEGACY( FileList *GetFirstCoherentFileList() ); + GDCM_LEGACY( FileList *GetNextCoherentFileList() ); + GDCM_LEGACY( FileList *GetCoherentFileList(std::string serieUID) ); + + FileList *GetFirstSingleSerieUIDFileSet(); + FileList *GetNextSingleSerieUIDFileSet(); + FileList *GetSingleSerieUIDFileSet(std::string serieUID); + /// brief returns the 'Series Instance UID' Single SerieUID FileSet + std::string GetCurrentSerieUIDFileSetUID() + { return (*ItFileSetHt).first; } + /// All the following allow user to restrict DICOM file to be part + /// of a particular serie + GDCM_LEGACY( void AddRestriction(TagKey const &key, std::string const &value) ); + /// Allow user to specify that the serie should also be consistent (== operation), + /// on the particular tag (group,element) + void AddRestriction(uint16_t group, uint16_t elem); + /// Same as above accept use the format: "0x1234|0x5678" + void AddRestriction(const std::string & tag) + { + unsigned int group, element; + sscanf( tag.c_str(), "%04x|%04x", &group, &element); + AddRestriction( group, element ); + } + /// Allow user to refine the selection of a serie by specifying operation (op) on a + /// particular tag (group, elem) with a particular value (value). + void AddRestriction(uint16_t group, uint16_t elem, + std::string const &value, int op); + + /// \brief Use additional series information such as ProtocolName + /// and SeriesName to identify when a single SeriesUID contains + /// multiple 3D volumes - as can occur with perfusion and DTI imaging + void SetUseSeriesDetails( bool useSeriesDetails ) + { + m_UseSeriesDetails = useSeriesDetails; + } + bool GetUseSeriesDetails() + { + return m_UseSeriesDetails; + } + /// \brief This function will add the following DICOM tag as being part of a + /// 'fake' uid. This is usefull when the Serie UID is not enough to disseminate + /// into multiple sub serie when needed: + /// 0020 0011 Series Number + /// 0018 0024 Sequence Name + /// 0018 0050 Slice Thickness + /// 0028 0010 Rows + /// 0028 0011 Columns + void CreateDefaultUniqueSeriesIdentifier(); + /// \brief Create a string that uniquely identifies a series. By default + // uses the SeriesUID. If UseSeriesDetails(true) has been called, + // then additional identifying information is used. + std::string CreateUniqueSeriesIdentifier( File * inFile ); + +/** + * \brief Sets the LoadMode as a boolean string. + * LD_NOSEQ, LD_NOSHADOW, LD_NOSHADOWSEQ + * ... (nothing more, right now) + * WARNING : before using LD_NOSHADOW, be sure *all* your files + * contain accurate values in the 0x0000 element (if any) + * of *each* Shadow Group. The parser will fail if the size is wrong ! + * @param mode Load mode to be used + */ + void SetLoadMode (int mode) { LoadMode = mode; } + +/// Brief User wants the files to be sorted Direct Order (default value) + void SetSortOrderToDirect() { DirectOrder = true; } + +/// Brief User wants the files to be sorted Reverse Order + void SetSortOrderToReverse() { DirectOrder = false; } + + /// to allow user to give is own comparison function + void SetUserLessThanFunction( BOOL_FUNCTION_PFILE_PFILE_POINTER userFunc ) + { UserLessThanFunction = userFunc; } + + XCoherentFileSetmap SplitOnOrientation(FileList *fileSet); + XCoherentFileSetmap SplitOnPosition(FileList *fileSet); + XCoherentFileSetmap SplitOnTagValue(FileList *fileSet, + uint16_t group, uint16_t element); + + +private: + void ClearAll(); + bool UserOrdering(FileList *fileSet); + bool ImagePositionPatientOrdering(FileList *fileSet); + bool ImageNumberOrdering(FileList *fileSet); + bool FileNameOrdering(FileList *fileSet); + +//Attributes: + + SingleSerieUIDFileSetmap SingleSerieUIDFileSetHT; + SingleSerieUIDFileSetmap::iterator ItFileSetHt; + +#ifndef GDCM_LEGACY_REMOVE + typedef std::pair<TagKey, std::string> Rule; + typedef std::vector<Rule> SerieRestrictions; + SerieRestrictions Restrictions; +#endif + + // New style for (extented) Rules + typedef struct { + uint16_t group; + uint16_t elem; + std::string value; + int op; + } ExRule; + typedef std::vector<ExRule> SerieExRestrictions; + SerieExRestrictions ExRestrictions; + SerieExRestrictions ExRefine; + + /// \brief Bit string integer (each one considered as a boolean) + /// Bit 0 : Skip Sequences, if possible + /// Bit 1 : Skip Shadow Groups if possible + /// Probabely, some more to add + int LoadMode; + + /// \brief whether we want to sort in direct order or not (reverse order). + /// To be used by aware user only + bool DirectOrder; + + /// \brief If user knows more about his images than gdcm does, + /// he may supply his own comparison function. + BOOL_FUNCTION_PFILE_PFILE_POINTER UserLessThanFunction; + + bool m_UseSeriesDetails; +}; + +} // end namespace gdcm + +//----------------------------------------------------------------------------- +#endif diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmTS.cxx b/Utilities/ITK/Utilities/gdcm/src/gdcmTS.cxx new file mode 100644 index 0000000000000000000000000000000000000000..48d21358455e89caae2b89e7ddc3c2431dd6248e --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmTS.cxx @@ -0,0 +1,365 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmTS.cxx,v $ + Language: C++ + Date: $Date: 2006/02/20 15:56:57 $ + Version: $Revision: 1.7 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#include "gdcmTS.h" +#include "gdcmDebug.h" +#include "gdcmUtil.h" +#include "gdcmDictSet.h" + +#include <fstream> +#include <string> +#include <iostream> +#include <ctype.h> // for isdigit + +// TODO +// troubles expected with TS : 1.2.840.113619.5.2 +// Implicit VR - Big Endian +// http://www.gemedicalsystemseurope.com/euen/it_solutions/pdf/lsqxi_rev2.pdf +// G.E. deliberately violated a lot of Dicom rules are +// (probabely to to avoid other people to read their images) +// Just try and error on new images : +// PrintFile debug filein=... +// and fix the bugs + +namespace gdcm +{ +//----------------------------------------------------------------------------- +/// \brief Transfer Syntaxes gdcm deals with (internal use only) +static const char *SpecialStrings[] = { + // Implicit VR Little Endian + "1.2.840.10008.1.2", + // Implicit VR Big Endian (G.E Private) + "1.2.840.113619.5.2", + // Explicit VR Little Endian + "1.2.840.10008.1.2.1", + // Deflated Explicit VR Little Endian + "1.2.840.10008.1.2.1.99", + // Explicit VR Big Endian + "1.2.840.10008.1.2.2", + // JPEG Baseline (Process 1) + "1.2.840.10008.1.2.4.50", + // JPEG Extended (Process 2 & 4) + "1.2.840.10008.1.2.4.51", + // JPEG Extended (Process 3 & 5) + "1.2.840.10008.1.2.4.52", + // JPEG Spectral Selection, Non-Hierarchical (Process 6 & 8) + "1.2.840.10008.1.2.4.53", + // JPEG Full Progression, Non-Hierarchical (Process 10 & 12) + "1.2.840.10008.1.2.4.55", + // JPEG Lossless, Non-Hierarchical (Process 14) + "1.2.840.10008.1.2.4.57", + // JPEG Lossless, Hierarchical, First-Order Prediction (Process 14, + // [Selection Value 1]) + "1.2.840.10008.1.2.4.70", + // JPEG-LS Lossless Image Compression + "1.2.840.10008.1.2.4.80", + // JPEG-LS Lossy (Near-Lossless) Image Compression + "1.2.840.10008.1.2.4.81", + // JPEG 2000 Lossless + "1.2.840.10008.1.2.4.90", + // JPEG 2000 + "1.2.840.10008.1.2.4.91", + // RLE Lossless + "1.2.840.10008.1.2.5", + // MPEG2 Main Profile @ Main Level + "1.2.840.10008.1.2.4.100", + // Unknown + "Unknown Transfer Syntax", // Pretty sure we never use this case... + NULL // Compilers have no obligation to finish by NULL, do it ourself +}; + +//----------------------------------------------------------------------------- +/// \brief auto generated function, to fill up the Dicom Dictionnary, +/// if relevant file is not found on user's disk +void FillDefaultTSDict(TSHT &ts); + +//----------------------------------------------------------------------------- +// Constructor / Destructor +TS::TS() +{ + std::string filename = DictSet::BuildDictPath() + DICT_TS; + std::ifstream from(filename.c_str()); + if ( !from ) + { + gdcmWarningMacro("Can't open dictionary" << filename.c_str()); + FillDefaultTSDict( TsMap ); + } + else + { + TSKey key; + TSAtr name; + + while (!from.eof()) + { + from >> key; + from >> std::ws; + std::getline(from, name); + + if (key != "") + { + TsMap[key] = name; + } + } + from.close(); + } +} + +TS::~TS() +{ + TsMap.clear(); +} + +//----------------------------------------------------------------------------- +// Public + +/// \brief returns occurence number of the given key +int TS::Count(TSKey const &key) +{ + return TsMap.count(key); +} + +/// \brief returns the human readable value of a Transfer Syntax string +TSAtr const &TS::GetValue(TSKey const &key) +{ + // First thing clean up the string + // (sometimes the transfer syntax is padded with spaces) + std::string copy = key; + while ( copy.size() && !isdigit((unsigned char)copy[copy.size()-1]) ) + { + copy.erase(copy.size()-1, 1); + } + + TSHT::const_iterator it = TsMap.find(copy); + if (it == TsMap.end()) + { + return GDCM_UNFOUND; + } + return it->second; +} +/** + * \brief Determines if the key passed corresponds to a 'Transfer Syntax' + * as defined in DICOM (and stored in gdcm::TS class) + * @return True when key is an actual 'Transfer Syntax'. + * False in all other cases. + */ +bool TS::IsTransferSyntax(TSKey const &key) +{ + TSHT::const_iterator it = TsMap.find(key); + return it != TsMap.end(); +} + +/** + * \brief Determines if the Transfer Syntax was already encountered + * and if it corresponds to a Run Length Encoding Lossless one + * @return True when Run Length Encoding Lossless found. + * False in all other cases. + */ +bool TS::IsRLELossless(TSKey const &key) +{ + bool r = false; + // First check this is an actual transfer syntax + if ( IsTransferSyntax(key) ) + { + if ( key == SpecialStrings[RLELossless] ) + { + r = true; + } + } + return r; +} + +/** + * \brief Determines if the Transfer Syntax was already encountered + * and if it corresponds to a 'classical' JPEG Lossless one + * @return True when 'classical' Lossless found. + * False in all other cases. + */ +bool TS::IsJPEGLossless(TSKey const &key) +{ + bool r = false; + // First check this is an actual transfer syntax + if ( IsTransferSyntax(key) ) + { + if ( key == SpecialStrings[JPEGFullProgressionProcess10_12] + || key == SpecialStrings[JPEGLosslessProcess14] + || key == SpecialStrings[JPEGLosslessProcess14_1] ) + { + r = true; + } + } + return r; +} + +/** + * \brief Determines if the Transfer Syntax was already encountered + * and if it corresponds to a 'classical' JPEG Lossy one + * @return True when 'classical' Lossy found. + * False in all other cases. + */ +bool TS::IsJPEGLossy(TSKey const &key) +{ + bool r = false; + // First check this is an actual transfer syntax + if ( IsTransferSyntax(key) ) + { + if ( key == SpecialStrings[JPEGBaselineProcess1] + || key == SpecialStrings[JPEGExtendedProcess2_4] + || key == SpecialStrings[JPEGExtendedProcess3_5] + || key == SpecialStrings[JPEGSpectralSelectionProcess6_8] ) + { + r = true; + } + } + return r; +} + +/** + * \brief Determines if the Transfer Syntax was already encountered + * and if it corresponds to a JPEG2000 one + * @return True when JPEG2000 (Lossly or LossLess) found. + * False in all other cases. + */ +bool TS::IsJPEG2000(TSKey const &key) +{ + bool r = false; + // First check this is an actual transfer syntax + if ( IsTransferSyntax(key) ) + { + if ( key == SpecialStrings[JPEG2000Lossless] + || key == SpecialStrings[JPEG2000] ) + { + r = true; + } + } + return r; +} + +/** + * \brief Determines if the Transfer Syntax corresponds to + * 'classical' Jpeg Lossless or Jpeg lossy. + * @return True when any form of JPEG found. False otherwise. + */ +bool TS::IsJPEG(TSKey const &key) +{ + bool r = false; + // First check this is an actual transfer syntax + if ( IsTransferSyntax(key) ) + { + if ( IsJPEGLossy( key ) + || IsJPEGLossless( key ) + || IsJPEG2000( key ) + || IsJPEGLS( key ) + ) + { + r = true; + } + } + return r; +} + +/** + * \brief Determines if the Transfer Syntax corresponds to any form + * of Jpeg-LS encoded Pixel data. + * @return True when any form of JPEG-LS found. False otherwise. + */ +bool TS::IsJPEGLS(TSKey const &key) +{ + bool r = false; + // First check this is an actual transfer syntax + if ( IsTransferSyntax(key) ) + { + if ( key == SpecialStrings[JPEGLSLossless] + || key == SpecialStrings[JPEGLSNearLossless] ) + { + r = true; + } + } + return r; +} + +/** + * \brief Determines if the Transfer Syntax corresponds to any form + * of MPEG encoded Pixel data. + * @return True when any form of MPEG found. False otherwise. + */ +bool TS::IsMPEG(TSKey const &key) +{ + bool r = false; + // First check this is an actual transfer syntax + if ( IsTransferSyntax(key) ) + { + if ( key == SpecialStrings[MPEG2MainProfile] ) + { + r = true; + } + } + return r; +} + +/** + * \brief GetSpecialTransferSyntax ?? + * @param key TSKey const &key ?? + * @return TS::SpecialType ??. + */ +TS::SpecialType TS::GetSpecialTransferSyntax(TSKey const &key) +{ + for (int i = 0; SpecialStrings[i] != NULL; i++) + { + if ( SpecialStrings[i] == key ) + { + return SpecialType(i); + } + } + return UnknownTS; +} + +/** + * \brief GetSpecialTransferSyntax ?? + * @param t SpecialType t ?? + * @return char* TS : SpecialStrings[t] ??. + */ +const char* TS::GetSpecialTransferSyntax(SpecialType t) +{ + return SpecialStrings[t]; +} + +//----------------------------------------------------------------------------- +// Protected + +//----------------------------------------------------------------------------- +// Private + +//----------------------------------------------------------------------------- +// Print +/** + * \brief Print all + * @param os The output stream to be written to. + */ +void TS::Print(std::ostream &os,std::string const &) +{ + itksys_ios::ostringstream s; + + for (TSHT::const_iterator it = TsMap.begin(); it != TsMap.end(); ++it) + { + s << "TS : " << it->first << " = " << it->second << std::endl; + } + os << s.str(); +} + +//----------------------------------------------------------------------------- +} // end namespace gdcm diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmTS.h b/Utilities/ITK/Utilities/gdcm/src/gdcmTS.h new file mode 100644 index 0000000000000000000000000000000000000000..9b2d7032b162997ea52442410db6b6f3cc9741cd --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmTS.h @@ -0,0 +1,94 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmTS.h,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:39 $ + Version: $Revision: 1.4 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#ifndef GDCMTS_H +#define GDCMTS_H + +#include "gdcmCommon.h" + +#include <map> +#include <string> +#include <iostream> + +namespace gdcm +{ +//----------------------------------------------------------------------------- +typedef std::string TSKey; +typedef std::string TSAtr; +typedef std::map<TSKey, TSAtr> TSHT; // Transfer Syntax Hash Table + + +//----------------------------------------------------------------------------- +/** + * \brief Container for dicom 'Transfer Syntax' Hash Table + * \note This is a singleton + */ +class GDCM_EXPORT TS +{ +public: +enum SpecialType { + ImplicitVRLittleEndian = 0, + ImplicitVRBigEndianPrivateGE, + ExplicitVRLittleEndian, + DeflatedExplicitVRLittleEndian, + ExplicitVRBigEndian, + JPEGBaselineProcess1, + JPEGExtendedProcess2_4, + JPEGExtendedProcess3_5, + JPEGSpectralSelectionProcess6_8, + JPEGFullProgressionProcess10_12, + JPEGLosslessProcess14, + JPEGLosslessProcess14_1, + JPEGLSLossless, + JPEGLSNearLossless, + JPEG2000Lossless, + JPEG2000, + RLELossless, + MPEG2MainProfile, + UnknownTS +}; + +public: + TS(); + ~TS(); + + void Print(std::ostream &os = std::cout, + std::string const &s = ""); + + int Count(TSKey const &key); + TSAtr const &GetValue(TSKey const &key); + bool IsTransferSyntax(TSKey const &key); + bool IsRLELossless(TSKey const &key); + bool IsJPEGLossless(TSKey const&key); + bool IsJPEGLossy(TSKey const&key); + bool IsJPEG2000(TSKey const &key); + bool IsJPEG(TSKey const &key); + bool IsJPEGLS(TSKey const &key); + bool IsMPEG(TSKey const &key); + + // This should be deprecated very soon + SpecialType GetSpecialTransferSyntax(TSKey const &key); + const char* GetSpecialTransferSyntax(SpecialType t); + +private: + TSHT TsMap; +}; +} // end namespace gdcm + +//----------------------------------------------------------------------------- +#endif diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmUtil.cxx b/Utilities/ITK/Utilities/gdcm/src/gdcmUtil.cxx new file mode 100644 index 0000000000000000000000000000000000000000..ac993725a5361fea73997f1a46cc23e8435105de --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmUtil.cxx @@ -0,0 +1,1176 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmUtil.cxx,v $ + Language: C++ + Date: $Date: 2006/02/20 15:56:58 $ + Version: $Revision: 1.37 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#include "gdcmUtil.h" +#include "gdcmDebug.h" + +#include <iostream> +#include <stdarg.h> // for va_list + +// For GetCurrentDate, GetCurrentTime +#include <time.h> +#include <sys/types.h> +#include <sys/stat.h> + +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__) +#include <sys/timeb.h> +#else +#include <sys/time.h> +#endif + +#include <stdarg.h> //only included in implementation file +#include <stdio.h> //only included in implementation file + +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__) + #include <winsock.h> // for gethostname and gethostbyname and GetTickCount... +// I haven't find a way to determine wether we need to under GetCurrentTime or not... +// I think the best solution would simply to get rid of this problematic function +// and use a 'less' common name... +#if !defined(__BORLANDC__) || (__BORLANDC__ >= 0x0560) + #undef GetCurrentTime +#endif +#else + #include <unistd.h> // for gethostname + #include <netdb.h> // for gethostbyname +#endif + +// For GetMACAddress +#ifdef _WIN32 + #include <snmp.h> + #include <conio.h> +#else + #include <unistd.h> + #include <stdlib.h> + #include <string.h> + #include <sys/types.h> +#endif + +#ifdef CMAKE_HAVE_SYS_IOCTL_H + #include <sys/ioctl.h> // For SIOCGIFCONF on Linux +#endif +#ifdef CMAKE_HAVE_SYS_SOCKET_H + #include <sys/socket.h> +#endif +#ifdef CMAKE_HAVE_SYS_SOCKIO_H + #include <sys/sockio.h> // For SIOCGIFCONF on SunOS +#endif +#ifdef CMAKE_HAVE_NET_IF_H + #include <net/if.h> +#endif +#ifdef CMAKE_HAVE_NETINET_IN_H + #include <netinet/in.h> //For IPPROTO_IP +#endif +#ifdef CMAKE_HAVE_NET_IF_DL_H + #include <net/if_dl.h> +#endif +#if defined(CMAKE_HAVE_NET_IF_ARP_H) && defined(__sun) + // This is absolutely necessary on SunOS + #include <net/if_arp.h> +#endif + +// For GetCurrentThreadID() +#ifdef __linux__ + #include <sys/types.h> + #include <linux/unistd.h> +#endif +#ifdef __sun + #include <thread.h> +#endif + +namespace gdcm +{ +//------------------------------------------------------------------------- +const std::string Util::GDCM_UID = "1.2.826.0.1.3680043.2.1143"; +std::string Util::RootUID = GDCM_UID; +/* + * File Meta Information Version (0002,0001) shall contain a two byte OB + * value consisting of a 0x00 byte, followed by 0x01 byte, and not the + * value 0x0001 encoded as a little endian 16 bit short value, + * which would be the other way around... + */ +const uint16_t Util::FMIV = 0x0100; +uint8_t *Util::FileMetaInformationVersion = (uint8_t *)&FMIV; +std::string Util::GDCM_MAC_ADRESS = GetMACAddress(); + +//------------------------------------------------------------------------- +// Public +/** + * \brief Provide a better 'c++' approach for sprintf + * For example c code is: + * char result[2048]; // hope 2048 is enough + * sprintf(result, "%04x|%04x", group , elem); + * + * c++ code is + * itksys_ios::ostringstream buf; + * buf << std::right << std::setw(4) << std::setfill('0') << std::hex + * << group << "|" << std::right << std::setw(4) << std::setfill('0') + * << std::hex << elem; + * buf.str(); + * + * gdcm style code is + * string result; + * result = gdcm::Util::Format("%04x|%04x", group , elem); + */ +std::string Util::Format(const char *format, ...) +{ + char buffer[2048]; // hope 2048 is enough + va_list args; + va_start(args, format); + vsprintf(buffer, format, args); //might be a security flaw + va_end(args); // Each invocation of va_start should be matched + // by a corresponding invocation of va_end + // args is then 'undefined' + return buffer; +} + + +/** + * \brief Because not available in C++ (?) + * @param str string to check + * @param tokens std::vector to receive the tokenized substrings + * @param delimiters string containing the character delimitors + + */ +void Util::Tokenize (const std::string &str, + std::vector<std::string> &tokens, + const std::string &delimiters) +{ + std::string::size_type lastPos = str.find_first_not_of(delimiters,0); + std::string::size_type pos = str.find_first_of (delimiters,lastPos); + while (std::string::npos != pos || std::string::npos != lastPos) + { + tokens.push_back(str.substr(lastPos, pos - lastPos)); + lastPos = str.find_first_not_of(delimiters, pos); + pos = str.find_first_of (delimiters, lastPos); + } +} + +/** + * \brief Because not available in C++ (?) + * Counts the number of occurences of a substring within a string + * @param str string to check + * @param subStr substring to count + */ + +int Util::CountSubstring (const std::string &str, + const std::string &subStr) +{ + int count = 0; // counts how many times it appears + std::string::size_type x = 0; // The index position in the string + + do + { + x = str.find(subStr,x); // Find the substring + if (x != std::string::npos) // If present + { + count++; // increase the count + x += subStr.length(); // Skip this word + } + } + while (x != std::string::npos);// Carry on until not present + + return count; +} + +/** + * \brief Checks whether a 'string' is printable or not (in order + * to avoid corrupting the terminal of invocation when printing) + * @param s string to check + */ +bool Util::IsCleanString(std::string const &s) +{ + for(unsigned int i=0; i<s.size(); i++) + { + if (!isprint((unsigned char)s[i]) ) + { + return false; + } + } + return true; +} + +/** + * \brief Checks whether an 'area' is printable or not (in order + * to avoid corrupting the terminal of invocation when printing) + * @param s area to check (uint8_t is just for prototyping. feel free to cast) + * @param l area length to check + */ +bool Util::IsCleanArea(uint8_t *s, int l) +{ + for( int i=0; i<l; i++) + { + if (!isprint((unsigned char)s[i]) ) + { + return false; + } + } + return true; +} +/** + * \brief Weed out a string from the non-printable characters (in order + * to avoid corrupting the terminal of invocation when printing) + * @param s string to check (uint8_t is just for prototyping. feel free to cast) + */ +std::string Util::CreateCleanString(std::string const &s) +{ + std::string str = s; + + for(unsigned int i=0; i<str.size(); i++) + { + if (!isprint((unsigned char)str[i]) ) + { + str[i] = '.'; + } + } + + if (str.size() > 0 ) + { + if (!isprint((unsigned char)s[str.size()-1]) ) + { + if (s[str.size()-1] == 0 ) + { + str[str.size()-1] = ' '; + } + } + } + + return str; +} + +/** + * \brief Weed out a string from the non-printable characters (in order + * to avoid corrupting the terminal of invocation when printing) + * @param s area to process (uint8_t is just for prototyping. feel free to cast) + * @param l area length to check + */ +std::string Util::CreateCleanString(uint8_t *s, int l) +{ + std::string str; + + for( int i=0; i<l; i++) + { + if (!isprint((unsigned char)s[i]) ) + { + str = str + '.'; + } + else + { + str = str + (char )s[i]; + } + } + + return str; +} +/** + * \brief Add a SEPARATOR to the end of the name if necessary + * @param pathname file/directory name to normalize + */ +std::string Util::NormalizePath(std::string const &pathname) +{ + const char SEPARATOR_X = '/'; + const char SEPARATOR_WIN = '\\'; + const std::string SEPARATOR = "/"; + std::string name = pathname; + int size = name.size(); + + if ( name[size-1] != SEPARATOR_X && name[size-1] != SEPARATOR_WIN ) + { + name += SEPARATOR; + } + return name; +} + +/** + * \brief Get the (directory) path from a full path file name + * @param fullName file/directory name to extract Path from + */ +std::string Util::GetPath(std::string const &fullName) +{ + std::string res = fullName; + int pos1 = res.rfind("/"); + int pos2 = res.rfind("\\"); + if ( pos1 > pos2 ) + { + res.resize(pos1); + } + else + { + res.resize(pos2); + } + + return res; +} + +/** + * \brief Get the (last) name of a full path file name + * @param fullName file/directory name to extract end name from + */ +std::string Util::GetName(std::string const &fullName) +{ + std::string filename = fullName; + + std::string::size_type slash_pos = filename.rfind("/"); + std::string::size_type backslash_pos = filename.rfind("\\"); + slash_pos = slash_pos > backslash_pos ? slash_pos : backslash_pos; + if (slash_pos != std::string::npos ) + { + return filename.substr(slash_pos + 1); + } + else + { + return filename; + } +} + +/** + * \brief Get the current date of the system in a dicom string + */ +std::string Util::GetCurrentDate() +{ + char tmp[512]; + time_t tloc; + time (&tloc); + strftime(tmp,512,"%Y%m%d", localtime(&tloc) ); + return tmp; +} + +/** + * \brief Get the current time of the system in a dicom string + */ +std::string Util::GetCurrentTime() +{ + char tmp[512]; + time_t tloc; + time (&tloc); + strftime(tmp,512,"%H%M%S", localtime(&tloc) ); + return tmp; +} + +/** + * \brief Get both the date and time at the same time to avoid problem + * around midnight where the two calls could be before and after midnight + */ +std::string Util::GetCurrentDateTime() +{ + char tmp[40]; + long milliseconds; + time_t timep; + + // We need implementation specific functions to obtain millisecond precision +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__) + struct timeb tb; + ::ftime(&tb); + timep = tb.time; + milliseconds = tb.millitm; +#else + struct timeval tv; + gettimeofday (&tv, NULL); + timep = tv.tv_sec; + // Compute milliseconds from microseconds. + milliseconds = tv.tv_usec / 1000; +#endif + // Obtain the time of day, and convert it to a tm struct. + struct tm *ptm = localtime (&timep); + // Format the date and time, down to a single second. + strftime (tmp, sizeof (tmp), "%Y%m%d%H%M%S", ptm); + + // Add milliseconds + // Don't use Util::Format to accelerate execution of code + char tmpAll[80]; + sprintf(tmpAll,"%s%03ld",tmp,milliseconds); + + return tmpAll; +} + +unsigned int Util::GetCurrentThreadID() +{ +// FIXME the implementation is far from complete +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__) + return (unsigned int)GetCurrentThreadId(); +#else +#ifdef __linux__ + return 0; + // Doesn't work on fedora, but is in the man page... + //return (unsigned int)gettid(); +#else +#ifdef __sun + return (unsigned int)thr_self(); +#else + //default implementation + return 0; +#endif // __sun +#endif // __linux__ +#endif // Win32 +} + +unsigned int Util::GetCurrentProcessID() +{ +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__) + // NOTE: There is also a _getpid()... + return (unsigned int)GetCurrentProcessId(); +#else + // get process identification, POSIX + return (unsigned int)getpid(); +#endif +} + +/** + * \brief tells us whether the processor we are working with is BigEndian or not + */ +bool Util::IsCurrentProcessorBigEndian() +{ +#if defined(GDCM_WORDS_BIGENDIAN) + return true; +#else + return false; +#endif +} + +/** + * \brief Create a /DICOM/ string: + * It should a of even length (no odd length ever) + * It can contain as many (if you are reading this from your + * editor the following character is backslash followed by zero + * that needed to be escaped with an extra backslash for doxygen) \\0 + * as you want. + */ +std::string Util::DicomString(const char *s, size_t l) +{ + std::string r(s, s+l); + gdcmAssertMacro( !(r.size() % 2) ); // == basically 'l' is even + return r; +} + +/** + * \brief Create a /DICOM/ string: + * It should a of even length (no odd length ever) + * It can contain as many (if you are reading this from your + * editor the following character is backslash followed by zero + * that needed to be escaped with an extra backslash for doxygen) \\0 + * as you want. + * This function is similar to DicomString(const char*), + * except it doesn't take a length. + * It only pad with a null character if length is odd + */ +std::string Util::DicomString(const char *s) +{ + size_t l = strlen(s); + if ( l%2 ) + { + l++; + } + std::string r(s, s+l); + gdcmAssertMacro( !(r.size() % 2) ); + return r; +} + +/** + * \brief Safely check the equality of two Dicom String: + * - Both strings should be of even length + * - We allow padding of even length string by either + * a null character of a space + */ +bool Util::DicomStringEqual(const std::string &s1, const char *s2) +{ + // s2 is the string from the DICOM reference e.g. : 'MONOCHROME1' + std::string s1_even = s1; //Never change input parameter + std::string s2_even = DicomString( s2 ); + if ( s1_even[s1_even.size()-1] == ' ' ) + { + s1_even[s1_even.size()-1] = '\0'; //replace space character by null + } + return s1_even == s2_even; +} + +/** + * \brief Safely compare two Dicom String: + * - Both strings should be of even length + * - We allow padding of even length string by either + * a null character of a space + */ +bool Util::CompareDicomString(const std::string &s1, const char *s2, int op) +{ + // s2 is the string from the DICOM reference e.g. : 'MONOCHROME1' + std::string s1_even = s1; //Never change input parameter + std::string s2_even = DicomString( s2 ); + if ( s1_even[s1_even.size()-1] == ' ' ) + { + s1_even[s1_even.size()-1] = '\0'; //replace space character by null + } + switch (op) + { + case GDCM_EQUAL : + return s1_even == s2_even; + case GDCM_DIFFERENT : + return s1_even != s2_even; + case GDCM_GREATER : + return s1_even > s2_even; + case GDCM_GREATEROREQUAL : + return s1_even >= s2_even; + case GDCM_LESS : + return s1_even < s2_even; + case GDCM_LESSOREQUAL : + return s1_even <= s2_even; + default : + gdcmDebugMacro(" Wrong operator : " << op); + return false; + } +} + +#ifdef _WIN32 + typedef BOOL(WINAPI * pSnmpExtensionInit) ( + IN DWORD dwTimeZeroReference, + OUT HANDLE * hPollForTrapEvent, + OUT AsnObjectIdentifier * supportedView); + + typedef BOOL(WINAPI * pSnmpExtensionTrap) ( + OUT AsnObjectIdentifier * enterprise, + OUT AsnInteger * genericTrap, + OUT AsnInteger * specificTrap, + OUT AsnTimeticks * timeStamp, + OUT RFC1157VarBindList * variableBindings); + + typedef BOOL(WINAPI * pSnmpExtensionQuery) ( + IN BYTE requestType, + IN OUT RFC1157VarBindList * variableBindings, + OUT AsnInteger * errorStatus, + OUT AsnInteger * errorIndex); + + typedef BOOL(WINAPI * pSnmpExtensionInitEx) ( + OUT AsnObjectIdentifier * supportedView); +#endif //_WIN32 + +#ifdef __sgi +static int SGIGetMacAddress(unsigned char *addr) +{ + FILE *f = popen("/etc/nvram eaddr","r"); + if(f == 0) + { + return -1; + } + unsigned int x[6]; + if(fscanf(f,"%02x:%02x:%02x:%02x:%02x:%02x", + x,x+1,x+2,x+3,x+4,x+5) != 6) + { + pclose(f); + return -1; + } + for(unsigned int i = 0; i < 6; i++) + { + addr[i] = static_cast<unsigned char>(x[i]); + } + return 0; +} +#endif + +/// \brief gets current M.A.C adress (for internal use only) +int GetMacAddrSys ( unsigned char *addr ); +int GetMacAddrSys ( unsigned char *addr ) +{ +#ifdef _WIN32 + WSADATA WinsockData; + if ( (WSAStartup(MAKEWORD(2, 0), &WinsockData)) != 0 ) + { + std::cerr << "in Get MAC Adress (internal) : This program requires Winsock 2.x!" + << std::endl; + return -1; + } + + HANDLE PollForTrapEvent; + AsnObjectIdentifier SupportedView; + UINT OID_ifEntryType[] = { 1, 3, 6, 1, 2, 1, 2, 2, 1, 3 }; + UINT OID_ifEntryNum[] = { 1, 3, 6, 1, 2, 1, 2, 1 }; + UINT OID_ipMACEntAddr[] = { 1, 3, 6, 1, 2, 1, 2, 2, 1, 6 }; + AsnObjectIdentifier MIB_ifMACEntAddr = { + sizeof(OID_ipMACEntAddr) / sizeof(UINT), OID_ipMACEntAddr }; + AsnObjectIdentifier MIB_ifEntryType = { + sizeof(OID_ifEntryType) / sizeof(UINT), OID_ifEntryType }; + AsnObjectIdentifier MIB_ifEntryNum = { + sizeof(OID_ifEntryNum) / sizeof(UINT), OID_ifEntryNum }; + RFC1157VarBindList varBindList; + RFC1157VarBind varBind[2]; + AsnInteger errorStatus; + AsnInteger errorIndex; + AsnObjectIdentifier MIB_NULL = { 0, 0 }; + int ret; + int dtmp; + int j = 0; + + // Load the SNMP dll and get the addresses of the functions necessary + HINSTANCE m_hInst = LoadLibrary("inetmib1.dll"); + if (m_hInst < (HINSTANCE) HINSTANCE_ERROR) + { + return -1; + } + pSnmpExtensionInit m_Init = + (pSnmpExtensionInit) GetProcAddress(m_hInst, "SnmpExtensionInit"); + pSnmpExtensionQuery m_Query = + (pSnmpExtensionQuery) GetProcAddress(m_hInst, "SnmpExtensionQuery"); + m_Init(GetTickCount(), &PollForTrapEvent, &SupportedView); + + /* Initialize the variable list to be retrieved by m_Query */ + varBindList.list = varBind; + varBind[0].name = MIB_NULL; + varBind[1].name = MIB_NULL; + + // Copy in the OID to find the number of entries in the + // Inteface table + varBindList.len = 1; // Only retrieving one item + SNMP_oidcpy(&varBind[0].name, &MIB_ifEntryNum); + m_Query(ASN_RFC1157_GETNEXTREQUEST, &varBindList, &errorStatus, + &errorIndex); +// printf("# of adapters in this system : %i\n", +// varBind[0].value.asnValue.number); + varBindList.len = 2; + + // Copy in the OID of ifType, the type of interface + SNMP_oidcpy(&varBind[0].name, &MIB_ifEntryType); + + // Copy in the OID of ifPhysAddress, the address + SNMP_oidcpy(&varBind[1].name, &MIB_ifMACEntAddr); + + do + { + // Submit the query. Responses will be loaded into varBindList. + // We can expect this call to succeed a # of times corresponding + // to the # of adapters reported to be in the system + ret = m_Query(ASN_RFC1157_GETNEXTREQUEST, &varBindList, &errorStatus, + &errorIndex); + if (!ret) + { + ret = 1; + } + else + { + // Confirm that the proper type has been returned + ret = SNMP_oidncmp(&varBind[0].name, &MIB_ifEntryType, + MIB_ifEntryType.idLength); + } + if (!ret) + { + j++; + dtmp = varBind[0].value.asnValue.number; + + // Type 6 describes ethernet interfaces + if (dtmp == 6) + { + // Confirm that we have an address here + ret = SNMP_oidncmp(&varBind[1].name, &MIB_ifMACEntAddr, + MIB_ifMACEntAddr.idLength); + if ( !ret && varBind[1].value.asnValue.address.stream != NULL ) + { + if ( (varBind[1].value.asnValue.address.stream[0] == 0x44) + && (varBind[1].value.asnValue.address.stream[1] == 0x45) + && (varBind[1].value.asnValue.address.stream[2] == 0x53) + && (varBind[1].value.asnValue.address.stream[3] == 0x54) + && (varBind[1].value.asnValue.address.stream[4] == 0x00) ) + { + // Ignore all dial-up networking adapters + std::cerr << "in Get MAC Adress (internal) : Interface #" + << j << " is a DUN adapter\n"; + continue; + } + if ( (varBind[1].value.asnValue.address.stream[0] == 0x00) + && (varBind[1].value.asnValue.address.stream[1] == 0x00) + && (varBind[1].value.asnValue.address.stream[2] == 0x00) + && (varBind[1].value.asnValue.address.stream[3] == 0x00) + && (varBind[1].value.asnValue.address.stream[4] == 0x00) + && (varBind[1].value.asnValue.address.stream[5] == 0x00) ) + { + // Ignore NULL addresses returned by other network + // interfaces + std::cerr << "in Get MAC Adress (internal) : Interface #" + << j << " is a NULL address\n"; + continue; + } + memcpy( addr, varBind[1].value.asnValue.address.stream, 6); + } + } + } + } while (!ret); + + // Free the bindings + SNMP_FreeVarBind(&varBind[0]); + SNMP_FreeVarBind(&varBind[1]); + return 0; +#endif //Win32 version + +#if defined(__sgi) + return SGIGetMacAddress(addr); +#endif // __sgi + + +// implementation for POSIX system +#if defined(CMAKE_HAVE_NET_IF_ARP_H) && defined(__sun) + //The POSIX version is broken anyway on Solaris, plus would require full + //root power + struct arpreq parpreq; + struct sockaddr_in *psa; + struct hostent *phost; + char hostname[MAXHOSTNAMELEN]; + char **paddrs; + int sock, status=0; + + if (gethostname(hostname, MAXHOSTNAMELEN) != 0 ) + { + perror("in Get MAC Adress (internal) : gethostname"); + return -1; + } + phost = gethostbyname(hostname); + paddrs = phost->h_addr_list; + + sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (sock == -1 ) + { + perror("in Get MAC Adress (internal) : sock"); + return -1; + } + memset(&parpreq, 0, sizeof(struct arpreq)); + psa = (struct sockaddr_in *) &parpreq.arp_pa; + + memset(psa, 0, sizeof(struct sockaddr_in)); + psa->sin_family = AF_INET; + memcpy(&psa->sin_addr, *paddrs, sizeof(struct in_addr)); + + status = ioctl(sock, SIOCGARP, &parpreq); + if (status == -1 ) + { + perror("in Get MAC Adress (internal) : SIOCGARP"); + return -1; + } + memcpy(addr, parpreq.arp_ha.sa_data, 6); + + return 0; +#else +#ifdef CMAKE_HAVE_NET_IF_H + int sd; + struct ifreq ifr, *ifrp; + struct ifconf ifc; + char buf[1024]; + int n, i; + unsigned char *a; +#if defined(AF_LINK) && (!defined(SIOCGIFHWADDR) && !defined(SIOCGENADDR)) + struct sockaddr_dl *sdlp; +#endif + +// +// BSD 4.4 defines the size of an ifreq to be +// max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len +// However, under earlier systems, sa_len isn't present, so the size is +// just sizeof(struct ifreq) +// We should investigate the use of SIZEOF_ADDR_IFREQ +// +#ifdef HAVE_SA_LEN + #ifndef max + #define max(a,b) ((a) > (b) ? (a) : (b)) + #endif + #define ifreq_size(i) max(sizeof(struct ifreq),\ + sizeof((i).ifr_name)+(i).ifr_addr.sa_len) +#else + #define ifreq_size(i) sizeof(struct ifreq) +#endif // HAVE_SA_LEN + + if ( (sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0 ) + { + return -1; + } + memset(buf, 0, sizeof(buf)); + ifc.ifc_len = sizeof(buf); + ifc.ifc_buf = buf; + if (ioctl (sd, SIOCGIFCONF, (char *)&ifc) < 0) + { + close(sd); + return -1; + } + n = ifc.ifc_len; + for (i = 0; i < n; i+= ifreq_size(*ifrp) ) + { + ifrp = (struct ifreq *)((char *) ifc.ifc_buf+i); + strncpy(ifr.ifr_name, ifrp->ifr_name, IFNAMSIZ); +#ifdef SIOCGIFHWADDR + if (ioctl(sd, SIOCGIFHWADDR, &ifr) < 0) + continue; + a = (unsigned char *) &ifr.ifr_hwaddr.sa_data; +#else +#ifdef SIOCGENADDR + // In theory this call should also work on Sun Solaris, but apparently + // SIOCGENADDR is not implemented properly thus the call + // ioctl(sd, SIOCGENADDR, &ifr) always returns errno=2 + // (No such file or directory) + // Furthermore the DLAPI seems to require full root access + if (ioctl(sd, SIOCGENADDR, &ifr) < 0) + continue; + a = (unsigned char *) ifr.ifr_enaddr; +#else +#ifdef AF_LINK + sdlp = (struct sockaddr_dl *) &ifrp->ifr_addr; + if ((sdlp->sdl_family != AF_LINK) || (sdlp->sdl_alen != 6)) + continue; + a = (unsigned char *) &sdlp->sdl_data[sdlp->sdl_nlen]; +#else + perror("in Get MAC Adress (internal) : No way to access hardware"); + close(sd); + return -1; +#endif // AF_LINK +#endif // SIOCGENADDR +#endif // SIOCGIFHWADDR + if (!a[0] && !a[1] && !a[2] && !a[3] && !a[4] && !a[5]) continue; + + if (addr) + { + memcpy(addr, a, 6); + close(sd); + return 0; + } + } + close(sd); +#endif + // Not implemented platforms (or no cable !) + perror("in Get MAC Adress (internal) : There was a configuration problem (or no cable !) on your plateform"); + memset(addr,0,6); + return -1; +#endif //__sun +} + +/** + * \brief Mini function to return the last digit from a number express in base 256 + * pre condition data contain an array of 6 unsigned char + * post condition carry contain the last digit + */ +inline int getlastdigit(unsigned char *data) +{ + int extended, carry = 0; + for(int i=0;i<6;i++) + { + extended = (carry << 8) + data[i]; + data[i] = extended / 10; + carry = extended % 10; + } + return carry; +} + +/** + * \brief Encode the mac address on a fixed length string of 15 characters. + * we save space this way. + */ +std::string Util::GetMACAddress() +{ + // This code is the result of a long internet search to find something + // as compact as possible (not OS independant). We only have to separate + // 3 OS: Win32, SunOS and 'real' POSIX + // http://groups-beta.google.com/group/comp.unix.solaris/msg/ad36929d783d63be + // http://bdn.borland.com/article/0,1410,26040,00.html + unsigned char addr[6]; + + int stat = GetMacAddrSys(addr); + if (stat == 0) + { + // We need to convert a 6 digit number from base 256 to base 10, using integer + // would requires a 48bits one. To avoid this we have to reimplement the div + modulo + // with string only + bool zero = false; + int res; + std::string sres; + while(!zero) + { + res = getlastdigit(addr); + sres.insert(sres.begin(), '0' + res); + zero = (addr[0] == 0) && (addr[1] == 0) && (addr[2] == 0) + && (addr[3] == 0) && (addr[4] == 0) && (addr[5] == 0); + } + + return sres; + } + else + { + gdcmWarningMacro("Problem in finding the MAC Address"); + return ""; + } +} + +/** + * \brief Creates a new UID. As stipulated in the DICOM ref + * each time a DICOM image is created it should have + * a unique identifier (URI) + * @param root is the DICOM prefix assigned by IOS group + */ +std::string Util::CreateUniqueUID(const std::string &root) +{ + std::string prefix; + std::string append; + if ( root.empty() ) + { + // gdcm UID prefix, as supplied by http://www.medicalconnections.co.uk + prefix = RootUID; + } + else + { + prefix = root; + } + + // A root was specified use it to forge our new UID: + append += "."; + //append += Util::GetMACAddress(); // to save CPU time + append += Util::GDCM_MAC_ADRESS; + append += "."; + append += Util::GetCurrentDateTime(); + + //Also add a mini random number just in case: + char tmp[10]; + int r = (int) (100.0*rand()/RAND_MAX); + // Don't use Util::Format to accelerate the execution + sprintf(tmp,"%02d", r); + append += tmp; + + // If append is too long we need to rehash it + if ( (prefix + append).size() > 64 ) + { + gdcmErrorMacro( "Size of UID is too long." ); + // we need a hash function to truncate this number + // if only md5 was cross plateform + // MD5(append); + } + + return prefix + append; +} + +void Util::SetRootUID(const std::string &root) +{ + if ( root.empty() ) + RootUID = GDCM_UID; + else + RootUID = root; +} + +const std::string &Util::GetRootUID() +{ + return RootUID; +} + +//------------------------------------------------------------------------- +/** + * \brief binary_write binary_write + * @param os ostream to write to + * @param val 16 bits value to write + */ +std::ostream &binary_write(std::ostream &os, const uint16_t &val) +{ +#if defined(GDCM_WORDS_BIGENDIAN) || defined(GDCM_FORCE_BIGENDIAN_EMULATION) + uint16_t swap; + swap = ( val << 8 | val >> 8 ); + + return os.write(reinterpret_cast<const char*>(&swap), 2); +#else + return os.write(reinterpret_cast<const char*>(&val), 2); +#endif //GDCM_WORDS_BIGENDIAN +} + +/** + * \brief binary_write binary_write + * @param os ostream to write to + * @param val 32 bits value to write + */ +std::ostream &binary_write(std::ostream &os, const uint32_t &val) +{ +#if defined(GDCM_WORDS_BIGENDIAN) || defined(GDCM_FORCE_BIGENDIAN_EMULATION) + uint32_t swap; + swap = ( (val<<24) | ((val<<8) & 0x00ff0000) | + ((val>>8) & 0x0000ff00) | (val>>24) ); + return os.write(reinterpret_cast<const char*>(&swap), 4); +#else + return os.write(reinterpret_cast<const char*>(&val), 4); +#endif //GDCM_WORDS_BIGENDIAN +} + +/** + * \brief binary_write binary_write + * @param os ostream to write to + * @param val double (64 bits) value to write + */ +std::ostream &binary_write(std::ostream &os, const double &val) +{ +#if defined(GDCM_WORDS_BIGENDIAN) || defined(GDCM_FORCE_BIGENDIAN_EMULATION) + double swap = val; + + char *beg = (char *)&swap; + char *end = beg + 7; + char t; + for (unsigned int i = 0; i<7; i++) + { + t = *beg; + *beg = *end; + *end = t; + beg++, + end--; + } + return os.write(reinterpret_cast<const char*>(&swap), 8); +#else + return os.write(reinterpret_cast<const char*>(&val), 8); +#endif //GDCM_WORDS_BIGENDIAN +} + +/** + * \brief binary_write binary_write + * @param os ostream to write to + * @param val 8 bits characters aray to write + */ +std::ostream &binary_write(std::ostream &os, const char *val) +{ + return os.write(val, strlen(val)); +} + +/** + * \brief binary_write binary_write + * @param os ostream to write to + * @param val std::string value to write + */ +std::ostream &binary_write(std::ostream &os, std::string const &val) +{ + return os.write(val.c_str(), val.size()); +} + +/** + * \brief binary_write binary_write + * @param os ostream to write to + * @param val 8 bits 'characters' aray to write + * @param len length of the 'value' to be written + */ +std::ostream &binary_write(std::ostream &os, const uint8_t *val, size_t len) +{ + // We are writting sizeof(char) thus no need to swap bytes + return os.write(reinterpret_cast<const char*>(val), len); +} + +/** + * \brief binary_write binary_write + * @param os ostream to write to + * @param val 16 bits words aray to write + * @param len length (in bytes) of the 'value' to be written + */ +std::ostream &binary_write(std::ostream &os, const uint16_t *val, size_t len) +{ +// This is tricky since we are writting two bytes buffer. +// Be carefull with little endian vs big endian. +// Also this other trick is to allocate a small (efficient) buffer that store +// intermediate result before writting it. +#if defined(GDCM_WORDS_BIGENDIAN) || defined(GDCM_FORCE_BIGENDIAN_EMULATION) + const int BUFFER_SIZE = 4096; + static char buffer[BUFFER_SIZE]; + uint16_t *binArea16 = (uint16_t*)val; //for the const + + // how many BUFFER_SIZE long pieces in binArea ? + int nbPieces = len/BUFFER_SIZE; //(16 bits = 2 Bytes) + int remainingSize = len%BUFFER_SIZE; + + for (int j=0;j<nbPieces;j++) + { + uint16_t *pbuffer = (uint16_t*)buffer; //reinitialize pbuffer + for (int i = 0; i < BUFFER_SIZE/2; i++) + { + *pbuffer = *binArea16 >> 8 | *binArea16 << 8; + pbuffer++; + binArea16++; + } + os.write ( buffer, BUFFER_SIZE ); + } + if ( remainingSize > 0) + { + uint16_t *pbuffer = (uint16_t*)buffer; //reinitialize pbuffer + for (int i = 0; i < remainingSize/2; i++) + { + *pbuffer = *binArea16 >> 8 | *binArea16 << 8; + pbuffer++; + binArea16++; + } + os.write ( buffer, remainingSize ); + } + return os; +#else + return os.write(reinterpret_cast<const char*>(val), len); +#endif +} + +//------------------------------------------------------------------------- +// Protected + +//------------------------------------------------------------------------- +// Private +/** + * \brief Return the IP adress of the machine writting the DICOM image + */ +std::string Util::GetIPAddress() +{ + // This is a rip from + // http://www.codeguru.com/Cpp/I-N/internet/network/article.php/c3445/ +#ifndef HOST_NAME_MAX + // SUSv2 guarantees that `Host names are limited to 255 bytes'. + // POSIX 1003.1-2001 guarantees that `Host names (not including the + // terminating NUL) are limited to HOST_NAME_MAX bytes'. +#define HOST_NAME_MAX 255 + // In this case we should maybe check the string was not truncated. + // But I don't known how to check that... +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__) + // with WinSock DLL we need to initialize the WinSock before using gethostname + WORD wVersionRequested = MAKEWORD(1,0); + WSADATA WSAData; + int err = WSAStartup(wVersionRequested,&WSAData); + if (err != 0) + { + // Tell the user that we could not find a usable + // WinSock DLL. + WSACleanup(); + return "127.0.0.1"; + } +#endif + +#endif //HOST_NAME_MAX + + std::string str; + char szHostName[HOST_NAME_MAX+1]; + int r = gethostname(szHostName, HOST_NAME_MAX); + + if ( r == 0 ) + { + // Get host adresses + struct hostent *pHost = gethostbyname(szHostName); + + for( int i = 0; pHost!= NULL && pHost->h_addr_list[i]!= NULL; i++ ) + { + for( int j = 0; j<pHost->h_length; j++ ) + { + if ( j > 0 ) str += "."; + + str += Util::Format("%u", + (unsigned int)((unsigned char*)pHost->h_addr_list[i])[j]); + } + // str now contains one local IP address + +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__) + WSACleanup(); +#endif + + } + } + // If an error occur r == -1 + // Most of the time it will return 127.0.0.1... + return str; +} + +//------------------------------------------------------------------------- +} // end namespace gdcm + diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmUtil.h b/Utilities/ITK/Utilities/gdcm/src/gdcmUtil.h new file mode 100644 index 0000000000000000000000000000000000000000..fbf51191f35b59e4abfe3df7df2f8698cd7befe4 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmUtil.h @@ -0,0 +1,98 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmUtil.h,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:39 $ + Version: $Revision: 1.8 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#ifndef GDCMUTIL_H +#define GDCMUTIL_H + +#include "gdcmCommon.h" +#include <vector> +#include <string> + +namespace gdcm +{ +/** + * \brief Here are some utility functions, belonging to the gdcm::Util class, + * dealing with strings, file names... that can be called + * from anywhere by whomsoever they can help. + */ + +//----------------------------------------------------------------------------- + +class GDCM_EXPORT Util +{ +public: + static std::string Format(const char *format, ...); + static void Tokenize (const std::string &str, + std::vector<std::string> &tokens, + const std::string &delimiters = " "); + static int CountSubstring (const std::string &str, + const std::string &subStr); + + static std::string CreateCleanString(std::string const &s); + static std::string CreateCleanString(uint8_t *s, int l); + static bool IsCleanString(std::string const &s); + static bool IsCleanArea(uint8_t *s, int l); + static std::string NormalizePath(std::string const &name); + static std::string GetPath(std::string const &fullName); + static std::string GetName(std::string const &fullName); + static std::string GetCurrentDate(); + static std::string GetCurrentTime(); + static std::string GetCurrentDateTime(); + /// Provides a simple static GetVersion() function + static std::string GetVersion() + { return GDCM_VERSION;} + static unsigned int GetCurrentThreadID(); + static unsigned int GetCurrentProcessID(); + static bool IsCurrentProcessorBigEndian(); + + static std::string DicomString(const char *s, size_t l); + static std::string DicomString(const char *s); + static bool DicomStringEqual(const std::string &s1, const char *s2); + static bool CompareDicomString(const std::string &s1, + const char *s2, int op); + static std::string GetMACAddress(); + + static std::string CreateUniqueUID(const std::string &root = ""); + static void SetRootUID(const std::string &root = ""); + static const std::string &GetRootUID(); + + static const uint8_t *GetFileMetaInformationVersion() + { return FileMetaInformationVersion;} + static void SetFileMetaInformationVersion( uint16_t fmiv ) + { FileMetaInformationVersion = (uint8_t *)&fmiv; } + +private: + static std::string GetIPAddress(); //Do not expose this method + + static std::string RootUID; + static const std::string GDCM_UID; + static uint8_t *FileMetaInformationVersion; + static const uint16_t FMIV; + static std::string GDCM_MAC_ADRESS; +}; + +GDCM_EXPORT std::ostream &binary_write(std::ostream &os, const uint16_t &val); +GDCM_EXPORT std::ostream &binary_write(std::ostream &os, const uint32_t &val); +GDCM_EXPORT std::ostream &binary_write(std::ostream &os, const double &val); +GDCM_EXPORT std::ostream &binary_write(std::ostream &os, const char *val); +GDCM_EXPORT std::ostream &binary_write(std::ostream &os, std::string const &val); +GDCM_EXPORT std::ostream &binary_write(std::ostream &os, const uint8_t *val, size_t len); +GDCM_EXPORT std::ostream &binary_write(std::ostream &os, const uint16_t *val, size_t len); +} // end namespace gdcm +//----------------------------------------------------------------------------- +#endif diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmVR.cxx b/Utilities/ITK/Utilities/gdcm/src/gdcmVR.cxx new file mode 100644 index 0000000000000000000000000000000000000000..038e1f40b8836b0f847c6777e37974510ef8efb5 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmVR.cxx @@ -0,0 +1,166 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmVR.cxx,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:39 $ + Version: $Revision: 1.6 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#include "gdcmVR.h" +#include "gdcmUtil.h" +#include "gdcmDictSet.h" +#include "gdcmDebug.h" + +#include <fstream> +#include <iostream> +#include <string.h> + +namespace gdcm +{ +//----------------------------------------------------------------------------- +/// \brief auto generated function, to fill up the 'Value Representation' +/// Dictionnary, if relevant file is not found on user's disk +void FillDefaultVRDict(VRHT &vr); + +//----------------------------------------------------------------------------- +// Constructor / Destructor +/** + * \brief Constructor + */ +VR::VR() +{ + std::string filename = DictSet::BuildDictPath() + DICT_VR; + std::ifstream from(filename.c_str()); + if ( !from ) + { + gdcmWarningMacro("Can't open dictionary " << filename.c_str()); + FillDefaultVRDict(vr); + } + else + { + char buff[1024]; + VRKey key; + VRAtr name; + + while (!from.eof()) + { + from >> std::ws; + from.getline(buff, 1024, ' '); + if( strcmp(buff,"") == 0) + continue; + + key = buff; + from >> std::ws; + from.getline(buff, 1024, ';'); + name = buff; + + from >> std::ws; + from.getline(buff, 1024, '\n'); + + vr[key] = name; + } + from.close(); + } +} + +/** + * \brief Destructor + */ +VR::~VR() +{ + vr.clear(); +} + +//----------------------------------------------------------------------------- +// Public + +/** + * \brief Simple predicate that checks whether the given argument + * corresponds to the Value Representation of a \ref BinEntry . + * @param tested value representation to check for. + */ +bool VR::IsVROfBinaryRepresentable(VRKey const &tested) +{ + if ( IsVROfStringRepresentable(tested) ) + return false; + + if ( IsVROfSequence(tested) ) + return false; + + return true; +} + +/** + * \brief Simple predicate that checks whether the given argument + * corresponds to the Value Representation of a \ref ValEntry + * but NOT a \ref BinEntry. + * @param tested value representation to be checked. + */ +bool VR::IsVROfStringRepresentable(VRKey const &tested) +{ + + return tested == "AE" || + tested == "AS" || + tested == "CS" || + tested == "DA" || + tested == "DS" || + tested == "FL" || + tested == "FD" || + tested == "IS" || + tested == "LO" || + tested == "LT" || + tested == "PN" || + tested == "SH" || + tested == "SL" || + tested == "SS" || + tested == "ST" || + tested == "TM" || + tested == "UI" || + tested == "UL" || + tested == "US" || + tested == "UT"; + + // Should be quicker + // --> will *never* work : any rotten value would be considered as OK ! +/* + return tested != "OB" && + tested != "OW" && + tested != "OF" && + tested != "AT" && // Attribute Tag ?!? contain no printable character + tested != "UN" && // UN is an actual VR ! + tested != "SQ" ; +*/ +} + +//----------------------------------------------------------------------------- +// Protected + +//----------------------------------------------------------------------------- +// Private + +//----------------------------------------------------------------------------- +// Print +/** + * \brief Print all + * @param os The output stream to be written to. + */ +void VR::Print(std::ostream &os,std::string const &) +{ + for (VRHT::iterator it = vr.begin(); it != vr.end(); ++it) + { + os << "VR : " << it->first << " = " << it->second << std::endl; + } +} + +//----------------------------------------------------------------------------- +} // end namespace gdcm diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmVR.h b/Utilities/ITK/Utilities/gdcm/src/gdcmVR.h new file mode 100644 index 0000000000000000000000000000000000000000..c4a68fef7b3aa676e42b199c7a1ca7e6ad382632 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmVR.h @@ -0,0 +1,68 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmVR.h,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:39 $ + Version: $Revision: 1.4 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#ifndef GDCMVR_H +#define GDCMVR_H + +#include "gdcmCommon.h" +#include <map> +#include <string> +#include <iostream> + +namespace gdcm +{ + +//----------------------------------------------------------------------------- +typedef std::string VRKey; +typedef std::string VRAtr; +/// Value Representation Hash Table +typedef std::map<VRKey, VRAtr> VRHT; + +//----------------------------------------------------------------------------- +/** + * \brief Container for dicom Value Representation Hash Table + * \note This is a singleton + */ +class GDCM_EXPORT VR +{ +public: + VR(); + ~VR(); + + void Print(std::ostream &os = std::cout, + std::string const &s = ""); + + /// \brief Get the count for an element + int Count(VRKey const &key) { return vr.count(key); }; + + bool IsVROfBinaryRepresentable(VRKey const &tested); + bool IsVROfStringRepresentable(VRKey const &tested); + + /// \brief Simple predicate that checks whether the given argument + /// corresponds to the Value Representation of a \ref SeqEntry + bool IsVROfSequence(VRKey const &tested) { return tested == "SQ"; } + + bool IsValidVR(VRKey const &key) { return vr.find(key) != vr.end(); } + +private: + VRHT vr; +}; +} // end namespace gdcm + +//----------------------------------------------------------------------------- +#endif diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmValEntry.cxx b/Utilities/ITK/Utilities/gdcm/src/gdcmValEntry.cxx new file mode 100644 index 0000000000000000000000000000000000000000..221f5b34ecb52025a5fe8d5018c88ac821ec1bb3 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmValEntry.cxx @@ -0,0 +1,315 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmValEntry.cxx,v $ + Language: C++ + Date: $Date: 2006/02/20 15:56:58 $ + Version: $Revision: 1.8 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#include "gdcmValEntry.h" +#include "gdcmVR.h" +#include "gdcmTS.h" +#include "gdcmGlobal.h" +#include "gdcmUtil.h" +#include "gdcmDebug.h" +#include "gdcmDocument.h" + +#include <fstream> +#include <ctype.h> // for isdigit +#include <stdlib.h> // for atoi + +namespace gdcm +{ +//----------------------------------------------------------------------------- +#define MAX_SIZE_PRINT_ELEMENT_VALUE 0x7fffffff +uint32_t ValEntry::MaxSizePrintEntry = MAX_SIZE_PRINT_ELEMENT_VALUE; +//----------------------------------------------------------------------------- +// Constructor / Destructor +/** + * \brief Constructor from a given DictEntry + * @param e Pointer to existing dictionary entry + */ +ValEntry::ValEntry(DictEntry *e) + : ContentEntry(e) +{ +} + +/** + * \brief Constructor from a given DocEntry + * @param e Pointer to existing Doc entry + */ +ValEntry::ValEntry(DocEntry *e) + : ContentEntry(e->GetDictEntry()) +{ + Copy(e); +} + +/** + * \brief Canonical destructor. + */ +ValEntry::~ValEntry () +{ +} + +//----------------------------------------------------------------------------- +// Public +/** + * \brief Writes the std::string representable' value of a ValEntry + * @param fp already open ofstream pointer + * @param filetype type of the file (ACR, ImplicitVR, ExplicitVR, ...) + */ +void ValEntry::WriteContent(std::ofstream *fp, FileType filetype) +{ + DocEntry::WriteContent(fp, filetype); + + if ( GetGroup() == 0xfffe ) + { + return; //delimitors have NO value + } + + const VRKey &vr = GetVR(); + unsigned int lgth = GetLength(); + if (vr == "US" || vr == "SS") + { + // some 'Short integer' fields may be multivaluated + // each single value is separated from the next one by '\' + // we split the string and write each value as a short int + std::vector<std::string> tokens; + tokens.erase(tokens.begin(),tokens.end()); // clean any previous value + Util::Tokenize (GetValue(), tokens, "\\"); + for (unsigned int i=0; i<tokens.size();i++) + { + uint16_t val_uint16 = atoi(tokens[i].c_str()); + binary_write( *fp, val_uint16); + } + tokens.clear(); + return; + } + if (vr == "UL" || vr == "SL") + { + // Some 'Integer' fields may be multivaluated (multiple instances + // of integer). But each single integer value is separated from the + // next one by '\' (backslash character). Hence we split the string + // along the '\' and write each value as an int: + std::vector<std::string> tokens; + tokens.erase(tokens.begin(),tokens.end()); // clean any previous value + Util::Tokenize (GetValue(), tokens, "\\"); + for (unsigned int i=0; i<tokens.size();i++) + { + uint32_t val_uint32 = atoi(tokens[i].c_str()); + binary_write( *fp, val_uint32); + } + tokens.clear(); + return; + } + + gdcmAssertMacro( lgth == GetValue().length() ); + binary_write(*fp, GetValue()); +} + + +/** + * \brief Header Elements too long will not be printed + * @param newSize new size + */ +void ValEntry::SetMaxSizePrintEntry(long newSize) +{ + if ( newSize < 0 ) + { + return; + } + if ((uint32_t)newSize >= (uint32_t)0xffffffff ) + { + ValEntry::MaxSizePrintEntry = 0xffffffff; + return; + } + ValEntry::MaxSizePrintEntry = newSize; +} + + +/** + * \brief Sets the std::string representable' value of a ValEntry + * @param val value to set + */ +void ValEntry::SetValue(std::string const &val) +{ + // Integers have a special treatement for their length: + int l = val.length(); + if ( l != 0) // To avoid to be cheated by 'zero length' integers + { + const VRKey &vr = GetVR(); + if ( vr == "US" || vr == "SS" ) + { + // for multivaluated items + l = (Util::CountSubstring(val, "\\") + 1) * 2; + ContentEntry::SetValue(val); + } + else if ( vr == "UL" || vr == "SL" ) + { + // for multivaluated items + l = (Util::CountSubstring(val, "\\") + 1) * 4;; + ContentEntry::SetValue(val); + } + else + { + std::string finalVal = Util::DicomString( val.c_str() ); + gdcmAssertMacro( !(finalVal.size() % 2) ); + + l = finalVal.length(); + ContentEntry::SetValue(finalVal); + } + } + else + { + std::string finalVal = Util::DicomString( val.c_str() ); + gdcmAssertMacro( !(finalVal.size() % 2) ); + + l = finalVal.length(); + ContentEntry::SetValue(finalVal); + } + + SetLength(l); +} + +/** + * \brief Compute the full length of the elementary DataEntry (not only value + * length) depending on the VR. + */ +uint32_t ValEntry::ComputeFullLength() +{ + return GetFullLength(); +} + +//----------------------------------------------------------------------------- +// Protected + +//----------------------------------------------------------------------------- +// Private + +//----------------------------------------------------------------------------- +// Print +/** + * \brief Prints the 'std::string representable' value of ValEntry + * @param os ostream we want to print in + * @param indent Indentation string to be prepended during printing + */ +void ValEntry::Print(std::ostream &os, std::string const &) +{ + uint16_t g = GetGroup(); + uint16_t e = GetElement(); + VRKey vr = GetVR(); + itksys_ios::ostringstream s; + std::string st; + std::string d2; + + os << "V "; + DocEntry::Print(os); + + if (g == 0xfffe) // delimiters have NO value + { + // just to avoid identing all the remaining code + return; + } + + TS *ts = Global::GetTS(); + + TSAtr v = GetValue(); + d2 = Util::CreateCleanString(v); // replace non printable characters by '.' + if ( (long)GetLength() <= ValEntry::GetMaxSizePrintEntry() + || PrintLevel >= 3 + || d2.find(GDCM_NOTLOADED) < d2.length() ) + { + s << " [" << d2 << "]"; + } + else + { + s << " [gdcm::too long for print (" << GetLength() << ") ]"; + } + + // Display the UID value (instead of displaying only the rough code) + // First 'clean' trailing character (space or zero) + if (g == 0x0002) + { + // Any more to be displayed ? + if ( e == 0x0010 || e == 0x0002 ) + { + if ( v.length() != 0 ) // for brain damaged headers + { + if ( ! isdigit((unsigned char)v[v.length()-1]) ) + { + v.erase(v.length()-1, 1); + } + } + s << " ==>\t[" << ts->GetValue(v) << "]"; + } + } + else + { + if (g == 0x0008) + { + if ( e == 0x0016 || e == 0x1150 ) + { + if ( v.length() != 0 ) // for brain damaged headers + { + if ( ! isdigit((unsigned char)v[v.length()-1]) ) + { + v.erase(v.length()-1, 1); + } + } + s << " ==>\t[" << ts->GetValue(v) << "]"; + } + } + else + { + if (g == 0x0004) + { + if ( e == 0x1510 || e == 0x1512 ) + { + if ( v.length() != 0 ) // for brain damaged headers + { + if ( ! isdigit((unsigned char)v[v.length()-1]) ) + { + v.erase(v.length()-1, 1); + } + } + s << " ==>\t[" << ts->GetValue(v) << "]"; + } + } + } + } + //if (e == 0x0000) { // elem 0x0000 --> group length + if ( vr == "UL" || vr == "US" || vr == "SL" || vr == "SS" ) + { + if (v == "4294967295") // to avoid troubles in convertion + { + st = "ffffffff"; + } + else + { + if ( GetLength() != 0 ) + { + st = Util::Format(" x(%x)", atoi(v.c_str()));//FIXME + } + else + { + st = " "; + } + } + s << st; + } + os << s.str(); +} + +//----------------------------------------------------------------------------- +} // end namespace gdcm + diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmValEntry.h b/Utilities/ITK/Utilities/gdcm/src/gdcmValEntry.h new file mode 100644 index 0000000000000000000000000000000000000000..7a12629bb941a020fe6f6ced2cbd5cba3b06ef32 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmValEntry.h @@ -0,0 +1,83 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmValEntry.h,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:39 $ + Version: $Revision: 1.4 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#ifndef GDCMVALENTRY_H +#define GDCMVALENTRY_H + +#include "gdcmDocEntry.h" +#include "gdcmContentEntry.h" + +#include <iostream> + +namespace gdcm +{ +//----------------------------------------------------------------------------- +/** + * \brief Any Dicom Document (File or DicomDir) contains + * a set of DocEntry - Dicom entries - + * ValEntry is an elementary DocEntry (i.e. a ContentEntry, + * as opposed to SeqEntry) + * whose content is 'std::string representable' : characters, + * or integers (loaded in memory as a std::string) + * ValEntry is a specialisation of ContentEntry + */ +class GDCM_EXPORT ValEntry : public ContentEntry +{ +public: + + // Contructors and Destructor are public. + ValEntry(DictEntry *e); + ValEntry(DocEntry *d); + + ~ValEntry(); + + // Other accessors are inherited from gdcm::ContentEntry + + void Print(std::ostream &os = std::cout, std::string const &indent = ""); + + void WriteContent(std::ofstream *fp, FileType filetype); + + /// Sets the value (string) of the current Dicom entry. + /// The size is updated + void SetValue(std::string const &val); + + uint32_t ComputeFullLength(); + + + /// \brief returns the size threshold above which an element value + /// will NOT be *printed* in order no to polute the screen output + static long GetMaxSizePrintEntry() { return ValEntry::MaxSizePrintEntry; } + + static void SetMaxSizePrintEntry(long); + +protected: + +private: + + /// \brief Size threshold above which an element val + /// By default, this upper bound is fixed to 64 bytes. + + static uint32_t MaxSizePrintEntry; + +}; + +} // end namespace gdcm + +//----------------------------------------------------------------------------- +#endif + diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmValidator.cxx b/Utilities/ITK/Utilities/gdcm/src/gdcmValidator.cxx new file mode 100644 index 0000000000000000000000000000000000000000..566bb795c1fe28a6fff42fe0697841edf25e0464 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmValidator.cxx @@ -0,0 +1,87 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmValidator.cxx,v $ + Language: C++ + Date: $Date: 2006/02/20 15:56:58 $ + Version: $Revision: 1.5 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#include "gdcmValidator.h" +#include "gdcmElementSet.h" +#include "gdcmBinEntry.h" +#include "gdcmValEntry.h" +#include "gdcmDebug.h" // hidden way to include sstream + +namespace gdcm +{ + +Validator::Validator() +{ +} + +Validator::~Validator() +{ +} + +// Function to compare the VM found while parsing d->GetValue() +// compare to the one from the dictionary +bool CheckVM(ValEntry *v) +{ + const std::string &s = v->GetValue(); + std::string::size_type n = s.find("\\"); + if ( n == s.npos ) // none found + { + n = 0; + } + n++; // number of '\' + 1 == Value Multiplicity + + unsigned int m; + itksys_ios::istringstream is; + is.str( v->GetVM()); + is >> m; + + return n == m; +} + +void Validator::SetInput(ElementSet *input) +{ + // berk for now SetInput do two things at the same time + gdcm::DocEntry *d=input->GetFirstEntry(); + while(d) + { + if ( gdcm::BinEntry *b = dynamic_cast<gdcm::BinEntry*>(d) ) + { +// copyH->InsertBinEntry( b->GetBinArea(),b->GetLength(), +// b->GetGroup(),b->GetElement(), +// b->GetVR() ); + (void)b; + } + else if ( gdcm::ValEntry *v = dynamic_cast<gdcm::ValEntry*>(d) ) + { + if ( !CheckVM(v) ) + { + std::cout << "This DICOM contains one wrong tag:" << + v->GetValue() << " " << + v->GetGroup() << "," << v->GetElement() << "," << + v->GetVR() << " " << v->GetVM() << " " << v->GetName() << std::endl; + } + } + else + { + // We skip pb of SQ recursive exploration + } + d=input->GetNextEntry(); + } +} + +} // end namespace gdcm diff --git a/Utilities/ITK/Utilities/gdcm/src/gdcmValidator.h b/Utilities/ITK/Utilities/gdcm/src/gdcmValidator.h new file mode 100644 index 0000000000000000000000000000000000000000..98ee89db6c6f1246465a5d9bdc3ec2329d9d6488 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/gdcmValidator.h @@ -0,0 +1,43 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: gdcmValidator.h,v $ + Language: C++ + Date: $Date: 2006/02/18 12:36:39 $ + Version: $Revision: 1.2 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 notices for more information. + +=========================================================================*/ + +#ifndef GDCMVALIDATOR_H +#define GDCMVALIDATOR_H + +#include "gdcmBase.h" + +namespace gdcm +{ +/** + * \brief Class to perform some verifications on a gdcm::Document + */ +class ElementSet; +class GDCM_EXPORT Validator : public Base +{ +public: + Validator(); + ~Validator(); + + void SetInput(ElementSet *input); + +}; + +} // end namespace gdcm + +//----------------------------------------------------------------------------- +#endif diff --git a/Utilities/ITK/Utilities/gdcm/src/jdatadst.cxx b/Utilities/ITK/Utilities/gdcm/src/jdatadst.cxx new file mode 100644 index 0000000000000000000000000000000000000000..63ae9a171e1faa1db558adbff33bf519a0964e13 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/jdatadst.cxx @@ -0,0 +1,194 @@ +/* + * jdatadst.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains compression data destination routines for the case of + * emitting JPEG data to a file (or any stdio stream). While these routines + * are sufficient for most applications, some will want to use a different + * destination manager. + * IMPORTANT: we assume that fwrite() will correctly transcribe an array of + * JOCTETs into 8-bit-wide elements on external storage. If char is wider + * than 8 bits on your machine, you may need to do some tweaking. + */ + +/* this is not a core library module, so it doesn't define JPEG_INTERNALS */ + + +/* Expanded data destination object for stdio output */ + +extern "C" { + typedef boolean(*boolean_jpeg_compress_struct)(jpeg_compress_struct*); + typedef void(*void_jpeg_compress_struct)(jpeg_compress_struct*); +} + +typedef struct { + struct jpeg_destination_mgr pub; /* public fields */ + + std::ostream * outfile; /* target stream */ + JOCTET * buffer; /* start of buffer */ +// boolean start_of_file; /* have we gotten any data yet? */ + + size_t frag_length; //we have to control this one to spec the size of the frag + size_t bytes_written; +} my_destination_mgr; + +typedef my_destination_mgr * my_dest_ptr; + +#define OUTPUT_BUF_SIZE 4096 /* choose an efficiently fwrite'able size */ + + +/* + * Initialize destination --- called by jpeg_start_compress + * before any data is actually written. + */ + +METHODDEF(void) +init_destination (j_compress_ptr cinfo) +{ + my_dest_ptr dest = (my_dest_ptr) cinfo->dest; + + /* Allocate the output buffer --- it will be released when done with image */ + dest->buffer = (JOCTET *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + OUTPUT_BUF_SIZE * SIZEOF(JOCTET)); + + dest->pub.next_output_byte = dest->buffer; + dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; +} + + +/* + * Empty the output buffer --- called whenever buffer fills up. + * + * In typical applications, this should write the entire output buffer + * (ignoring the current state of next_output_byte & free_in_buffer), + * reset the pointer & count to the start of the buffer, and return TRUE + * indicating that the buffer has been dumped. + * + * In applications that need to be able to suspend compression due to output + * overrun, a FALSE return indicates that the buffer cannot be emptied now. + * In this situation, the compressor will return to its caller (possibly with + * an indication that it has not accepted all the supplied scanlines). The + * application should resume compression after it has made more room in the + * output buffer. Note that there are substantial restrictions on the use of + * suspension --- see the documentation. + * + * When suspending, the compressor will back up to a convenient restart point + * (typically the start of the current MCU). next_output_byte & free_in_buffer + * indicate where the restart point will be if the current call returns FALSE. + * Data beyond this point will be regenerated after resumption, so do not + * write it out when emptying the buffer externally. + */ + +METHODDEF(boolean) +empty_output_buffer (j_compress_ptr cinfo) +{ + my_dest_ptr dest = (my_dest_ptr) cinfo->dest; + + if( dest->bytes_written == dest->frag_length ) + { + // Start the I/O suspension simply by returning false here: + return FALSE; + } + + size_t output_buf_size = OUTPUT_BUF_SIZE; + if( (dest->bytes_written + OUTPUT_BUF_SIZE) > dest->frag_length ) + { + output_buf_size = dest->frag_length - dest->bytes_written; + } + dest->outfile->write((char*)dest->buffer, output_buf_size); + size_t nbytes = output_buf_size; //dest->outfile->gcount(); + + if( nbytes <= 0 ) + ERREXIT(cinfo, JERR_FILE_WRITE); + + if( dest->outfile->fail() ) + ERREXIT(cinfo, JERR_FILE_WRITE); + + dest->pub.next_output_byte = dest->buffer; + dest->pub.free_in_buffer = nbytes; //OUTPUT_BUF_SIZE; + dest->bytes_written += nbytes; + + return TRUE; +} + + +/* + * Terminate destination --- called by jpeg_finish_compress + * after all data has been written. Usually needs to flush buffer. + * + * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding + * application must deal with any cleanup that should happen even + * for error exit. + */ + +METHODDEF(void) +term_destination (j_compress_ptr cinfo) +{ + my_dest_ptr dest = (my_dest_ptr) cinfo->dest; + size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer; + + /* Write any data remaining in the buffer */ +#if 0 + if (datacount > 0) { + if (JFWRITE(dest->outfile, dest->buffer, datacount) != datacount) + ERREXIT(cinfo, JERR_FILE_WRITE); + } + fflush(dest->outfile); + /* Make sure we wrote the output file OK */ + if (ferror(dest->outfile)) + ERREXIT(cinfo, JERR_FILE_WRITE); +#else + if (datacount > 0) { + dest->outfile->write((char*)dest->buffer, datacount); + if (dest->outfile->fail()) + ERREXIT(cinfo, JERR_FILE_WRITE); + dest->outfile->flush(); + /* Make sure we wrote the output file OK */ + if (dest->outfile->fail()) + ERREXIT(cinfo, JERR_FILE_WRITE); + } +#endif +} + + +/* + * Prepare for output to a stdio stream. + * The caller must have already opened the stream, and is responsible + * for closing it after finishing compression. + */ + +GLOBAL(void) +jpeg_stdio_dest (j_compress_ptr cinfo, std::ostream * outfile, size_t frag_length, int flag) +{ + my_dest_ptr dest; + + /* The destination object is made permanent so that multiple JPEG images + * can be written to the same file without re-executing jpeg_stdio_dest. + * This makes it dangerous to use this manager and a different destination + * manager serially with the same JPEG object, because their private object + * sizes may be different. Caveat programmer. + */ + if (cinfo->dest == NULL) { /* first time for this JPEG object? */ + cinfo->dest = (struct jpeg_destination_mgr *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + SIZEOF(my_destination_mgr)); + } + + dest = (my_dest_ptr) cinfo->dest; + dest->pub.init_destination = reinterpret_cast<void_jpeg_compress_struct>(init_destination); + dest->pub.empty_output_buffer = reinterpret_cast<boolean_jpeg_compress_struct>(empty_output_buffer); + dest->pub.term_destination = reinterpret_cast<void_jpeg_compress_struct>(term_destination); + dest->outfile = outfile; + + // Need to setup a new buffer, clean bytes_in_buffer and next_input_byte + if( flag ) + { + dest->bytes_written = 0; + } + // only upate the new fragment, valid for both 'flag' value + dest->frag_length = frag_length; +} diff --git a/Utilities/ITK/Utilities/gdcm/src/jdatasrc.cxx b/Utilities/ITK/Utilities/gdcm/src/jdatasrc.cxx new file mode 100644 index 0000000000000000000000000000000000000000..bf658ef10b2fc0bab7c07f7ee547ace1450ae594 --- /dev/null +++ b/Utilities/ITK/Utilities/gdcm/src/jdatasrc.cxx @@ -0,0 +1,239 @@ +/* + * jdatasrc.cxx + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains decompression data source routines for the case of + * reading JPEG data from a file (or any stdio stream). While these routines + * are sufficient for most applications, some will want to use a different + * source manager. + * IMPORTANT: we assume that fread() will correctly transcribe an array of + * JOCTETs from 8-bit-wide elements on external storage. If char is wider + * than 8 bits on your machine, you may need to do some tweaking. + */ + +/* this is not a core library module, so it doesn't define JPEG_INTERNALS */ + +/* Expanded data source object for stdio input */ + +extern "C" { + typedef boolean(*boolean_jpeg_decompress_struct)(jpeg_decompress_struct*); + typedef void(*void_jpeg_decompress_struct)(jpeg_decompress_struct*); + typedef void(*void_jpeg_decompress_struct_long)(jpeg_decompress_struct*,long); +} + +typedef struct { + struct jpeg_source_mgr pub; /* public fields */ + + std::istream *infile; /* source stream */ + JOCTET * buffer; /* start of buffer */ + boolean start_of_file; /* have we gotten any data yet? */ + + gdcm::JPEGFragment *frag; + size_t bytes_read; +} my_source_mgr; + +typedef my_source_mgr * my_src_ptr; + +#define INPUT_BUF_SIZE 4096 /* choose an efficiently fread'able size */ + + +/* + * Initialize source --- called by jpeg_read_header + * before any data is actually read. + */ + +METHODDEF(void) +init_source (j_decompress_ptr cinfo) +{ + my_src_ptr src = (my_src_ptr) cinfo->src; + + /* We reset the empty-input-file flag for each image, + * but we don't clear the input buffer. + * This is correct behavior for reading a series of images from one source. + */ + src->start_of_file = TRUE; +} + + +/* + * Fill the input buffer --- called whenever buffer is emptied. + * + * In typical applications, this should read fresh data into the buffer + * (ignoring the current state of next_input_byte & bytes_in_buffer), + * reset the pointer & count to the start of the buffer, and return TRUE + * indicating that the buffer has been reloaded. It is not necessary to + * fill the buffer entirely, only to obtain at least one more byte. + * + * There is no such thing as an EOF return. If the end of the file has been + * reached, the routine has a choice of ERREXIT() or inserting fake data into + * the buffer. In most cases, generating a warning message and inserting a + * fake EOI marker is the best course of action --- this will allow the + * decompressor to output however much of the image is there. However, + * the resulting error message is misleading if the real problem is an empty + * input file, so we handle that case specially. + * + * In applications that need to be able to suspend compression due to input + * not being available yet, a FALSE return indicates that no more data can be + * obtained right now, but more may be forthcoming later. In this situation, + * the decompressor will return to its caller (with an indication of the + * number of scanlines it has read, if any). The application should resume + * decompression after it has loaded more data into the input buffer. Note + * that there are substantial restrictions on the use of suspension --- see + * the documentation. + * + * When suspending, the decompressor will back up to a convenient restart point + * (typically the start of the current MCU). next_input_byte & bytes_in_buffer + * indicate where the restart point will be if the current call returns FALSE. + * Data beyond this point must be rescanned after resumption, so move it to + * the front of the buffer rather than discarding it. + */ + +METHODDEF(boolean) +fill_input_buffer (j_decompress_ptr cinfo) +{ + my_src_ptr src = (my_src_ptr) cinfo->src; + + if( src->bytes_read == src->frag->GetLength() ) + { + // Start the I/O suspension simply by returning false here: + return FALSE; + } + + size_t input_buf_size = INPUT_BUF_SIZE; + if( (src->bytes_read + INPUT_BUF_SIZE) > src->frag->GetLength() ) + { + input_buf_size = src->frag->GetLength() - src->bytes_read; + } + + src->infile->read( (char*)src->buffer, input_buf_size); + size_t nbytes = src->infile->gcount(); + + if (nbytes <= 0) { + if (src->start_of_file) /* Treat empty input file as fatal error */ + ERREXIT(cinfo, JERR_INPUT_EMPTY); + WARNMS(cinfo, JWRN_JPEG_EOF); + /* Insert a fake EOI marker */ + src->buffer[0] = (JOCTET) 0xFF; + src->buffer[1] = (JOCTET) JPEG_EOI; + nbytes = 2; + } + + src->pub.next_input_byte = src->buffer; + src->pub.bytes_in_buffer = nbytes; + src->start_of_file = FALSE; + src->bytes_read += nbytes; + + return TRUE; +} + + +/* + * Skip data --- used to skip over a potentially large amount of + * uninteresting data (such as an APPn marker). + * + * Writers of suspendable-input applications must note that skip_input_data + * is not granted the right to give a suspension return. If the skip extends + * beyond the data currently in the buffer, the buffer can be marked empty so + * that the next read will cause a fill_input_buffer call that can suspend. + * Arranging for additional bytes to be discarded before reloading the input + * buffer is the application writer's problem. + */ + +METHODDEF(void) +skip_input_data (j_decompress_ptr cinfo, long num_bytes) +{ + my_src_ptr src = (my_src_ptr) cinfo->src; + + /* Just a dumb implementation for now. Could use fseek() except + * it doesn't work on pipes. Not clear that being smart is worth + * any trouble anyway --- large skips are infrequent. + */ + if (num_bytes > 0) { + while (num_bytes > (long) src->pub.bytes_in_buffer) { + num_bytes -= (long) src->pub.bytes_in_buffer; + (void) fill_input_buffer(cinfo); + /* note we assume that fill_input_buffer will never return FALSE, + * so suspension need not be handled. + */ + } + src->pub.next_input_byte += (size_t) num_bytes; + src->pub.bytes_in_buffer -= (size_t) num_bytes; + } +} + + +/* + * An additional method that can be provided by data source modules is the + * resync_to_restart method for error recovery in the presence of RST markers. + * For the moment, this source module just uses the default resync method + * provided by the JPEG library. That method assumes that no backtracking + * is possible. + */ + + +/* + * Terminate source --- called by jpeg_finish_decompress + * after all data has been read. Often a no-op. + * + * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding + * application must deal with any cleanup that should happen even + * for error exit. + */ + +METHODDEF(void) +term_source (j_decompress_ptr cinfo) +{ + cinfo=cinfo; + /* no work necessary here */ +} + + +/* + * Prepare for input from a stdio stream. + * The caller must have already opened the stream, and is responsible + * for closing it after finishing decompression. + */ + +GLOBAL(void) +jpeg_stdio_src (j_decompress_ptr cinfo, std::istream * infile, gdcm::JPEGFragment *frag, int flag) +{ + my_src_ptr src; + + /* The source object and input buffer are made permanent so that a series + * of JPEG images can be read from the same file by calling jpeg_stdio_src + * only before the first one. (If we discarded the buffer at the end of + * one image, we'd likely lose the start of the next one.) + * This makes it unsafe to use this manager and a different source + * manager serially with the same JPEG object. Caveat programmer. + */ + if (cinfo->src == NULL) { /* first time for this JPEG object? */ + cinfo->src = (struct jpeg_source_mgr *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + SIZEOF(my_source_mgr)); + src = (my_src_ptr) cinfo->src; + src->buffer = (JOCTET *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + INPUT_BUF_SIZE * SIZEOF(JOCTET)); + } + + src = (my_src_ptr) cinfo->src; + src->pub.init_source = reinterpret_cast<void_jpeg_decompress_struct>(init_source); + src->pub.fill_input_buffer = reinterpret_cast<boolean_jpeg_decompress_struct>(fill_input_buffer); + src->pub.skip_input_data = reinterpret_cast<void_jpeg_decompress_struct_long>(skip_input_data); + src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */ + src->pub.term_source = reinterpret_cast<void_jpeg_decompress_struct>(term_source); + src->infile = infile; + + // Need to setup a new buffer, clean bytes_in_buffer and next_input_byte + if( flag ) + { + src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */ + src->pub.next_input_byte = NULL; /* until buffer loaded */ + } + //only upate the new fragment, valid for both 'flag' value + src->frag = frag; + src->bytes_read = 0; +} diff --git a/Utilities/ITK/Utilities/itkjpeg/.NoDartCoverage b/Utilities/ITK/Utilities/itkjpeg/.NoDartCoverage new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Utilities/ITK/Utilities/itkjpeg/12/CMakeLists.txt b/Utilities/ITK/Utilities/itkjpeg/12/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..fdbaedeef7f441050e02ac70057b126bf7e7e18c --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/12/CMakeLists.txt @@ -0,0 +1,9 @@ +# JPEG 12 bits project + +INCLUDE_DIRECTORIES(BEFORE + "${CMAKE_CURRENT_BINARY_DIR}" + "${ITKJPEG_SOURCE_DIR}") +ADD_LIBRARY(itkjpeg12 ${JPEG_SOURCES}) +INSTALL_TARGETS(/lib/InsightToolkit itkjpeg12) + + diff --git a/Utilities/ITK/Utilities/itkjpeg/16/CMakeLists.txt b/Utilities/ITK/Utilities/itkjpeg/16/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..8e98dfb82c3dce165cd0cf508bb5d7398cc1abfa --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/16/CMakeLists.txt @@ -0,0 +1,9 @@ +# JPEG 16 bits project + +INCLUDE_DIRECTORIES(BEFORE + "${CMAKE_CURRENT_BINARY_DIR}" + "${ITKJPEG_SOURCE_DIR}") +ADD_LIBRARY(itkjpeg16 ${JPEG_SOURCES}) +INSTALL_TARGETS(/lib/InsightToolkit itkjpeg16) + + diff --git a/Utilities/ITK/Utilities/itkjpeg/8/CMakeLists.txt b/Utilities/ITK/Utilities/itkjpeg/8/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..5deb268ed0939852e1c058e39f8abc4460dd5413 --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/8/CMakeLists.txt @@ -0,0 +1,8 @@ +# JPEG 8 bits project + +INCLUDE_DIRECTORIES(BEFORE + "${CMAKE_CURRENT_BINARY_DIR}" + "${ITKJPEG_SOURCE_DIR}") +ADD_LIBRARY(itkjpeg8 ${JPEG_SOURCES}) +INSTALL_TARGETS(/lib/InsightToolkit itkjpeg8) + diff --git a/Utilities/ITK/Utilities/itkjpeg/CMakeLists.txt b/Utilities/ITK/Utilities/itkjpeg/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..47b1bf4b57b33d3d48d55c3aa060db8262b26b00 --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/CMakeLists.txt @@ -0,0 +1,126 @@ +PROJECT(ITKJPEG) + +INCLUDE_REGULAR_EXPRESSION("^(jchuff|jconfig|jdct|jdhuff|jerror|jinclude|jmemsys|jmorecfg|jpegint|jpeglib|jversion|jpeg).*$") + +#MESSAGE(FATAL_ERROR ${ITKJPEG_SOURCE_DIR}) +#INCLUDE_DIRECTORIES(${ITKJPEG_SOURCE_DIR}) +#INCLUDE_DIRECTORIES(${ITKJPEG_BINARY_DIR}) + + +# memmgr back ends: compile only one of these into a working library +# (For now, let's use the mode that requires the image fit into memory. +# This is the recommended mode for Win32 anyway.) +SET(systemdependent_SRCS jmemnobs.c) + +# library object files common to compression and decompression +SET(common_SRCS +jcomapi.c jutils.c jerror.c jmemmgr.c +) + +# compression library object files +SET(compression_SRCS +jcapimin.c jcapistd.c jctrans.c jcparam.c jcinit.c +jcmaster.c jcmarker.c jcmainct.c jcprepct.c jccoefct.c jccolor.c +jcsample.c jchuff.c jcphuff.c jcdctmgr.c jfdctfst.c jfdctflt.c +jdatadst.c +) + +# Lossy (DCT) codec: +SET(comp_lossy_SRCS +jfdctint.c +jclossy.c + +# lossless +jclossls.c + +jdarith.c +jcodec.c +jcscale.c +jcshuff.c +jclhuff.c +jcpred.c +jcdiffct.c +) + +# decompression library object files +SET(decompression_SRCS +jdapimin.c jdapistd.c jdtrans.c jdmaster.c +jdinput.c jdmarker.c jdhuff.c jdphuff.c jdmainct.c jdcoefct.c +jdpostct.c jddctmgr.c jidctfst.c jidctflt.c jidctint.c jidctred.c +jdsample.c jdcolor.c jquant1.c jquant2.c jdmerge.c +jdatasrc.c +) + +SET(decomp_lossy_SRCS + jdlossls.c jdlossy.c +jcarith.c +jdlhuff.c +jddiffct.c +jdpred.c +jdscale.c +jdshuff.c +) + +SET(JPEG_HEADER_FILES + jchuff.h + jdct.h + jdhuff.h + jerror.h + jinclude.h + jmemsys.h +# jmorecfg.h #this one need to be configured + jpegint.h + jpeglib.h + jversion.h + jlossy.h + jlossls.h + ) + +SET(JPEG_SOURCES) +FOREACH(src + ${systemdependent_SRCS} + ${common_SRCS} + ${compression_SRCS} + ${decompression_SRCS} + ${comp_lossy_SRCS} + ${decomp_lossy_SRCS} + ) + SET(JPEG_SOURCES ${JPEG_SOURCES} + "${ITKJPEG_SOURCE_DIR}/${src}") +ENDFOREACH(src) + +IF (WIN32) + IF (BUILD_SHARED_LIBS) + ADD_DEFINITIONS(-DJPEGDLL) + ELSE (BUILD_SHARED_LIBS) + SET(JPEGSTATIC 1) + ENDIF (BUILD_SHARED_LIBS) +ENDIF (WIN32) + +CONFIGURE_FILE(${ITKJPEG_SOURCE_DIR}/.NoDartCoverage + ${ITKJPEG_BINARY_DIR}/.NoDartCoverage) +CONFIGURE_FILE(${ITKJPEG_SOURCE_DIR}/jpegDllConfig.h.in + ${ITKJPEG_BINARY_DIR}/jpegDllConfig.h) + +# Generate three libraries: jpeg 8bits, 12bits and 16bits +# using only one source directory + +# Particular case jmorecfg.h needs to be specified either 8, 12 or 16 bits: +FOREACH(bits 8 12 16) + SET(CMAKE_BITS_IN_JSAMPLE ${bits}) + CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/jmorecfg.h.in + ${CMAKE_CURRENT_BINARY_DIR}/${bits}/jmorecfg.h @ONLY IMMEDIATE) + SET(BITS_TYPE_JPEG_MANGLE_NAME "itkjpeg/mangle_jpeg${bits}bits.h") + CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/jconfig.h.in + ${CMAKE_CURRENT_BINARY_DIR}/${bits}/jconfig.h @ONLY IMMEDIATE) + # Dummy copy for ITK to include <jpeg/8/jpeglib.h> with no conflict + CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/jpeglib.h + ${CMAKE_CURRENT_BINARY_DIR}/${bits}/jpeglib.h COPYONLY IMMEDIATE) + CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/jerror.h + ${CMAKE_CURRENT_BINARY_DIR}/${bits}/jerror.h COPYONLY IMMEDIATE) + CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/jinclude.h + ${CMAKE_CURRENT_BINARY_DIR}/${bits}/jinclude.h COPYONLY IMMEDIATE) +ENDFOREACH(bits) + +SUBDIRS(8 12 16) + diff --git a/Utilities/ITK/Utilities/itkjpeg/COPYRIGHT.dcmtk b/Utilities/ITK/Utilities/itkjpeg/COPYRIGHT.dcmtk new file mode 100644 index 0000000000000000000000000000000000000000..4c0359f241711aac462ffcf10aa651f9b72bddfa --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/COPYRIGHT.dcmtk @@ -0,0 +1,258 @@ + +COPYRIGHT + +Unless otherwise specified, the DCMTK software package has the +following copyright: + +/* + * Copyright (C) 1994-2004, OFFIS + * + * This software and supporting documentation were developed by + * + * Kuratorium OFFIS e.V. + * Healthcare Information and Communication Systems + * Escherweg 2 + * D-26121 Oldenburg, Germany + * + * THIS SOFTWARE IS MADE AVAILABLE, AS IS, AND OFFIS MAKES NO WARRANTY + * REGARDING THE SOFTWARE, ITS PERFORMANCE, ITS MERCHANTABILITY OR + * FITNESS FOR ANY PARTICULAR USE, FREEDOM FROM ANY COMPUTER DISEASES OR + * ITS CONFORMITY TO ANY SPECIFICATION. THE ENTIRE RISK AS TO QUALITY AND + * PERFORMANCE OF THE SOFTWARE IS WITH THE USER. + * + * Copyright of the software and supporting documentation is, unless + * otherwise stated, owned by OFFIS, and free access is hereby granted as + * a license to use this software, copy this software and prepare + * derivative works based upon this software. However, any distribution + * of this software source code or supporting documentation or derivative + * works (source code and supporting documentation) must include the + * three paragraphs of this copyright notice. + * + */ + +Some portions of the DCMTK software package are derived from earlier +versions of this software with the following copyright, and can be +identifed by the following copyright notice located in each source file: + +/* + * Copyright (C) 1993/1994, OFFIS, Oldenburg University and CERIUM + * + * This software and supporting documentation were + * developed by + * + * Institut OFFIS + * Bereich Kommunikationssysteme + * Westerstr. 10-12 + * 26121 Oldenburg, Germany + * + * Fachbereich Informatik + * Abteilung Prozessinformatik + * Carl von Ossietzky Universitaet Oldenburg + * Ammerlaender Heerstr. 114-118 + * 26111 Oldenburg, Germany + * + * CERIUM + * Laboratoire SIM + * Faculte de Medecine + * 2 Avenue du Pr. Leon Bernard + * 35043 Rennes Cedex, France + * + * for CEN/TC251/WG4 as a contribution to the Radiological + * Society of North America (RSNA) 1993 Digital Imaging and + * Communications in Medicine (DICOM) Demonstration. + * + * THIS SOFTWARE IS MADE AVAILABLE, AS IS, AND NEITHER OFFIS, + * OLDENBURG UNIVERSITY NOR CERIUM MAKE ANY WARRANTY REGARDING + * THE SOFTWARE, ITS PERFORMANCE, ITS MERCHANTABILITY OR + * FITNESS FOR ANY PARTICULAR USE, FREEDOM FROM ANY COMPUTER + * DISEASES OR ITS CONFORMITY TO ANY SPECIFICATION. THE + * ENTIRE RISK AS TO QUALITY AND PERFORMANCE OF THE SOFTWARE + * IS WITH THE USER. + * + * Copyright of the software and supporting documentation + * is, unless otherwise stated, jointly owned by OFFIS, + * Oldenburg University and CERIUM and free access is hereby + * granted as a license to use this software, copy this + * software and prepare derivative works based upon this + * software. However, any distribution of this software + * source code or supporting documentation or derivative + * works (source code and supporting documentation) must + * include the three paragraphs of this copyright notice. + * + */ + +Some other parts of this software within the dcmtk/dcmnet +sub-package related to the DICOM Upper Layer Protocol are +derived from software developed for the RSNA'93 DICOM +demonstration and kindly made available to us by the Mallinckrodt +Institute of Radiology. Such software can be identifed by the +following copyright notice located in each affected source file: + +/* + * Copyright (C) 1993, RSNA and Washington University + * + * The software and supporting documentation for the Radiological + * Society of North America (RSNA) 1993 Digital Imaging and + * Communications in Medicine (DICOM) Demonstration were developed + * at the + * Electronic Radiology Laboratory + * Mallinckrodt Institute of Radiology + * Washington University School of Medicine + * 510 S. Kingshighway Blvd. + * St. Louis, MO 63110 + * as part of the 1993 DICOM Central Test Node project for, and + * under contract with, the Radiological Society of North America. + * + * THIS SOFTWARE IS MADE AVAILABLE, AS IS, AND NEITHER RSNA NOR + * WASHINGTON UNIVERSITY MAKE ANY WARRANTY ABOUT THE SOFTWARE, ITS + * PERFORMANCE, ITS MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR + * USE, FREEDOM FROM ANY COMPUTER DISEASES OR ITS CONFORMITY TO ANY + * SPECIFICATION. THE ENTIRE RISK AS TO QUALITY AND PERFORMANCE OF + * THE SOFTWARE IS WITH THE USER. + * + * Copyright of the software and supporting documentation is + * jointly owned by RSNA and Washington University, and free access + * is hereby granted as a license to use this software, copy this + * software and prepare derivative works based upon this software. + * However, any distribution of this software source code or + * supporting documentation or derivative works (source code and + * supporting documentation) must include the three paragraphs of + * the copyright notice. + */ + +The dcmjpeg sub-package includes an adapted version of the Independent JPEG +Group Toolkit Version 6b, which is contained in dcmjpeg/libijg8, +dcmjpeg/libijg12 and dcmjpeg/libijg16. This toolkit is covered by the +following copyright. The original README file for the Independent JPEG +Group Toolkit is located in dcmjpeg/docs/ijg_readme.txt. + +/* + * The authors make NO WARRANTY or representation, either express or implied, + * with respect to this software, its quality, accuracy, merchantability, or + * fitness for a particular purpose. This software is provided "AS IS", and you, + * its user, assume the entire risk as to its quality and accuracy. + * + * This software is copyright (C) 1991-1998, Thomas G. Lane. + * All Rights Reserved except as specified below. + * + * Permission is hereby granted to use, copy, modify, and distribute this + * software (or portions thereof) for any purpose, without fee, subject to these + * conditions: + * (1) If any part of the source code for this software is distributed, then this + * README file must be included, with this copyright and no-warranty notice + * unaltered; and any additions, deletions, or changes to the original files + * must be clearly indicated in accompanying documentation. + * (2) If only executable code is distributed, then the accompanying + * documentation must state that "this software is based in part on the work of + * the Independent JPEG Group". + * (3) Permission for use of this software is granted only if the user accepts + * full responsibility for any undesirable consequences; the authors accept + * NO LIABILITY for damages of any kind. + * + * These conditions apply to any software derived from or based on the IJG code, + * not just to the unmodified library. If you use our work, you ought to + * acknowledge us. + * + * Permission is NOT granted for the use of any IJG author's name or company name + * in advertising or publicity relating to this software or products derived from + * it. This software may be referred to only as "the Independent JPEG Group's + * software". + * + * We specifically permit and encourage the use of this software as the basis of + * commercial products, provided that all warranty or liability claims are + * assumed by the product vendor. + */ + + +The color quantization code in module dcmimage (dcmquant and the related +classes) is derived from code written by Jef Poskanzer for the NetPBM +toolkit which has the following copyright: + +/* + * Copyright (C) 1989, 1991 by Jef Poskanzer. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation. This software is provided "as is" without express or + * implied warranty. + */ + + +The code for the OFStandard::strlcpy and OFStandard::strlcat helper +functions in ofstd/libsrc/ofstd.cc has been derived from the BSD +implementation of strlcpy() and strlcat() and which carries the +following copyright notice: + +/* + * Copyright (c) 1998 Todd C. Miller <Todd.Miller(at)courtesan.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +The code for the OFStandard::atof helper function in +ofstd/libsrc/ofstd.cc has been derived from an implementation which +carries the following copyright notice: + +/* + * Copyright 1988 Regents of the University of California + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appear in all copies. The + * University of California makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * + * The code for OFStandard::ftoa has been derived + * from an implementation which carries the following copyright notice: + * + * Copyright (c) 1988 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +The "Base64" encoder/decoder in ofstd/libsrc/ofstd.cc has been derived +from an implementation which carries the following copyright notice: + +/* + * Copyright (c) 1999, Bob Withers - bwit(at)pobox.com + * + * This code may be freely used for any purpose, either personal or commercial, + * provided the authors copyright notice remains intact. + */ + diff --git a/Utilities/ITK/Utilities/itkjpeg/README b/Utilities/ITK/Utilities/itkjpeg/README new file mode 100644 index 0000000000000000000000000000000000000000..242359479d6c40f7da40f80f0ebc08adfe0b6b29 --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/README @@ -0,0 +1,385 @@ +The Independent JPEG Group's JPEG software +========================================== + +README for release 6b of 27-Mar-1998 +==================================== + +This distribution contains the sixth public release of the Independent JPEG +Group's free JPEG software. You are welcome to redistribute this software and +to use it for any purpose, subject to the conditions under LEGAL ISSUES, below. + +Serious users of this software (particularly those incorporating it into +larger programs) should contact IJG at jpeg-info@uunet.uu.net to be added to +our electronic mailing list. Mailing list members are notified of updates +and have a chance to participate in technical discussions, etc. + +This software is the work of Tom Lane, Philip Gladstone, Jim Boucher, +Lee Crocker, Julian Minguillon, Luis Ortiz, George Phillips, Davide Rossi, +Guido Vollbeding, Ge' Weijers, and other members of the Independent JPEG +Group. + +IJG is not affiliated with the official ISO JPEG standards committee. + + +DOCUMENTATION ROADMAP +===================== + +This file contains the following sections: + +OVERVIEW General description of JPEG and the IJG software. +LEGAL ISSUES Copyright, lack of warranty, terms of distribution. +REFERENCES Where to learn more about JPEG. +ARCHIVE LOCATIONS Where to find newer versions of this software. +RELATED SOFTWARE Other stuff you should get. +FILE FORMAT WARS Software *not* to get. +TO DO Plans for future IJG releases. + +Other documentation files in the distribution are: + +User documentation: + install.doc How to configure and install the IJG software. + usage.doc Usage instructions for cjpeg, djpeg, jpegtran, + rdjpgcom, and wrjpgcom. + *.1 Unix-style man pages for programs (same info as usage.doc). + wizard.doc Advanced usage instructions for JPEG wizards only. + change.log Version-to-version change highlights. +Programmer and internal documentation: + libjpeg.doc How to use the JPEG library in your own programs. + example.c Sample code for calling the JPEG library. + structure.doc Overview of the JPEG library's internal structure. + filelist.doc Road map of IJG files. + coderules.doc Coding style rules --- please read if you contribute code. + +Please read at least the files install.doc and usage.doc. Useful information +can also be found in the JPEG FAQ (Frequently Asked Questions) article. See +ARCHIVE LOCATIONS below to find out where to obtain the FAQ article. + +If you want to understand how the JPEG code works, we suggest reading one or +more of the REFERENCES, then looking at the documentation files (in roughly +the order listed) before diving into the code. + + +OVERVIEW +======== + +This package contains C software to implement JPEG image compression and +decompression. JPEG (pronounced "jay-peg") is a standardized compression +method for full-color and gray-scale images. JPEG is intended for compressing +"real-world" scenes; line drawings, cartoons and other non-realistic images +are not its strong suit. JPEG is lossy, meaning that the output image is not +exactly identical to the input image. Hence you must not use JPEG if you +have to have identical output bits. However, on typical photographic images, +very good compression levels can be obtained with no visible change, and +remarkably high compression levels are possible if you can tolerate a +low-quality image. For more details, see the references, or just experiment +with various compression settings. + +This software implements JPEG baseline, extended-sequential, progressive +and lossless compression processes. Provision is made for supporting all +variants of these processes, although some uncommon parameter settings aren't +implemented yet. For legal reasons, we are not distributing code for the +arithmetic-coding variants of JPEG; see LEGAL ISSUES. We have made no +provision for supporting the hierarchical processes defined in the standard. + +We provide a set of library routines for reading and writing JPEG image files, +plus two sample applications "cjpeg" and "djpeg", which use the library to +perform conversion between JPEG and some other popular image file formats. +The library is intended to be reused in other applications. + +In order to support file conversion and viewing software, we have included +considerable functionality beyond the bare JPEG coding/decoding capability; +for example, the color quantization modules are not strictly part of JPEG +decoding, but they are essential for output to colormapped file formats or +colormapped displays. These extra functions can be compiled out of the +library if not required for a particular application. We have also included +"jpegtran", a utility for lossless transcoding between different JPEG +processes, and "rdjpgcom" and "wrjpgcom", two simple applications for +inserting and extracting textual comments in JFIF files. + +The emphasis in designing this software has been on achieving portability and +flexibility, while also making it fast enough to be useful. In particular, +the software is not intended to be read as a tutorial on JPEG. (See the +REFERENCES section for introductory material.) Rather, it is intended to +be reliable, portable, industrial-strength code. We do not claim to have +achieved that goal in every aspect of the software, but we strive for it. + +We welcome the use of this software as a component of commercial products. +No royalty is required, but we do ask for an acknowledgement in product +documentation, as described under LEGAL ISSUES. + + +LEGAL ISSUES +============ + +In plain English: + +1. We don't promise that this software works. (But if you find any bugs, + please let us know!) +2. You can use this software for whatever you want. You don't have to pay us. +3. You may not pretend that you wrote this software. If you use it in a + program, you must acknowledge somewhere in your documentation that + you've used the IJG code. + +In legalese: + +The authors make NO WARRANTY or representation, either express or implied, +with respect to this software, its quality, accuracy, merchantability, or +fitness for a particular purpose. This software is provided "AS IS", and you, +its user, assume the entire risk as to its quality and accuracy. + +This software is copyright (C) 1991-1998, Thomas G. Lane. +All Rights Reserved except as specified below. + +Permission is hereby granted to use, copy, modify, and distribute this +software (or portions thereof) for any purpose, without fee, subject to these +conditions: +(1) If any part of the source code for this software is distributed, then this +README file must be included, with this copyright and no-warranty notice +unaltered; and any additions, deletions, or changes to the original files +must be clearly indicated in accompanying documentation. +(2) If only executable code is distributed, then the accompanying +documentation must state that "this software is based in part on the work of +the Independent JPEG Group". +(3) Permission for use of this software is granted only if the user accepts +full responsibility for any undesirable consequences; the authors accept +NO LIABILITY for damages of any kind. + +These conditions apply to any software derived from or based on the IJG code, +not just to the unmodified library. If you use our work, you ought to +acknowledge us. + +Permission is NOT granted for the use of any IJG author's name or company name +in advertising or publicity relating to this software or products derived from +it. This software may be referred to only as "the Independent JPEG Group's +software". + +We specifically permit and encourage the use of this software as the basis of +commercial products, provided that all warranty or liability claims are +assumed by the product vendor. + + +ansi2knr.c is included in this distribution by permission of L. Peter Deutsch, +sole proprietor of its copyright holder, Aladdin Enterprises of Menlo Park, CA. +ansi2knr.c is NOT covered by the above copyright and conditions, but instead +by the usual distribution terms of the Free Software Foundation; principally, +that you must include source code if you redistribute it. (See the file +ansi2knr.c for full details.) However, since ansi2knr.c is not needed as part +of any program generated from the IJG code, this does not limit you more than +the foregoing paragraphs do. + +The Unix configuration script "configure" was produced with GNU Autoconf. +It is copyright by the Free Software Foundation but is freely distributable. +The same holds for its supporting scripts (config.guess, config.sub, +ltconfig, ltmain.sh). Another support script, install-sh, is copyright +by M.I.T. but is also freely distributable. + +It appears that the arithmetic coding option of the JPEG spec is covered by +patents owned by IBM, AT&T, and Mitsubishi. Hence arithmetic coding cannot +legally be used without obtaining one or more licenses. For this reason, +support for arithmetic coding has been removed from the free JPEG software. +(Since arithmetic coding provides only a marginal gain over the unpatented +Huffman mode, it is unlikely that very many implementations will support it.) +So far as we are aware, there are no patent restrictions on the remaining +code. + +The IJG distribution formerly included code to read and write GIF files. +To avoid entanglement with the Unisys LZW patent, GIF reading support has +been removed altogether, and the GIF writer has been simplified to produce +"uncompressed GIFs". This technique does not use the LZW algorithm; the +resulting GIF files are larger than usual, but are readable by all standard +GIF decoders. + +We are required to state that + "The Graphics Interchange Format(c) is the Copyright property of + CompuServe Incorporated. GIF(sm) is a Service Mark property of + CompuServe Incorporated." + + +REFERENCES +========== + +We highly recommend reading one or more of these references before trying to +understand the innards of the JPEG software. + +The best short technical introduction to the JPEG compression algorithm is + Wallace, Gregory K. "The JPEG Still Picture Compression Standard", + Communications of the ACM, April 1991 (vol. 34 no. 4), pp. 30-44. +(Adjacent articles in that issue discuss MPEG motion picture compression, +applications of JPEG, and related topics.) If you don't have the CACM issue +handy, a PostScript file containing a revised version of Wallace's article is +available at ftp://ftp.uu.net/graphics/jpeg/wallace.ps.gz. The file (actually +a preprint for an article that appeared in IEEE Trans. Consumer Electronics) +omits the sample images that appeared in CACM, but it includes corrections +and some added material. Note: the Wallace article is copyright ACM and IEEE, +and it may not be used for commercial purposes. + +A somewhat less technical, more leisurely introduction to JPEG can be found in +"The Data Compression Book" by Mark Nelson and Jean-loup Gailly, published by +M&T Books (New York), 2nd ed. 1996, ISBN 1-55851-434-1. This book provides +good explanations and example C code for a multitude of compression methods +including JPEG. It is an excellent source if you are comfortable reading C +code but don't know much about data compression in general. The book's JPEG +sample code is far from industrial-strength, but when you are ready to look +at a full implementation, you've got one here... + +The best full description of JPEG is the textbook "JPEG Still Image Data +Compression Standard" by William B. Pennebaker and Joan L. Mitchell, published +by Van Nostrand Reinhold, 1993, ISBN 0-442-01272-1. Price US$59.95, 638 pp. +The book includes the complete text of the ISO JPEG standards (DIS 10918-1 +and draft DIS 10918-2). This is by far the most complete exposition of JPEG +in existence, and we highly recommend it. + +The JPEG standard itself is not available electronically; you must order a +paper copy through ISO or ITU. (Unless you feel a need to own a certified +official copy, we recommend buying the Pennebaker and Mitchell book instead; +it's much cheaper and includes a great deal of useful explanatory material.) +In the USA, copies of the standard may be ordered from ANSI Sales at (212) +642-4900, or from Global Engineering Documents at (800) 854-7179. (ANSI +doesn't take credit card orders, but Global does.) It's not cheap: as of +1992, ANSI was charging $95 for Part 1 and $47 for Part 2, plus 7% +shipping/handling. The standard is divided into two parts, Part 1 being the +actual specification, while Part 2 covers compliance testing methods. Part 1 +is titled "Digital Compression and Coding of Continuous-tone Still Images, +Part 1: Requirements and guidelines" and has document numbers ISO/IEC IS +10918-1, ITU-T T.81. Part 2 is titled "Digital Compression and Coding of +Continuous-tone Still Images, Part 2: Compliance testing" and has document +numbers ISO/IEC IS 10918-2, ITU-T T.83. + +Some extensions to the original JPEG standard are defined in JPEG Part 3, +a newer ISO standard numbered ISO/IEC IS 10918-3 and ITU-T T.84. IJG +currently does not support any Part 3 extensions. + +The JPEG standard does not specify all details of an interchangeable file +format. For the omitted details we follow the "JFIF" conventions, revision +1.02. A copy of the JFIF spec is available from: + Literature Department + C-Cube Microsystems, Inc. + 1778 McCarthy Blvd. + Milpitas, CA 95035 + phone (408) 944-6300, fax (408) 944-6314 +A PostScript version of this document is available by FTP at +ftp://ftp.uu.net/graphics/jpeg/jfif.ps.gz. There is also a plain text +version at ftp://ftp.uu.net/graphics/jpeg/jfif.txt.gz, but it is missing +the figures. + +The TIFF 6.0 file format specification can be obtained by FTP from +ftp://ftp.sgi.com/graphics/tiff/TIFF6.ps.gz. The JPEG incorporation scheme +found in the TIFF 6.0 spec of 3-June-92 has a number of serious problems. +IJG does not recommend use of the TIFF 6.0 design (TIFF Compression tag 6). +Instead, we recommend the JPEG design proposed by TIFF Technical Note #2 +(Compression tag 7). Copies of this Note can be obtained from ftp.sgi.com or +from ftp://ftp.uu.net/graphics/jpeg/. It is expected that the next revision +of the TIFF spec will replace the 6.0 JPEG design with the Note's design. +Although IJG's own code does not support TIFF/JPEG, the free libtiff library +uses our library to implement TIFF/JPEG per the Note. libtiff is available +from ftp://ftp.sgi.com/graphics/tiff/. + + +ARCHIVE LOCATIONS +================= + +The "official" archive site for this software is ftp.uu.net (Internet +address 192.48.96.9). The most recent released version can always be found +there in directory graphics/jpeg. This particular version will be archived +as ftp://ftp.uu.net/graphics/jpeg/jpegsrc.v6b.tar.gz. If you don't have +direct Internet access, UUNET's archives are also available via UUCP; contact +help@uunet.uu.net for information on retrieving files that way. + +Numerous Internet sites maintain copies of the UUNET files. However, only +ftp.uu.net is guaranteed to have the latest official version. + +You can also obtain this software in DOS-compatible "zip" archive format from +the SimTel archives (ftp://ftp.simtel.net/pub/simtelnet/msdos/graphics/), or +on CompuServe in the Graphics Support forum (GO CIS:GRAPHSUP), library 12 +"JPEG Tools". Again, these versions may sometimes lag behind the ftp.uu.net +release. + +The JPEG FAQ (Frequently Asked Questions) article is a useful source of +general information about JPEG. It is updated constantly and therefore is +not included in this distribution. The FAQ is posted every two weeks to +Usenet newsgroups comp.graphics.misc, news.answers, and other groups. +It is available on the World Wide Web at http://www.faqs.org/faqs/jpeg-faq/ +and other news.answers archive sites, including the official news.answers +archive at rtfm.mit.edu: ftp://rtfm.mit.edu/pub/usenet/news.answers/jpeg-faq/. +If you don't have Web or FTP access, send e-mail to mail-server@rtfm.mit.edu +with body + send usenet/news.answers/jpeg-faq/part1 + send usenet/news.answers/jpeg-faq/part2 + + +RELATED SOFTWARE +================ + +Numerous viewing and image manipulation programs now support JPEG. (Quite a +few of them use this library to do so.) The JPEG FAQ described above lists +some of the more popular free and shareware viewers, and tells where to +obtain them on Internet. + +If you are on a Unix machine, we highly recommend Jef Poskanzer's free +PBMPLUS software, which provides many useful operations on PPM-format image +files. In particular, it can convert PPM images to and from a wide range of +other formats, thus making cjpeg/djpeg considerably more useful. The latest +version is distributed by the NetPBM group, and is available from numerous +sites, notably ftp://wuarchive.wustl.edu/graphics/graphics/packages/NetPBM/. +Unfortunately PBMPLUS/NETPBM is not nearly as portable as the IJG software is; +you are likely to have difficulty making it work on any non-Unix machine. + +A different free JPEG implementation, written by the PVRG group at Stanford, +is available from ftp://havefun.stanford.edu/pub/jpeg/. This program +is designed for research and experimentation rather than production use; +it is slower, harder to use, and less portable than the IJG code, but it +is easier to read and modify. Also, the PVRG code supports lossless JPEG, +which we do not. (On the other hand, it doesn't do progressive JPEG.) + + +FILE FORMAT WARS +================ + +Some JPEG programs produce files that are not compatible with our library. +The root of the problem is that the ISO JPEG committee failed to specify a +concrete file format. Some vendors "filled in the blanks" on their own, +creating proprietary formats that no one else could read. (For example, none +of the early commercial JPEG implementations for the Macintosh were able to +exchange compressed files.) + +The file format we have adopted is called JFIF (see REFERENCES). This format +has been agreed to by a number of major commercial JPEG vendors, and it has +become the de facto standard. JFIF is a minimal or "low end" representation. +We recommend the use of TIFF/JPEG (TIFF revision 6.0 as modified by TIFF +Technical Note #2) for "high end" applications that need to record a lot of +additional data about an image. TIFF/JPEG is fairly new and not yet widely +supported, unfortunately. + +The upcoming JPEG Part 3 standard defines a file format called SPIFF. +SPIFF is interoperable with JFIF, in the sense that most JFIF decoders should +be able to read the most common variant of SPIFF. SPIFF has some technical +advantages over JFIF, but its major claim to fame is simply that it is an +official standard rather than an informal one. At this point it is unclear +whether SPIFF will supersede JFIF or whether JFIF will remain the de-facto +standard. IJG intends to support SPIFF once the standard is frozen, but we +have not decided whether it should become our default output format or not. +(In any case, our decoder will remain capable of reading JFIF indefinitely.) + +Various proprietary file formats incorporating JPEG compression also exist. +We have little or no sympathy for the existence of these formats. Indeed, +one of the original reasons for developing this free software was to help +force convergence on common, open format standards for JPEG files. Don't +use a proprietary file format! + + +TO DO +===== + +The major thrust for v7 will probably be improvement of visual quality. +The current method for scaling the quantization tables is known not to be +very good at low Q values. We also intend to investigate block boundary +smoothing, "poor man's variable quantization", and other means of improving +quality-vs-file-size performance without sacrificing compatibility. + +In future versions, we are considering supporting some of the upcoming JPEG +Part 3 extensions --- principally, variable quantization and the SPIFF file +format. + +As always, speeding things up is of great interest. + +Please send bug reports, offers of help, etc. to jpeg-info@uunet.uu.net. diff --git a/Utilities/ITK/Utilities/itkjpeg/README.GDCM.txt b/Utilities/ITK/Utilities/itkjpeg/README.GDCM.txt new file mode 100644 index 0000000000000000000000000000000000000000..e88393ae9d5bed3e3ea3ba21d63f42914ea4a865 --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/README.GDCM.txt @@ -0,0 +1,105 @@ +This directory contains a subset of the Independent JPEG Group's (IJG) +libjpeg version 6b. We only include enough of distribution to build +libjpeg. We do not include the standard executables that come with +libjpeg (cjpeg, djpeg, etc.). Furthermore, the standard libjpeg build +process is replaced with a CMake build process. + +We'd like to thank the IJG for distributing a public JPEG IO library. + +We'd like to also thank the dcmtk crew for releasing their toolkit under such a nice license that allow us to patch ijg properly to handle all sort of jpeg compression found in the DICOM implementation. The copyright can be found in COPYRIGHT.dcmtk. + +Modifications +------------- + +1. +jconfig.h is usually generated by the build process. For this distribution, +we ship a version of jconfig.h.in to be used across several platforms. It's +purpose is also to allow generation of both 8bits and 12bits lib. + + + +2. +jdhuff.c was modified to support special Philips MRI image: + +Index: jdhuff.c +=================================================================== +RCS file: /cvs/public/gdcm/src/jpeg/libijg8/jdhuff.c,v +retrieving revision 1.1 +diff -u -3 -p -r1.1 jdhuff.c +--- jdhuff.c 24 Jun 2003 10:09:48 -0000 1.1 ++++ jdhuff.c 7 Oct 2004 02:29:43 -0000 +@@ -259,8 +259,11 @@ jpeg_make_d_derived_tbl (j_decompress_pt + if (isDC) { + for (i = 0; i < numsymbols; i++) { + int sym = htbl->huffval[i]; +- if (sym < 0 || sym > 15) +- ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); ++ if (sym < 0 || sym > 15) { ++ // Now, we can read Philips MRI Images ++ htbl->huffval[i]=15; ++// ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); ++ } + } + } + } + + +3. +jmorecfg.h was modified so that we can modify it automatically at build time to +either generate a 8bits jpeg lib or 12bits jpeg library: + +Index: jmorecfg.h +=================================================================== +RCS file: /cvs/public/gdcm/src/jpeg/libijg8/jmorecfg.h,v +retrieving revision 1.4 +diff -u -3 -p -r1.4 jmorecfg.h +--- jmorecfg.h 31 Oct 2003 14:59:50 -0000 1.4 ++++ jmorecfg.h 7 Oct 2004 02:30:40 -0000 +@@ -19,7 +19,8 @@ + * We do not support run-time selection of data precision, sorry. + */ + +-#define BITS_IN_JSAMPLE 8 /* use 8 or 12 */ ++//#define BITS_IN_JSAMPLE 8 /* use 8 or 12 */ ++#define BITS_IN_JSAMPLE @GDCM_BITS_IN_JSAMPLE@ + + /* + * Maximum number of components (color channels) allowed in JPEG image. + + + + +4. +To further allow us to have to different copy of the 8, 12 and 16 bits jpeg +library we had to mangle the name. Fur this purpose two new file were added to +the library: gdcm_mangle_8bits.h, gdcm_mangle_12bits.h and gdcm_mangle_16bits.h. +Those file were generated using: + + nm libgdcmijpeg8.a | grep " [R|T] " | colrm 1 11 | sort + + +5. +In order to read lossless images, we had to apply the ls-patch to jpeg-6b. So I started from scratch: + +tar xvfz /tmp/jpegsrc.v6b.tar.gz (1) +patch < /tmp/ljpeg-6b.patch (2) +patch -p0 < arithmetic-without-arith-option-full.patch (3) +patch -p0 < warnings10-14.patch (4) +patch -p0 < previous-gdcm.patch (5) +----------------------------------------------------------- += The subdir src/jpeg/libijg + +(now I also need to apply the redhat patch for cplusplus lib) + +(1) http://www.ijg.org/files/jpegsrc.v6b.tar.gz +(2) http://www.oceana.com/ftp/ljpeg/ljpeg-patch.v6b.tar.gz +(3), (4) and (5) http://www.creatis.insa-lyon.fr/~malaterre/jpeg/ + +(3) Was made with a carefull inspection of dcmtk code (see convert.sh at the same spot as the patch) +(4) Is basically just compilation of the lib with -W -Wall -Werror +(5) This contains some configuration copy/paste from VTK, and the 'well known' 12 bits Philips MRI DICOM patch + + + +NOTE for later: +(shoud we disable getenv just as dcmtk ? there is a ijg flag for that NO_ENV or something similar diff --git a/Utilities/ITK/Utilities/itkjpeg/README.ITK.txt b/Utilities/ITK/Utilities/itkjpeg/README.ITK.txt new file mode 100644 index 0000000000000000000000000000000000000000..ebe67e264bdfca69aefb09f05facb6902ed7b5f0 --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/README.ITK.txt @@ -0,0 +1,22 @@ +This directory contains a subset of the Independent JPEG Group's (IJG) +libjpeg version 6b. We only include enough of distribution to build +libjpeg. We do not include the standard executables that come with +libjpeg (cjpeg, djpeg, etc.). Furthermore, the standard libjpeg build +process is replaced with a CMake build process. + +We'd like to thank the IJG for distributing a public JPEG IO library. + +Modifications +------------- + +jconfig.h is usually generated by the build process. For this distribution, +we ship a version of jconfig.h to be used across several platforms. + +jmorecfg.h was altered to support Windows DLL generation. We also +changed the typedef INT32 to be an "int" instead of a "long". + + + + + + diff --git a/Utilities/ITK/Utilities/itkjpeg/change.log b/Utilities/ITK/Utilities/itkjpeg/change.log new file mode 100644 index 0000000000000000000000000000000000000000..74102c0db5aa2bf3dae6f3f54673b1a257004aee --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/change.log @@ -0,0 +1,217 @@ +CHANGE LOG for Independent JPEG Group's JPEG software + + +Version 6b 27-Mar-1998 +----------------------- + +jpegtran has new features for lossless image transformations (rotation +and flipping) as well as "lossless" reduction to grayscale. + +jpegtran now copies comments by default; it has a -copy switch to enable +copying all APPn blocks as well, or to suppress comments. (Formerly it +always suppressed comments and APPn blocks.) jpegtran now also preserves +JFIF version and resolution information. + +New decompressor library feature: COM and APPn markers found in the input +file can be saved in memory for later use by the application. (Before, +you had to code this up yourself with a custom marker processor.) + +There is an unused field "void * client_data" now in compress and decompress +parameter structs; this may be useful in some applications. + +JFIF version number information is now saved by the decoder and accepted by +the encoder. jpegtran uses this to copy the source file's version number, +to ensure "jpegtran -copy all" won't create bogus files that contain JFXX +extensions but claim to be version 1.01. Applications that generate their +own JFXX extension markers also (finally) have a supported way to cause the +encoder to emit JFIF version number 1.02. + +djpeg's trace mode reports JFIF 1.02 thumbnail images as such, rather +than as unknown APP0 markers. + +In -verbose mode, djpeg and rdjpgcom will try to print the contents of +APP12 markers as text. Some digital cameras store useful text information +in APP12 markers. + +Handling of truncated data streams is more robust: blocks beyond the one in +which the error occurs will be output as uniform gray, or left unchanged +if decoding a progressive JPEG. The appearance no longer depends on the +Huffman tables being used. + +Huffman tables are checked for validity much more carefully than before. + +To avoid the Unisys LZW patent, djpeg's GIF output capability has been +changed to produce "uncompressed GIFs", and cjpeg's GIF input capability +has been removed altogether. We're not happy about it either, but there +seems to be no good alternative. + +The configure script now supports building libjpeg as a shared library +on many flavors of Unix (all the ones that GNU libtool knows how to +build shared libraries for). Use "./configure --enable-shared" to +try this out. + +New jconfig file and makefiles for Microsoft Visual C++ and Developer Studio. +Also, a jconfig file and a build script for Metrowerks CodeWarrior +on Apple Macintosh. makefile.dj has been updated for DJGPP v2, and there +are miscellaneous other minor improvements in the makefiles. + +jmemmac.c now knows how to create temporary files following Mac System 7 +conventions. + +djpeg's -map switch is now able to read raw-format PPM files reliably. + +cjpeg -progressive -restart no longer generates any unnecessary DRI markers. + +Multiple calls to jpeg_simple_progression for a single JPEG object +no longer leak memory. + + +Version 6a 7-Feb-96 +-------------------- + +Library initialization sequence modified to detect version mismatches +and struct field packing mismatches between library and calling application. +This change requires applications to be recompiled, but does not require +any application source code change. + +All routine declarations changed to the style "GLOBAL(type) name ...", +that is, GLOBAL, LOCAL, METHODDEF, EXTERN are now macros taking the +routine's return type as an argument. This makes it possible to add +Microsoft-style linkage keywords to all the routines by changing just +these macros. Note that any application code that was using these macros +will have to be changed. + +DCT coefficient quantization tables are now stored in normal array order +rather than zigzag order. Application code that calls jpeg_add_quant_table, +or otherwise manipulates quantization tables directly, will need to be +changed. If you need to make such code work with either older or newer +versions of the library, a test like "#if JPEG_LIB_VERSION >= 61" is +recommended. + +djpeg's trace capability now dumps DQT tables in natural order, not zigzag +order. This allows the trace output to be made into a "-qtables" file +more easily. + +New system-dependent memory manager module for use on Apple Macintosh. + +Fix bug in cjpeg's -smooth option: last one or two scanlines would be +duplicates of the prior line unless the image height mod 16 was 1 or 2. + +Repair minor problems in VMS, BCC, MC6 makefiles. + +New configure script based on latest GNU Autoconf. + +Correct the list of include files needed by MetroWerks C for ccommand(). + +Numerous small documentation updates. + + +Version 6 2-Aug-95 +------------------- + +Progressive JPEG support: library can read and write full progressive JPEG +files. A "buffered image" mode supports incremental decoding for on-the-fly +display of progressive images. Simply recompiling an existing IJG-v5-based +decoder with v6 should allow it to read progressive files, though of course +without any special progressive display. + +New "jpegtran" application performs lossless transcoding between different +JPEG formats; primarily, it can be used to convert baseline to progressive +JPEG and vice versa. In support of jpegtran, the library now allows lossless +reading and writing of JPEG files as DCT coefficient arrays. This ability +may be of use in other applications. + +Notes for programmers: +* We changed jpeg_start_decompress() to be able to suspend; this makes all +decoding modes available to suspending-input applications. However, +existing applications that use suspending input will need to be changed +to check the return value from jpeg_start_decompress(). You don't need to +do anything if you don't use a suspending data source. +* We changed the interface to the virtual array routines: access_virt_array +routines now take a count of the number of rows to access this time. The +last parameter to request_virt_array routines is now interpreted as the +maximum number of rows that may be accessed at once, but not necessarily +the height of every access. + + +Version 5b 15-Mar-95 +--------------------- + +Correct bugs with grayscale images having v_samp_factor > 1. + +jpeg_write_raw_data() now supports output suspension. + +Correct bugs in "configure" script for case of compiling in +a directory other than the one containing the source files. + +Repair bug in jquant1.c: sometimes didn't use as many colors as it could. + +Borland C makefile and jconfig file work under either MS-DOS or OS/2. + +Miscellaneous improvements to documentation. + + +Version 5a 7-Dec-94 +-------------------- + +Changed color conversion roundoff behavior so that grayscale values are +represented exactly. (This causes test image files to change.) + +Make ordered dither use 16x16 instead of 4x4 pattern for a small quality +improvement. + +New configure script based on latest GNU Autoconf. +Fix configure script to handle CFLAGS correctly. +Rename *.auto files to *.cfg, so that configure script still works if +file names have been truncated for DOS. + +Fix bug in rdbmp.c: didn't allow for extra data between header and image. + +Modify rdppm.c/wrppm.c to handle 2-byte raw PPM/PGM formats for 12-bit data. + +Fix several bugs in rdrle.c. + +NEED_SHORT_EXTERNAL_NAMES option was broken. + +Revise jerror.h/jerror.c for more flexibility in message table. + +Repair oversight in jmemname.c NO_MKTEMP case: file could be there +but unreadable. + + +Version 5 24-Sep-94 +-------------------- + +Version 5 represents a nearly complete redesign and rewrite of the IJG +software. Major user-visible changes include: + * Automatic configuration simplifies installation for most Unix systems. + * A range of speed vs. image quality tradeoffs are supported. + This includes resizing of an image during decompression: scaling down + by a factor of 1/2, 1/4, or 1/8 is handled very efficiently. + * New programs rdjpgcom and wrjpgcom allow insertion and extraction + of text comments in a JPEG file. + +The application programmer's interface to the library has changed completely. +Notable improvements include: + * We have eliminated the use of callback routines for handling the + uncompressed image data. The application now sees the library as a + set of routines that it calls to read or write image data on a + scanline-by-scanline basis. + * The application image data is represented in a conventional interleaved- + pixel format, rather than as a separate array for each color channel. + This can save a copying step in many programs. + * The handling of compressed data has been cleaned up: the application can + supply routines to source or sink the compressed data. It is possible to + suspend processing on source/sink buffer overrun, although this is not + supported in all operating modes. + * All static state has been eliminated from the library, so that multiple + instances of compression or decompression can be active concurrently. + * JPEG abbreviated datastream formats are supported, ie, quantization and + Huffman tables can be stored separately from the image data. + * And not only that, but the documentation of the library has improved + considerably! + + +The last widely used release before the version 5 rewrite was version 4A of +18-Feb-93. Change logs before that point have been discarded, since they +are not of much interest after the rewrite. diff --git a/Utilities/ITK/Utilities/itkjpeg/filelist.doc b/Utilities/ITK/Utilities/itkjpeg/filelist.doc new file mode 100644 index 0000000000000000000000000000000000000000..9ba88e00325c33ac754e40396e123f0f8af5b3a0 --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/filelist.doc @@ -0,0 +1,239 @@ +IJG JPEG LIBRARY: FILE LIST + +Copyright (C) 1994-1997, Thomas G. Lane. +This file is part of the Independent JPEG Group's software. +For conditions of distribution and use, see the accompanying README file. + + +Here is a road map to the files in the IJG JPEG distribution. The +distribution includes the JPEG library proper, plus two application +programs ("cjpeg" and "djpeg") which use the library to convert JPEG +files to and from some other popular image formats. A third application +"jpegtran" uses the library to do lossless conversion between different +variants of JPEG. There are also two stand-alone applications, +"rdjpgcom" and "wrjpgcom". + + +THE JPEG LIBRARY +================ + +Include files: + +jpeglib.h JPEG library's exported data and function declarations. +jconfig.h Configuration declarations. Note: this file is not present + in the distribution; it is generated during installation. +jmorecfg.h Additional configuration declarations; need not be changed + for a standard installation. +jerror.h Declares JPEG library's error and trace message codes. +jinclude.h Central include file used by all IJG .c files to reference + system include files. +jpegint.h JPEG library's internal data structures. +jlossls.h JPEG library's lossless codec data structures. +jlossy.h JPEG library's lossy codec structures. +jchuff.h Private declarations for Huffman encoder modules. +jdhuff.h Private declarations for Huffman decoder modules. +jdct.h Private declarations for forward & reverse DCT subsystems. +jmemsys.h Private declarations for memory management subsystem. +jversion.h Version information. + +Applications using the library should include jpeglib.h (which in turn +includes jconfig.h and jmorecfg.h). Optionally, jerror.h may be included +if the application needs to reference individual JPEG error codes. The +other include files are intended for internal use and would not normally +be included by an application program. (cjpeg/djpeg/etc do use jinclude.h, +since its function is to improve portability of the whole IJG distribution. +Most other applications will directly include the system include files they +want, and hence won't need jinclude.h.) + + +C source code files: + +These files contain most of the functions intended to be called directly by +an application program: + +jcapimin.c Application program interface: core routines for compression. +jcapistd.c Application program interface: standard compression. +jdapimin.c Application program interface: core routines for decompression. +jdapistd.c Application program interface: standard decompression. +jcomapi.c Application program interface routines common to compression + and decompression. +jcparam.c Compression parameter setting helper routines. +jctrans.c API and library routines for transcoding compression. +jdtrans.c API and library routines for transcoding decompression. + +Compression side of the library: + +jcinit.c Initialization: determines which other modules to use. +jcmaster.c Master control: setup and inter-pass sequencing logic. +jcmainct.c Main buffer controller (preprocessor => JPEG compressor). +jchuff.c Codec-independent Huffman entropy encoding routines. +jcprepct.c Preprocessor buffer controller. +jccolor.c Color space conversion. +jcsample.c Downsampling. +jcmarker.c JPEG marker writing. +jdatadst.c Data destination manager for stdio output. + +Lossy (DCT) codec: + +jlossy.c Lossy compressor proper. +jccoefct.c Buffer controller for DCT coefficient buffer. +jcdctmgr.c DCT manager (DCT implementation selection & control). +jfdctint.c Forward DCT using slow-but-accurate integer method. +jfdctfst.c Forward DCT using faster, less accurate integer method. +jfdctflt.c Forward DCT using floating-point arithmetic. +jcshuff.c Huffman entropy coding for sequential JPEG. +jcphuff.c Huffman entropy coding for progressive JPEG. + +Lossless (spatial) codec: + +jclossls.c Lossless compressor proper. +jcdiffct.c Buffer controller for difference buffer. +jcscale.c Point transformation. +jcpred.c Sample predictor and differencer. +jclhuff.c Huffman entropy encoding for lossless JPEG. + +Decompression side of the library: + +jdmaster.c Master control: determines which other modules to use. +jdinput.c Input controller: controls input processing modules. +jdmainct.c Main buffer controller (JPEG decompressor => postprocessor). +jdhuff.c Codec-independent Huffman entropy decoding routines. +jdpostct.c Postprocessor buffer controller. +jdmarker.c JPEG marker reading. +jdsample.c Upsampling. +jdcolor.c Color space conversion. +jdmerge.c Merged upsampling/color conversion (faster, lower quality). +jquant1.c One-pass color quantization using a fixed-spacing colormap. +jquant2.c Two-pass color quantization using a custom-generated colormap. + Also handles one-pass quantization to an externally given map. +jdatasrc.c Data source manager for stdio input. + +Lossy (DCT) codec: + +jdlossy.c Lossy decompressor proper. +jdcoefct.c Buffer controller for DCT coefficient buffer. +jdshuff.c Huffman entropy decoding for sequential JPEG. +jdphuff.c Huffman entropy decoding for progressive JPEG. +jddctmgr.c IDCT manager (IDCT implementation selection & control). +jidctint.c Inverse DCT using slow-but-accurate integer method. +jidctfst.c Inverse DCT using faster, less accurate integer method. +jidctflt.c Inverse DCT using floating-point arithmetic. +jidctred.c Inverse DCTs with reduced-size outputs. + +Lossless (spatial) codec: + +jdlossls.c Lossless decompressor proper. +jddiffct.c Buffer controller for difference buffers. +jdlhuff.c Huffman entropy decoding for lossless JPEG. +jdpred.c Sample predictor and undifferencer. +jdscale.c Point transformation, sample size scaling. + +Support files for both compression and decompression: + +jerror.c Standard error handling routines (application replaceable). +jmemmgr.c System-independent (more or less) memory management code. +jcodec.c Codec-independent utility routines. +jutils.c Miscellaneous utility routines. + +jmemmgr.c relies on a system-dependent memory management module. The IJG +distribution includes the following implementations of the system-dependent +module: + +jmemnobs.c "No backing store": assumes adequate virtual memory exists. +jmemansi.c Makes temporary files with ANSI-standard routine tmpfile(). +jmemname.c Makes temporary files with program-generated file names. +jmemdos.c Custom implementation for MS-DOS (16-bit environment only): + can use extended and expanded memory as well as temp files. +jmemmac.c Custom implementation for Apple Macintosh. + +Exactly one of the system-dependent modules should be configured into an +installed JPEG library (see install.doc for hints about which one to use). +On unusual systems you may find it worthwhile to make a special +system-dependent memory manager. + + +Non-C source code files: + +jmemdosa.asm 80x86 assembly code support for jmemdos.c; used only in + MS-DOS-specific configurations of the JPEG library. + + +CJPEG/DJPEG/JPEGTRAN +==================== + +Include files: + +cdjpeg.h Declarations shared by cjpeg/djpeg/jpegtran modules. +cderror.h Additional error and trace message codes for cjpeg et al. +transupp.h Declarations for jpegtran support routines in transupp.c. + +C source code files: + +cjpeg.c Main program for cjpeg. +djpeg.c Main program for djpeg. +jpegtran.c Main program for jpegtran. +cdjpeg.c Utility routines used by all three programs. +rdcolmap.c Code to read a colormap file for djpeg's "-map" switch. +rdswitch.c Code to process some of cjpeg's more complex switches. + Also used by jpegtran. +transupp.c Support code for jpegtran: lossless image manipulations. + +Image file reader modules for cjpeg: + +rdbmp.c BMP file input. +rdgif.c GIF file input (now just a stub). +rdppm.c PPM/PGM file input. +rdrle.c Utah RLE file input. +rdtarga.c Targa file input. + +Image file writer modules for djpeg: + +wrbmp.c BMP file output. +wrgif.c GIF file output (a mere shadow of its former self). +wrppm.c PPM/PGM file output. +wrrle.c Utah RLE file output. +wrtarga.c Targa file output. + + +RDJPGCOM/WRJPGCOM +================= + +C source code files: + +rdjpgcom.c Stand-alone rdjpgcom application. +wrjpgcom.c Stand-alone wrjpgcom application. + +These programs do not depend on the IJG library. They do use +jconfig.h and jinclude.h, only to improve portability. + + +ADDITIONAL FILES +================ + +Documentation (see README for a guide to the documentation files): + +README Master documentation file. +*.doc Other documentation files. +*.1 Documentation in Unix man page format. +change.log Version-to-version change highlights. +example.c Sample code for calling JPEG library. + +Configuration/installation files and programs (see install.doc for more info): + +configure Unix shell script to perform automatic configuration. +ltconfig Support scripts for configure (from GNU libtool). +ltmain.sh +config.guess +config.sub +install-sh Install shell script for those Unix systems lacking one. +ckconfig.c Program to generate jconfig.h on non-Unix systems. +jconfig.doc Template for making jconfig.h by hand. +makefile.* Sample makefiles for particular systems. +jconfig.* Sample jconfig.h for particular systems. +ansi2knr.c De-ANSIfier for pre-ANSI C compilers (courtesy of + L. Peter Deutsch and Aladdin Enterprises). + +Test files (see install.doc for test procedure): + +test*.* Source and comparison files for confidence test. + These are binary image files, NOT text files. diff --git a/Utilities/ITK/Utilities/itkjpeg/install.doc b/Utilities/ITK/Utilities/itkjpeg/install.doc new file mode 100644 index 0000000000000000000000000000000000000000..3702b986b6f9bf5c3156a1bd84edbebfdc911b44 --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/install.doc @@ -0,0 +1,1063 @@ +INSTALLATION INSTRUCTIONS for the Independent JPEG Group's JPEG software + +Copyright (C) 1991-1998, Thomas G. Lane. +This file is part of the Independent JPEG Group's software. +For conditions of distribution and use, see the accompanying README file. + + +This file explains how to configure and install the IJG software. We have +tried to make this software extremely portable and flexible, so that it can be +adapted to almost any environment. The downside of this decision is that the +installation process is complicated. We have provided shortcuts to simplify +the task on common systems. But in any case, you will need at least a little +familiarity with C programming and program build procedures for your system. + +If you are only using this software as part of a larger program, the larger +program's installation procedure may take care of configuring the IJG code. +For example, Ghostscript's installation script will configure the IJG code. +You don't need to read this file if you just want to compile Ghostscript. + +If you are on a Unix machine, you may not need to read this file at all. +Try doing + ./configure + make + make test +If that doesn't complain, do + make install +(better do "make -n install" first to see if the makefile will put the files +where you want them). Read further if you run into snags or want to customize +the code for your system. + + +TABLE OF CONTENTS +----------------- + +Before you start +Configuring the software: + using the automatic "configure" script + using one of the supplied jconfig and makefile files + by hand +Building the software +Testing the software +Installing the software +Optional stuff +Optimization +Hints for specific systems + + +BEFORE YOU START +================ + +Before installing the software you must unpack the distributed source code. +Since you are reading this file, you have probably already succeeded in this +task. However, there is a potential for error if you needed to convert the +files to the local standard text file format (for example, if you are on +MS-DOS you may have converted LF end-of-line to CR/LF). You must apply +such conversion to all the files EXCEPT those whose names begin with "test". +The test files contain binary data; if you change them in any way then the +self-test will give bad results. + +Please check the last section of this file to see if there are hints for the +specific machine or compiler you are using. + + +CONFIGURING THE SOFTWARE +======================== + +To configure the IJG code for your system, you need to create two files: + * jconfig.h: contains values for system-dependent #define symbols. + * Makefile: controls the compilation process. +(On a non-Unix machine, you may create "project files" or some other +substitute for a Makefile. jconfig.h is needed in any environment.) + +We provide three different ways to generate these files: + * On a Unix system, you can just run the "configure" script. + * We provide sample jconfig files and makefiles for popular machines; + if your machine matches one of the samples, just copy the right sample + files to jconfig.h and Makefile. + * If all else fails, read the instructions below and make your own files. + + +Configuring the software using the automatic "configure" script +--------------------------------------------------------------- + +If you are on a Unix machine, you can just type + ./configure +and let the configure script construct appropriate configuration files. +If you're using "csh" on an old version of System V, you might need to type + sh configure +instead to prevent csh from trying to execute configure itself. +Expect configure to run for a few minutes, particularly on slower machines; +it works by compiling a series of test programs. + +Configure was created with GNU Autoconf and it follows the usual conventions +for GNU configure scripts. It makes a few assumptions that you may want to +override. You can do this by providing optional switches to configure: + +* If you want to build libjpeg as a shared library, say + ./configure --enable-shared +To get both shared and static libraries, say + ./configure --enable-shared --enable-static +Note that these switches invoke GNU libtool to take care of system-dependent +shared library building methods. If things don't work this way, please try +running configure without either switch; that should build a static library +without using libtool. If that works, your problem is probably with libtool +not with the IJG code. libtool is fairly new and doesn't support all flavors +of Unix yet. (You might be able to find a newer version of libtool than the +one included with libjpeg; see ftp.gnu.org. Report libtool problems to +bug-libtool@gnu.org.) + +* Configure will use gcc (GNU C compiler) if it's available, otherwise cc. +To force a particular compiler to be selected, use the CC option, for example + ./configure CC='cc' +The same method can be used to include any unusual compiler switches. +For example, on HP-UX you probably want to say + ./configure CC='cc -Aa' +to get HP's compiler to run in ANSI mode. + +* The default CFLAGS setting is "-O" for non-gcc compilers, "-O2" for gcc. +You can override this by saying, for example, + ./configure CFLAGS='-g' +if you want to compile with debugging support. + +* Configure will set up the makefile so that "make install" will install files +into /usr/local/bin, /usr/local/man, etc. You can specify an installation +prefix other than "/usr/local" by giving configure the option "--prefix=PATH". + +* If you don't have a lot of swap space, you may need to enable the IJG +software's internal virtual memory mechanism. To do this, give the option +"--enable-maxmem=N" where N is the default maxmemory limit in megabytes. +This is discussed in more detail under "Selecting a memory manager", below. +You probably don't need to worry about this on reasonably-sized Unix machines, +unless you plan to process very large images. + +Configure has some other features that are useful if you are cross-compiling +or working in a network of multiple machine types; but if you need those +features, you probably already know how to use them. + + +Configuring the software using one of the supplied jconfig and makefile files +----------------------------------------------------------------------------- + +If you have one of these systems, you can just use the provided configuration +files: + +Makefile jconfig file System and/or compiler + +makefile.manx jconfig.manx Amiga, Manx Aztec C +makefile.sas jconfig.sas Amiga, SAS C +makeproj.mac jconfig.mac Apple Macintosh, Metrowerks CodeWarrior +mak*jpeg.st jconfig.st Atari ST/STE/TT, Pure C or Turbo C +makefile.bcc jconfig.bcc MS-DOS or OS/2, Borland C +makefile.dj jconfig.dj MS-DOS, DJGPP (Delorie's port of GNU C) +makefile.mc6 jconfig.mc6 MS-DOS, Microsoft C (16-bit only) +makefile.wat jconfig.wat MS-DOS, OS/2, or Windows NT, Watcom C +makefile.vc jconfig.vc Windows NT/95, MS Visual C++ +make*.ds jconfig.vc Windows NT/95, MS Developer Studio +makefile.mms jconfig.vms Digital VMS, with MMS software +makefile.vms jconfig.vms Digital VMS, without MMS software + +Copy the proper jconfig file to jconfig.h and the makefile to Makefile (or +whatever your system uses as the standard makefile name). For more info see +the appropriate system-specific hints section near the end of this file. + + +Configuring the software by hand +-------------------------------- + +First, generate a jconfig.h file. If you are moderately familiar with C, +the comments in jconfig.doc should be enough information to do this; just +copy jconfig.doc to jconfig.h and edit it appropriately. Otherwise, you may +prefer to use the ckconfig.c program. You will need to compile and execute +ckconfig.c by hand --- we hope you know at least enough to do that. +ckconfig.c may not compile the first try (in fact, the whole idea is for it +to fail if anything is going to). If you get compile errors, fix them by +editing ckconfig.c according to the directions given in ckconfig.c. Once +you get it to run, it will write a suitable jconfig.h file, and will also +print out some advice about which makefile to use. + +You may also want to look at the canned jconfig files, if there is one for a +system similar to yours. + +Second, select a makefile and copy it to Makefile (or whatever your system +uses as the standard makefile name). The most generic makefiles we provide +are + makefile.ansi: if your C compiler supports function prototypes + makefile.unix: if not. +(You have function prototypes if ckconfig.c put "#define HAVE_PROTOTYPES" +in jconfig.h.) You may want to start from one of the other makefiles if +there is one for a system similar to yours. + +Look over the selected Makefile and adjust options as needed. In particular +you may want to change the CC and CFLAGS definitions. For instance, if you +are using GCC, set CC=gcc. If you had to use any compiler switches to get +ckconfig.c to work, make sure the same switches are in CFLAGS. + +If you are on a system that doesn't use makefiles, you'll need to set up +project files (or whatever you do use) to compile all the source files and +link them into executable files cjpeg, djpeg, jpegtran, rdjpgcom, and wrjpgcom. +See the file lists in any of the makefiles to find out which files go into +each program. Note that the provided makefiles all make a "library" file +libjpeg first, but you don't have to do that if you don't want to; the file +lists identify which source files are actually needed for compression, +decompression, or both. As a last resort, you can make a batch script that +just compiles everything and links it all together; makefile.vms is an example +of this (it's for VMS systems that have no make-like utility). + +Here are comments about some specific configuration decisions you'll +need to make: + +Command line style +------------------ + +These programs can use a Unix-like command line style which supports +redirection and piping, like this: + cjpeg inputfile >outputfile + cjpeg <inputfile >outputfile + source program | cjpeg >outputfile +The simpler "two file" command line style is just + cjpeg inputfile outputfile +You may prefer the two-file style, particularly if you don't have pipes. + +You MUST use two-file style on any system that doesn't cope well with binary +data fed through stdin/stdout; this is true for some MS-DOS compilers, for +example. If you're not on a Unix system, it's safest to assume you need +two-file style. (But if your compiler provides either the Posix-standard +fdopen() library routine or a Microsoft-compatible setmode() routine, you +can safely use the Unix command line style, by defining USE_FDOPEN or +USE_SETMODE respectively.) + +To use the two-file style, make jconfig.h say "#define TWO_FILE_COMMANDLINE". + +Selecting a memory manager +-------------------------- + +The IJG code is capable of working on images that are too big to fit in main +memory; data is swapped out to temporary files as necessary. However, the +code to do this is rather system-dependent. We provide five different +memory managers: + +* jmemansi.c This version uses the ANSI-standard library routine tmpfile(), + which not all non-ANSI systems have. On some systems + tmpfile() may put the temporary file in a non-optimal + location; if you don't like what it does, use jmemname.c. + +* jmemname.c This version creates named temporary files. For anything + except a Unix machine, you'll need to configure the + select_file_name() routine appropriately; see the comments + near the head of jmemname.c. If you use this version, define + NEED_SIGNAL_CATCHER in jconfig.h to make sure the temp files + are removed if the program is aborted. + +* jmemnobs.c (That stands for No Backing Store :-).) This will compile on + almost any system, but it assumes you have enough main memory + or virtual memory to hold the biggest images you work with. + +* jmemdos.c This should be used with most 16-bit MS-DOS compilers. + See the system-specific notes about MS-DOS for more info. + IMPORTANT: if you use this, define USE_MSDOS_MEMMGR in + jconfig.h, and include the assembly file jmemdosa.asm in the + programs. The supplied makefiles and jconfig files for + 16-bit MS-DOS compilers already do both. + +* jmemmac.c Custom version for Apple Macintosh; see the system-specific + notes for Macintosh for more info. + +To use a particular memory manager, change the SYSDEPMEM variable in your +makefile to equal the corresponding object file name (for example, jmemansi.o +or jmemansi.obj for jmemansi.c). + +If you have plenty of (real or virtual) main memory, just use jmemnobs.c. +"Plenty" means about ten bytes for every pixel in the largest images +you plan to process, so a lot of systems don't meet this criterion. +If yours doesn't, try jmemansi.c first. If that doesn't compile, you'll have +to use jmemname.c; be sure to adjust select_file_name() for local conditions. +You may also need to change unlink() to remove() in close_backing_store(). + +Except with jmemnobs.c or jmemmac.c, you need to adjust the DEFAULT_MAX_MEM +setting to a reasonable value for your system (either by adding a #define for +DEFAULT_MAX_MEM to jconfig.h, or by adding a -D switch to the Makefile). +This value limits the amount of data space the program will attempt to +allocate. Code and static data space isn't counted, so the actual memory +needs for cjpeg or djpeg are typically 100 to 150Kb more than the max-memory +setting. Larger max-memory settings reduce the amount of I/O needed to +process a large image, but too large a value can result in "insufficient +memory" failures. On most Unix machines (and other systems with virtual +memory), just set DEFAULT_MAX_MEM to several million and forget it. At the +other end of the spectrum, for MS-DOS machines you probably can't go much +above 300K to 400K. (On MS-DOS the value refers to conventional memory only. +Extended/expanded memory is handled separately by jmemdos.c.) + + +BUILDING THE SOFTWARE +===================== + +Now you should be able to compile the software. Just say "make" (or +whatever's necessary to start the compilation). Have a cup of coffee. + +Here are some things that could go wrong: + +If your compiler complains about undefined structures, you should be able to +shut it up by putting "#define INCOMPLETE_TYPES_BROKEN" in jconfig.h. + +If you have trouble with missing system include files or inclusion of the +wrong ones, read jinclude.h. This shouldn't happen if you used configure +or ckconfig.c to set up jconfig.h. + +There are a fair number of routines that do not use all of their parameters; +some compilers will issue warnings about this, which you can ignore. There +are also a few configuration checks that may give "unreachable code" warnings. +Any other warning deserves investigation. + +If you don't have a getenv() library routine, define NO_GETENV. + +Also see the system-specific hints, below. + + +TESTING THE SOFTWARE +==================== + +As a quick test of functionality we've included a small sample image in +several forms: + testorig.jpg Starting point for the djpeg tests. + testimg.ppm The output of djpeg testorig.jpg + testimg.bmp The output of djpeg -bmp -colors 256 testorig.jpg + testimg.jpg The output of cjpeg testimg.ppm + testprog.jpg Progressive-mode equivalent of testorig.jpg. + testimgp.jpg The output of cjpeg -progressive -optimize testimg.ppm +(The first- and second-generation .jpg files aren't identical since JPEG is +lossy.) If you can generate duplicates of the testimg* files then you +probably have working programs. + +With most of the makefiles, "make test" will perform the necessary +comparisons. + +If you're using a makefile that doesn't provide the test option, run djpeg +and cjpeg by hand and compare the output files to testimg* with whatever +binary file comparison tool you have. The files should be bit-for-bit +identical. + +If the programs complain "MAX_ALLOC_CHUNK is wrong, please fix", then you +need to reduce MAX_ALLOC_CHUNK to a value that fits in type size_t. +Try adding "#define MAX_ALLOC_CHUNK 65520L" to jconfig.h. A less likely +configuration error is "ALIGN_TYPE is wrong, please fix": defining ALIGN_TYPE +as long should take care of that one. + +If the cjpeg test run fails with "Missing Huffman code table entry", it's a +good bet that you needed to define RIGHT_SHIFT_IS_UNSIGNED. Go back to the +configuration step and run ckconfig.c. (This is a good plan for any other +test failure, too.) + +If you are using Unix (one-file) command line style on a non-Unix system, +it's a good idea to check that binary I/O through stdin/stdout actually +works. You should get the same results from "djpeg <testorig.jpg >out.ppm" +as from "djpeg -outfile out.ppm testorig.jpg". Note that the makefiles all +use the latter style and therefore do not exercise stdin/stdout! If this +check fails, try recompiling with USE_SETMODE or USE_FDOPEN defined. +If it still doesn't work, better use two-file style. + +If you chose a memory manager other than jmemnobs.c, you should test that +temporary-file usage works. Try "djpeg -bmp -colors 256 -max 0 testorig.jpg" +and make sure its output matches testimg.bmp. If you have any really large +images handy, try compressing them with -optimize and/or decompressing with +-colors 256 to make sure your DEFAULT_MAX_MEM setting is not too large. + +NOTE: this is far from an exhaustive test of the JPEG software; some modules, +such as 1-pass color quantization, are not exercised at all. It's just a +quick test to give you some confidence that you haven't missed something +major. + + +INSTALLING THE SOFTWARE +======================= + +Once you're done with the above steps, you can install the software by +copying the executable files (cjpeg, djpeg, jpegtran, rdjpgcom, and wrjpgcom) +to wherever you normally install programs. On Unix systems, you'll also want +to put the man pages (cjpeg.1, djpeg.1, jpegtran.1, rdjpgcom.1, wrjpgcom.1) +in the man-page directory. The pre-fab makefiles don't support this step +since there's such a wide variety of installation procedures on different +systems. + +If you generated a Makefile with the "configure" script, you can just say + make install +to install the programs and their man pages into the standard places. +(You'll probably need to be root to do this.) We recommend first saying + make -n install +to see where configure thought the files should go. You may need to edit +the Makefile, particularly if your system's conventions for man page +filenames don't match what configure expects. + +If you want to install the IJG library itself, for use in compiling other +programs besides ours, then you need to put the four include files + jpeglib.h jerror.h jconfig.h jmorecfg.h +into your include-file directory, and put the library file libjpeg.a +(extension may vary depending on system) wherever library files go. +If you generated a Makefile with "configure", it will do what it thinks +is the right thing if you say + make install-lib + + +OPTIONAL STUFF +============== + +Progress monitor: + +If you like, you can #define PROGRESS_REPORT (in jconfig.h) to enable display +of percent-done progress reports. The routine provided in cdjpeg.c merely +prints percentages to stderr, but you can customize it to do something +fancier. + +Utah RLE file format support: + +We distribute the software with support for RLE image files (Utah Raster +Toolkit format) disabled, because the RLE support won't compile without the +Utah library. If you have URT version 3.1 or later, you can enable RLE +support as follows: + 1. #define RLE_SUPPORTED in jconfig.h. + 2. Add a -I option to CFLAGS in the Makefile for the directory + containing the URT .h files (typically the "include" + subdirectory of the URT distribution). + 3. Add -L... -lrle to LDLIBS in the Makefile, where ... specifies + the directory containing the URT "librle.a" file (typically the + "lib" subdirectory of the URT distribution). + +Support for 12-bit-deep pixel data: + +The JPEG standard allows either 8-bit or 12-bit data precision. (For color, +this means 8 or 12 bits per channel, of course.) If you need to work with +deeper than 8-bit data, you can compile the IJG code for 12-bit operation. +To do so: + 1. In jmorecfg.h, define BITS_IN_JSAMPLE as 12 rather than 8. + 2. In jconfig.h, undefine BMP_SUPPORTED, RLE_SUPPORTED, and TARGA_SUPPORTED, + because the code for those formats doesn't handle 12-bit data and won't + even compile. (The PPM code does work, as explained below. The GIF + code works too; it scales 8-bit GIF data to and from 12-bit depth + automatically.) + 3. Compile. Don't expect "make test" to pass, since the supplied test + files are for 8-bit data. + +Currently, 12-bit support does not work on 16-bit-int machines. + +Note that a 12-bit version will not read 8-bit JPEG files, nor vice versa; +so you'll want to keep around a regular 8-bit compilation as well. +(Run-time selection of data depth, to allow a single copy that does both, +is possible but would probably slow things down considerably; it's very low +on our to-do list.) + +The PPM reader (rdppm.c) can read 12-bit data from either text-format or +binary-format PPM and PGM files. Binary-format PPM/PGM files which have a +maxval greater than 255 are assumed to use 2 bytes per sample, LSB first +(little-endian order). As of early 1995, 2-byte binary format is not +officially supported by the PBMPLUS library, but it is expected that a +future release of PBMPLUS will support it. Note that the PPM reader will +read files of any maxval regardless of the BITS_IN_JSAMPLE setting; incoming +data is automatically rescaled to either maxval=255 or maxval=4095 as +appropriate for the cjpeg bit depth. + +The PPM writer (wrppm.c) will normally write 2-byte binary PPM or PGM +format, maxval 4095, when compiled with BITS_IN_JSAMPLE=12. Since this +format is not yet widely supported, you can disable it by compiling wrppm.c +with PPM_NORAWWORD defined; then the data is scaled down to 8 bits to make a +standard 1-byte/sample PPM or PGM file. (Yes, this means still another copy +of djpeg to keep around. But hopefully you won't need it for very long. +Poskanzer's supposed to get that new PBMPLUS release out Real Soon Now.) + +Of course, if you are working with 12-bit data, you probably have it stored +in some other, nonstandard format. In that case you'll probably want to +write your own I/O modules to read and write your format. + +Note that a 12-bit version of cjpeg always runs in "-optimize" mode, in +order to generate valid Huffman tables. This is necessary because our +default Huffman tables only cover 8-bit data. + +Removing code: + +If you need to make a smaller version of the JPEG software, some optional +functions can be removed at compile time. See the xxx_SUPPORTED #defines in +jconfig.h and jmorecfg.h. If at all possible, we recommend that you leave in +decoder support for all valid JPEG files, to ensure that you can read anyone's +output. Taking out support for image file formats that you don't use is the +most painless way to make the programs smaller. Another possibility is to +remove some of the DCT methods: in particular, the "IFAST" method may not be +enough faster than the others to be worth keeping on your machine. (If you +do remove ISLOW or IFAST, be sure to redefine JDCT_DEFAULT or JDCT_FASTEST +to a supported method, by adding a #define in jconfig.h.) + + +OPTIMIZATION +============ + +Unless you own a Cray, you'll probably be interested in making the JPEG +software go as fast as possible. This section covers some machine-dependent +optimizations you may want to try. We suggest that before trying any of +this, you first get the basic installation to pass the self-test step. +Repeat the self-test after any optimization to make sure that you haven't +broken anything. + +The integer DCT routines perform a lot of multiplications. These +multiplications must yield 32-bit results, but none of their input values +are more than 16 bits wide. On many machines, notably the 680x0 and 80x86 +CPUs, a 16x16=>32 bit multiply instruction is faster than a full 32x32=>32 +bit multiply. Unfortunately there is no portable way to specify such a +multiplication in C, but some compilers can generate one when you use the +right combination of casts. See the MULTIPLYxxx macro definitions in +jdct.h. If your compiler makes "int" be 32 bits and "short" be 16 bits, +defining SHORTxSHORT_32 is fairly likely to work. When experimenting with +alternate definitions, be sure to test not only whether the code still works +(use the self-test), but also whether it is actually faster --- on some +compilers, alternate definitions may compute the right answer, yet be slower +than the default. Timing cjpeg on a large PGM (grayscale) input file is the +best way to check this, as the DCT will be the largest fraction of the runtime +in that mode. (Note: some of the distributed compiler-specific jconfig files +already contain #define switches to select appropriate MULTIPLYxxx +definitions.) + +If your machine has sufficiently fast floating point hardware, you may find +that the float DCT method is faster than the integer DCT methods, even +after tweaking the integer multiply macros. In that case you may want to +make the float DCT be the default method. (The only objection to this is +that float DCT results may vary slightly across machines.) To do that, add +"#define JDCT_DEFAULT JDCT_FLOAT" to jconfig.h. Even if you don't change +the default, you should redefine JDCT_FASTEST, which is the method selected +by djpeg's -fast switch. Don't forget to update the documentation files +(usage.doc and/or cjpeg.1, djpeg.1) to agree with what you've done. + +If access to "short" arrays is slow on your machine, it may be a win to +define type JCOEF as int rather than short. This will cost a good deal of +memory though, particularly in some multi-pass modes, so don't do it unless +you have memory to burn and short is REALLY slow. + +If your compiler can compile function calls in-line, make sure the INLINE +macro in jmorecfg.h is defined as the keyword that marks a function +inline-able. Some compilers have a switch that tells the compiler to inline +any function it thinks is profitable (e.g., -finline-functions for gcc). +Enabling such a switch is likely to make the compiled code bigger but faster. + +In general, it's worth trying the maximum optimization level of your compiler, +and experimenting with any optional optimizations such as loop unrolling. +(Unfortunately, far too many compilers have optimizer bugs ... be prepared to +back off if the code fails self-test.) If you do any experimentation along +these lines, please report the optimal settings to jpeg-info@uunet.uu.net so +we can mention them in future releases. Be sure to specify your machine and +compiler version. + + +HINTS FOR SPECIFIC SYSTEMS +========================== + +We welcome reports on changes needed for systems not mentioned here. Submit +'em to jpeg-info@uunet.uu.net. Also, if configure or ckconfig.c is wrong +about how to configure the JPEG software for your system, please let us know. + + +Acorn RISC OS: + +(Thanks to Simon Middleton for these hints on compiling with Desktop C.) +After renaming the files according to Acorn conventions, take a copy of +makefile.ansi, change all occurrences of 'libjpeg.a' to 'libjpeg.o' and +change these definitions as indicated: + +CFLAGS= -throwback -IC: -Wn +LDLIBS=C:o.Stubs +SYSDEPMEM=jmemansi.o +LN=Link +AR=LibFile -c -o + +Also add a new line '.c.o:; $(cc) $< $(cflags) -c -o $@'. Remove the +lines '$(RM) libjpeg.o' and '$(AR2) libjpeg.o' and the 'jconfig.h' +dependency section. + +Copy jconfig.doc to jconfig.h. Edit jconfig.h to define TWO_FILE_COMMANDLINE +and CHAR_IS_UNSIGNED. + +Run the makefile using !AMU not !Make. If you want to use the 'clean' and +'test' makefile entries then you will have to fiddle with the syntax a bit +and rename the test files. + + +Amiga: + +SAS C 6.50 reportedly is too buggy to compile the IJG code properly. +A patch to update to 6.51 is available from SAS or AmiNet FTP sites. + +The supplied config files are set up to use jmemname.c as the memory +manager, with temporary files being created on the device named by +"JPEGTMP:". + + +Atari ST/STE/TT: + +Copy the project files makcjpeg.st, makdjpeg.st, maktjpeg.st, and makljpeg.st +to cjpeg.prj, djpeg.prj, jpegtran.prj, and libjpeg.prj respectively. The +project files should work as-is with Pure C. For Turbo C, change library +filenames "pc..." to "tc..." in each project file. Note that libjpeg.prj +selects jmemansi.c as the recommended memory manager. You'll probably want to +adjust the DEFAULT_MAX_MEM setting --- you want it to be a couple hundred K +less than your normal free memory. Put "#define DEFAULT_MAX_MEM nnnn" into +jconfig.h to do this. + +To use the 68881/68882 coprocessor for the floating point DCT, add the +compiler option "-8" to the project files and replace pcfltlib.lib with +pc881lib.lib in cjpeg.prj and djpeg.prj. Or if you don't have a +coprocessor, you may prefer to remove the float DCT code by undefining +DCT_FLOAT_SUPPORTED in jmorecfg.h (since without a coprocessor, the float +code will be too slow to be useful). In that case, you can delete +pcfltlib.lib from the project files. + +Note that you must make libjpeg.lib before making cjpeg.ttp, djpeg.ttp, +or jpegtran.ttp. You'll have to perform the self-test by hand. + +We haven't bothered to include project files for rdjpgcom and wrjpgcom. +Those source files should just be compiled by themselves; they don't +depend on the JPEG library. + +There is a bug in some older versions of the Turbo C library which causes the +space used by temporary files created with "tmpfile()" not to be freed after +an abnormal program exit. If you check your disk afterwards, you will find +cluster chains that are allocated but not used by a file. This should not +happen in cjpeg/djpeg/jpegtran, since we enable a signal catcher to explicitly +close temp files before exiting. But if you use the JPEG library with your +own code, be sure to supply a signal catcher, or else use a different +system-dependent memory manager. + + +Cray: + +Should you be so fortunate as to be running JPEG on a Cray YMP, there is a +compiler bug in old versions of Cray's Standard C (prior to 3.1). If you +still have an old compiler, you'll need to insert a line reading +"#pragma novector" just before the loop + for (i = 1; i <= (int) htbl->bits[l]; i++) + huffsize[p++] = (char) l; +in fix_huff_tbl (in V5beta1, line 204 of jchuff.c and line 176 of jdhuff.c). +[This bug may or may not still occur with the current IJG code, but it's +probably a dead issue anyway...] + + +HP-UX: + +If you have HP-UX 7.05 or later with the "software development" C compiler, +you should run the compiler in ANSI mode. If using the configure script, +say + ./configure CC='cc -Aa' +(or -Ae if you prefer). If configuring by hand, use makefile.ansi and add +"-Aa" to the CFLAGS line in the makefile. + +If you have a pre-7.05 system, or if you are using the non-ANSI C compiler +delivered with a minimum HP-UX system, then you must use makefile.unix +(and do NOT add -Aa); or just run configure without the CC option. + +On HP 9000 series 800 machines, the HP C compiler is buggy in revisions prior +to A.08.07. If you get complaints about "not a typedef name", you'll have to +use makefile.unix, or run configure without the CC option. + + +Macintosh, generic comments: + +The supplied user-interface files (cjpeg.c, djpeg.c, etc) are set up to +provide a Unix-style command line interface. You can use this interface on +the Mac by means of the ccommand() library routine provided by Metrowerks +CodeWarrior or Think C. This is only appropriate for testing the library, +however; to make a user-friendly equivalent of cjpeg/djpeg you'd really want +to develop a Mac-style user interface. There isn't a complete example +available at the moment, but there are some helpful starting points: +1. Sam Bushell's free "To JPEG" applet provides drag-and-drop conversion to +JPEG under System 7 and later. This only illustrates how to use the +compression half of the library, but it does a very nice job of that part. +The CodeWarrior source code is available from http://www.pobox.com/~jsam. +2. Jim Brunner prepared a Mac-style user interface for both compression and +decompression. Unfortunately, it hasn't been updated since IJG v4, and +the library's API has changed considerably since then. Still it may be of +some help, particularly as a guide to compiling the IJG code under Think C. +Jim's code is available from the Info-Mac archives, at sumex-aim.stanford.edu +or mirrors thereof; see file /info-mac/dev/src/jpeg-convert-c.hqx. + +jmemmac.c is the recommended memory manager back end for Macintosh. It uses +NewPtr/DisposePtr instead of malloc/free, and has a Mac-specific +implementation of jpeg_mem_available(). It also creates temporary files that +follow Mac conventions. (That part of the code relies on System-7-or-later OS +functions. See the comments in jmemmac.c if you need to run it on System 6.) +NOTE that USE_MAC_MEMMGR must be defined in jconfig.h to use jmemmac.c. + +You can also use jmemnobs.c, if you don't care about handling images larger +than available memory. If you use any memory manager back end other than +jmemmac.c, we recommend replacing "malloc" and "free" by "NewPtr" and +"DisposePtr", because Mac C libraries often have peculiar implementations of +malloc/free. (For instance, free() may not return the freed space to the +Mac Memory Manager. This is undesirable for the IJG code because jmemmgr.c +already clumps space requests.) + + +Macintosh, Metrowerks CodeWarrior: + +The Unix-command-line-style interface can be used by defining USE_CCOMMAND. +You'll also need to define TWO_FILE_COMMANDLINE to avoid stdin/stdout. +This means that when using the cjpeg/djpeg programs, you'll have to type the +input and output file names in the "Arguments" text-edit box, rather than +using the file radio buttons. (Perhaps USE_FDOPEN or USE_SETMODE would +eliminate the problem, but I haven't heard from anyone who's tried it.) + +On 680x0 Macs, Metrowerks defines type "double" as a 10-byte IEEE extended +float. jmemmgr.c won't like this: it wants sizeof(ALIGN_TYPE) to be a power +of 2. Add "#define ALIGN_TYPE long" to jconfig.h to eliminate the complaint. + +The supplied configuration file jconfig.mac can be used for your jconfig.h; +it includes all the recommended symbol definitions. If you have AppleScript +installed, you can run the supplied script makeproj.mac to create CodeWarrior +project files for the library and the testbed applications, then build the +library and applications. (Thanks to Dan Sears and Don Agro for this nifty +hack, which saves us from trying to maintain CodeWarrior project files as part +of the IJG distribution...) + + +Macintosh, Think C: + +The documentation in Jim Brunner's "JPEG Convert" source code (see above) +includes detailed build instructions for Think C; it's probably somewhat +out of date for the current release, but may be helpful. + +If you want to build the minimal command line version, proceed as follows. +You'll have to prepare project files for the programs; we don't include any +in the distribution since they are not text files. Use the file lists in +any of the supplied makefiles as a guide. Also add the ANSI and Unix C +libraries in a separate segment. You may need to divide the JPEG files into +more than one segment; we recommend dividing compression and decompression +modules. Define USE_CCOMMAND in jconfig.h so that the ccommand() routine is +called. You must also define TWO_FILE_COMMANDLINE because stdin/stdout +don't handle binary data correctly. + +On 680x0 Macs, Think C defines type "double" as a 12-byte IEEE extended float. +jmemmgr.c won't like this: it wants sizeof(ALIGN_TYPE) to be a power of 2. +Add "#define ALIGN_TYPE long" to jconfig.h to eliminate the complaint. + +jconfig.mac should work as a jconfig.h configuration file for Think C, +but the makeproj.mac AppleScript script is specific to CodeWarrior. Sorry. + + +MIPS R3000: + +MIPS's cc version 1.31 has a rather nasty optimization bug. Don't use -O +if you have that compiler version. (Use "cc -V" to check the version.) +Note that the R3000 chip is found in workstations from DEC and others. + + +MS-DOS, generic comments for 16-bit compilers: + +The IJG code is designed to work well in 80x86 "small" or "medium" memory +models (i.e., data pointers are 16 bits unless explicitly declared "far"; +code pointers can be either size). You may be able to use small model to +compile cjpeg or djpeg by itself, but you will probably have to use medium +model for any larger application. This won't make much difference in +performance. You *will* take a noticeable performance hit if you use a +large-data memory model, and you should avoid "huge" model if at all +possible. Be sure that NEED_FAR_POINTERS is defined in jconfig.h if you use +a small-data memory model; be sure it is NOT defined if you use a large-data +model. (The supplied makefiles and jconfig files for Borland and Microsoft C +compile in medium model and define NEED_FAR_POINTERS.) + +The DOS-specific memory manager, jmemdos.c, should be used if possible. +It needs some assembly-code routines which are in jmemdosa.asm; make sure +your makefile assembles that file and includes it in the library. If you +don't have a suitable assembler, you can get pre-assembled object files for +jmemdosa by FTP from ftp.uu.net:/graphics/jpeg/jdosaobj.zip. (DOS-oriented +distributions of the IJG source code often include these object files.) + +When using jmemdos.c, jconfig.h must define USE_MSDOS_MEMMGR and must set +MAX_ALLOC_CHUNK to less than 64K (65520L is a typical value). If your +C library's far-heap malloc() can't allocate blocks that large, reduce +MAX_ALLOC_CHUNK to whatever it can handle. + +If you can't use jmemdos.c for some reason --- for example, because you +don't have an assembler to assemble jmemdosa.asm --- you'll have to fall +back to jmemansi.c or jmemname.c. You'll probably still need to set +MAX_ALLOC_CHUNK in jconfig.h, because most DOS C libraries won't malloc() +more than 64K at a time. IMPORTANT: if you use jmemansi.c or jmemname.c, +you will have to compile in a large-data memory model in order to get the +right stdio library. Too bad. + +wrjpgcom needs to be compiled in large model, because it malloc()s a 64KB +work area to hold the comment text. If your C library's malloc can't +handle that, reduce MAX_COM_LENGTH as necessary in wrjpgcom.c. + +Most MS-DOS compilers treat stdin/stdout as text files, so you must use +two-file command line style. But if your compiler has either fdopen() or +setmode(), you can use one-file style if you like. To do this, define +USE_SETMODE or USE_FDOPEN so that stdin/stdout will be set to binary mode. +(USE_SETMODE seems to work with more DOS compilers than USE_FDOPEN.) You +should test that I/O through stdin/stdout produces the same results as I/O +to explicitly named files... the "make test" procedures in the supplied +makefiles do NOT use stdin/stdout. + + +MS-DOS, generic comments for 32-bit compilers: + +None of the above comments about memory models apply if you are using a +32-bit flat-memory-space environment, such as DJGPP or Watcom C. (And you +should use one if you have it, as performance will be much better than +8086-compatible code!) For flat-memory-space compilers, do NOT define +NEED_FAR_POINTERS, and do NOT use jmemdos.c. Use jmemnobs.c if the +environment supplies adequate virtual memory, otherwise use jmemansi.c or +jmemname.c. + +You'll still need to be careful about binary I/O through stdin/stdout. +See the last paragraph of the previous section. + + +MS-DOS, Borland C: + +Be sure to convert all the source files to DOS text format (CR/LF newlines). +Although Borland C will often work OK with unmodified Unix (LF newlines) +source files, sometimes it will give bogus compile errors. +"Illegal character '#'" is the most common such error. (This is true with +Borland C 3.1, but perhaps is fixed in newer releases.) + +If you want one-file command line style, just undefine TWO_FILE_COMMANDLINE. +jconfig.bcc already includes #define USE_SETMODE to make this work. +(fdopen does not work correctly.) + + +MS-DOS, Microsoft C: + +makefile.mc6 works with Microsoft C, DOS Visual C++, etc. It should only +be used if you want to build a 16-bit (small or medium memory model) program. + +If you want one-file command line style, just undefine TWO_FILE_COMMANDLINE. +jconfig.mc6 already includes #define USE_SETMODE to make this work. +(fdopen does not work correctly.) + +Note that this makefile assumes that the working copy of itself is called +"makefile". If you want to call it something else, say "makefile.mak", +be sure to adjust the dependency line that reads "$(RFILE) : makefile". +Otherwise the make will fail because it doesn't know how to create "makefile". +Worse, some releases of Microsoft's make utilities give an incorrect error +message in this situation. + +Old versions of MS C fail with an "out of macro expansion space" error +because they can't cope with the macro TRACEMS8 (defined in jerror.h). +If this happens to you, the easiest solution is to change TRACEMS8 to +expand to nothing. You'll lose the ability to dump out JPEG coefficient +tables with djpeg -debug -debug, but at least you can compile. + +Original MS C 6.0 is very buggy; it compiles incorrect code unless you turn +off optimization entirely (remove -O from CFLAGS). 6.00A is better, but it +still generates bad code if you enable loop optimizations (-Ol or -Ox). + +MS C 8.0 crashes when compiling jquant1.c with optimization switch /Oo ... +which is on by default. To work around this bug, compile that one file +with /Oo-. + + +Microsoft Windows (all versions), generic comments: + +Some Windows system include files define typedef boolean as "unsigned char". +The IJG code also defines typedef boolean, but we make it "int" by default. +This doesn't affect the IJG programs because we don't import those Windows +include files. But if you use the JPEG library in your own program, and some +of your program's files import one definition of boolean while some import the +other, you can get all sorts of mysterious problems. A good preventive step +is to make the IJG library use "unsigned char" for boolean. To do that, +add something like this to your jconfig.h file: + /* Define "boolean" as unsigned char, not int, per Windows custom */ + #ifndef __RPCNDR_H__ /* don't conflict if rpcndr.h already read */ + typedef unsigned char boolean; + #endif + #define HAVE_BOOLEAN /* prevent jmorecfg.h from redefining it */ +(This is already in jconfig.vc, by the way.) + +windef.h contains the declarations + #define far + #define FAR far +Since jmorecfg.h tries to define FAR as empty, you may get a compiler +warning if you include both jpeglib.h and windef.h (which windows.h +includes). To suppress the warning, you can put "#ifndef FAR"/"#endif" +around the line "#define FAR" in jmorecfg.h. + +When using the library in a Windows application, you will almost certainly +want to modify or replace the error handler module jerror.c, since our +default error handler does a couple of inappropriate things: + 1. it tries to write error and warning messages on stderr; + 2. in event of a fatal error, it exits by calling exit(). + +A simple stopgap solution for problem 1 is to replace the line + fprintf(stderr, "%s\n", buffer); +(in output_message in jerror.c) with + MessageBox(GetActiveWindow(),buffer,"JPEG Error",MB_OK|MB_ICONERROR); +It's highly recommended that you at least do that much, since otherwise +error messages will disappear into nowhere. (Beginning with IJG v6b, this +code is already present in jerror.c; just define USE_WINDOWS_MESSAGEBOX in +jconfig.h to enable it.) + +The proper solution for problem 2 is to return control to your calling +application after a library error. This can be done with the setjmp/longjmp +technique discussed in libjpeg.doc and illustrated in example.c. (NOTE: +some older Windows C compilers provide versions of setjmp/longjmp that +don't actually work under Windows. You may need to use the Windows system +functions Catch and Throw instead.) + +The recommended memory manager under Windows is jmemnobs.c; in other words, +let Windows do any virtual memory management needed. You should NOT use +jmemdos.c nor jmemdosa.asm under Windows. + +For Windows 3.1, we recommend compiling in medium or large memory model; +for newer Windows versions, use a 32-bit flat memory model. (See the MS-DOS +sections above for more info about memory models.) In the 16-bit memory +models only, you'll need to put + #define MAX_ALLOC_CHUNK 65520L /* Maximum request to malloc() */ +into jconfig.h to limit allocation chunks to 64Kb. (Without that, you'd +have to use huge memory model, which slows things down unnecessarily.) +jmemnobs.c works without modification in large or flat memory models, but to +use medium model, you need to modify its jpeg_get_large and jpeg_free_large +routines to allocate far memory. In any case, you might like to replace +its calls to malloc and free with direct calls on Windows memory allocation +functions. + +You may also want to modify jdatasrc.c and jdatadst.c to use Windows file +operations rather than fread/fwrite. This is only necessary if your C +compiler doesn't provide a competent implementation of C stdio functions. + +You might want to tweak the RGB_xxx macros in jmorecfg.h so that the library +will accept or deliver color pixels in BGR sample order, not RGB; BGR order +is usually more convenient under Windows. Note that this change will break +the sample applications cjpeg/djpeg, but the library itself works fine. + + +Many people want to convert the IJG library into a DLL. This is reasonably +straightforward, but watch out for the following: + + 1. Don't try to compile as a DLL in small or medium memory model; use +large model, or even better, 32-bit flat model. Many places in the IJG code +assume the address of a local variable is an ordinary (not FAR) pointer; +that isn't true in a medium-model DLL. + + 2. Microsoft C cannot pass file pointers between applications and DLLs. +(See Microsoft Knowledge Base, PSS ID Number Q50336.) So jdatasrc.c and +jdatadst.c don't work if you open a file in your application and then pass +the pointer to the DLL. One workaround is to make jdatasrc.c/jdatadst.c +part of your main application rather than part of the DLL. + + 3. You'll probably need to modify the macros GLOBAL() and EXTERN() to +attach suitable linkage keywords to the exported routine names. Similarly, +you'll want to modify METHODDEF() and JMETHOD() to ensure function pointers +are declared in a way that lets application routines be called back through +the function pointers. These macros are in jmorecfg.h. Typical definitions +for a 16-bit DLL are: + #define GLOBAL(type) type _far _pascal _loadds _export + #define EXTERN(type) extern type _far _pascal _loadds + #define METHODDEF(type) static type _far _pascal + #define JMETHOD(type,methodname,arglist) \ + type (_far _pascal *methodname) arglist +For a 32-bit DLL you may want something like + #define GLOBAL(type) __declspec(dllexport) type + #define EXTERN(type) extern __declspec(dllexport) type +Although not all the GLOBAL routines are actually intended to be called by +the application, the performance cost of making them all DLL entry points is +negligible. + +The unmodified IJG library presents a very C-specific application interface, +so the resulting DLL is only usable from C or C++ applications. There has +been some talk of writing wrapper code that would present a simpler interface +usable from other languages, such as Visual Basic. This is on our to-do list +but hasn't been very high priority --- any volunteers out there? + + +Microsoft Windows, Borland C: + +The provided jconfig.bcc should work OK in a 32-bit Windows environment, +but you'll need to tweak it in a 16-bit environment (you'd need to define +NEED_FAR_POINTERS and MAX_ALLOC_CHUNK). Beware that makefile.bcc will need +alteration if you want to use it for Windows --- in particular, you should +use jmemnobs.c not jmemdos.c under Windows. + +Borland C++ 4.5 fails with an internal compiler error when trying to compile +jdmerge.c in 32-bit mode. If enough people complain, perhaps Borland will fix +it. In the meantime, the simplest known workaround is to add a redundant +definition of the variable range_limit in h2v1_merged_upsample(), at the head +of the block that handles odd image width (about line 268 in v6 jdmerge.c): + /* If image width is odd, do the last output column separately */ + if (cinfo->output_width & 1) { + register JSAMPLE * range_limit = cinfo->sample_range_limit; /* ADD THIS */ + cb = GETJSAMPLE(*inptr1); +Pretty bizarre, especially since the very similar routine h2v2_merged_upsample +doesn't trigger the bug. +Recent reports suggest that this bug does not occur with "bcc32a" (the +Pentium-optimized version of the compiler). + +Another report from a user of Borland C 4.5 was that incorrect code (leading +to a color shift in processed images) was produced if any of the following +optimization switch combinations were used: + -Ot -Og + -Ot -Op + -Ot -Om +So try backing off on optimization if you see such a problem. (Are there +several different releases all numbered "4.5"??) + + +Microsoft Windows, Microsoft Visual C++: + +jconfig.vc should work OK with any Microsoft compiler for a 32-bit memory +model. makefile.vc is intended for command-line use. (If you are using +the Developer Studio environment, you may prefer the DevStudio project +files; see below.) + +Some users feel that it's easier to call the library from C++ code if you +force VC++ to treat the library as C++ code, which you can do by renaming +all the *.c files to *.cpp (and adjusting the makefile to match). This +avoids the need to put extern "C" { ... } around #include "jpeglib.h" in +your C++ application. + + +Microsoft Windows, Microsoft Developer Studio: + +We include makefiles that should work as project files in DevStudio 4.2 or +later. There is a library makefile that builds the IJG library as a static +Win32 library, and an application makefile that builds the sample applications +as Win32 console applications. (Even if you only want the library, we +recommend building the applications so that you can run the self-test.) + +To use: +1. Copy jconfig.vc to jconfig.h, makelib.ds to jpeg.mak, and + makeapps.ds to apps.mak. (Note that the renaming is critical!) +2. Click on the .mak files to construct project workspaces. + (If you are using DevStudio more recent than 4.2, you'll probably + get a message saying that the makefiles are being updated.) +3. Build the library project, then the applications project. +4. Move the application .exe files from `app`\Release to an + appropriate location on your path. +5. To perform the self-test, execute the command line + NMAKE /f makefile.vc test + + +OS/2, Borland C++: + +Watch out for optimization bugs in older Borland compilers; you may need +to back off the optimization switch settings. See the comments in +makefile.bcc. + + +SGI: + +On some SGI systems, you may need to set "AR2= ar -ts" in the Makefile. +If you are using configure, you can do this by saying + ./configure RANLIB='ar -ts' +This change is not needed on all SGIs. Use it only if the make fails at the +stage of linking the completed programs. + +On the MIPS R4000 architecture (Indy, etc.), the compiler option "-mips2" +reportedly speeds up the float DCT method substantially, enough to make it +faster than the default int method (but still slower than the fast int +method). If you use -mips2, you may want to alter the default DCT method to +be float. To do this, put "#define JDCT_DEFAULT JDCT_FLOAT" in jconfig.h. + + +VMS: + +On an Alpha/VMS system with MMS, be sure to use the "/Marco=Alpha=1" +qualifier with MMS when building the JPEG package. + +VAX/VMS v5.5-1 may have problems with the test step of the build procedure +reporting differences when it compares the original and test images. If the +error points to the last block of the files, it is most likely bogus and may +be safely ignored. It seems to be because the files are Stream_LF and +Backup/Compare has difficulty with the (presumably) null padded files. +This problem was not observed on VAX/VMS v6.1 or AXP/VMS v6.1. diff --git a/Utilities/ITK/Utilities/itkjpeg/jaricom.c b/Utilities/ITK/Utilities/itkjpeg/jaricom.c new file mode 100644 index 0000000000000000000000000000000000000000..fac051804883863d1d58d69368ec44713e4e80e7 --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jaricom.c @@ -0,0 +1,15 @@ +/* + * jaricom.c + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file holds place for arithmetic entropy codec tables. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + +INT32 jaritab[1]; /* dummy table */ diff --git a/Utilities/ITK/Utilities/itkjpeg/jcapimin.c b/Utilities/ITK/Utilities/itkjpeg/jcapimin.c new file mode 100644 index 0000000000000000000000000000000000000000..7bb6e7b410fba4d4eca4b26c13236ea39fad6f75 --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jcapimin.c @@ -0,0 +1,280 @@ +/* + * jcapimin.c + * + * Copyright (C) 1994-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains application interface code for the compression half + * of the JPEG library. These are the "minimum" API routines that may be + * needed in either the normal full-compression case or the transcoding-only + * case. + * + * Most of the routines intended to be called directly by an application + * are in this file or in jcapistd.c. But also see jcparam.c for + * parameter-setup helper routines, jcomapi.c for routines shared by + * compression and decompression, and jctrans.c for the transcoding case. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* + * Initialization of a JPEG compression object. + * The error manager must already be set up (in case memory manager fails). + */ + +GLOBAL(void) +jpeg_CreateCompress (j_compress_ptr cinfo, int version, size_t structsize) +{ + int i; + + /* Guard against version mismatches between library and caller. */ + cinfo->mem = NULL; /* so jpeg_destroy knows mem mgr not called */ + if (version != JPEG_LIB_VERSION) + ERREXIT2(cinfo, JERR_BAD_LIB_VERSION, JPEG_LIB_VERSION, version); + if (structsize != SIZEOF(struct jpeg_compress_struct)) + ERREXIT2(cinfo, JERR_BAD_STRUCT_SIZE, + (int) SIZEOF(struct jpeg_compress_struct), (int) structsize); + + /* For debugging purposes, we zero the whole master structure. + * But the application has already set the err pointer, and may have set + * client_data, so we have to save and restore those fields. + * Note: if application hasn't set client_data, tools like Purify may + * complain here. + */ + { + struct jpeg_error_mgr * err = cinfo->err; + void * client_data = cinfo->client_data; /* ignore Purify complaint here */ + MEMZERO(cinfo, SIZEOF(struct jpeg_compress_struct)); + cinfo->err = err; + cinfo->client_data = client_data; + } + cinfo->is_decompressor = FALSE; + + /* Initialize a memory manager instance for this object */ + jinit_memory_mgr((j_common_ptr) cinfo); + + /* Zero out pointers to permanent structures. */ + cinfo->progress = NULL; + cinfo->dest = NULL; + + cinfo->comp_info = NULL; + + for (i = 0; i < NUM_QUANT_TBLS; i++) + cinfo->quant_tbl_ptrs[i] = NULL; + + for (i = 0; i < NUM_HUFF_TBLS; i++) { + cinfo->dc_huff_tbl_ptrs[i] = NULL; + cinfo->ac_huff_tbl_ptrs[i] = NULL; + } + + cinfo->script_space = NULL; + + cinfo->input_gamma = 1.0; /* in case application forgets */ + + /* OK, I'm ready */ + cinfo->global_state = CSTATE_START; +} + + +/* + * Destruction of a JPEG compression object + */ + +GLOBAL(void) +jpeg_destroy_compress (j_compress_ptr cinfo) +{ + jpeg_destroy((j_common_ptr) cinfo); /* use common routine */ +} + + +/* + * Abort processing of a JPEG compression operation, + * but don't destroy the object itself. + */ + +GLOBAL(void) +jpeg_abort_compress (j_compress_ptr cinfo) +{ + jpeg_abort((j_common_ptr) cinfo); /* use common routine */ +} + + +/* + * Forcibly suppress or un-suppress all quantization and Huffman tables. + * Marks all currently defined tables as already written (if suppress) + * or not written (if !suppress). This will control whether they get emitted + * by a subsequent jpeg_start_compress call. + * + * This routine is exported for use by applications that want to produce + * abbreviated JPEG datastreams. It logically belongs in jcparam.c, but + * since it is called by jpeg_start_compress, we put it here --- otherwise + * jcparam.o would be linked whether the application used it or not. + */ + +GLOBAL(void) +jpeg_suppress_tables (j_compress_ptr cinfo, boolean suppress) +{ + int i; + JQUANT_TBL * qtbl; + JHUFF_TBL * htbl; + + for (i = 0; i < NUM_QUANT_TBLS; i++) { + if ((qtbl = cinfo->quant_tbl_ptrs[i]) != NULL) + qtbl->sent_table = suppress; + } + + for (i = 0; i < NUM_HUFF_TBLS; i++) { + if ((htbl = cinfo->dc_huff_tbl_ptrs[i]) != NULL) + htbl->sent_table = suppress; + if ((htbl = cinfo->ac_huff_tbl_ptrs[i]) != NULL) + htbl->sent_table = suppress; + } +} + + +/* + * Finish JPEG compression. + * + * If a multipass operating mode was selected, this may do a great deal of + * work including most of the actual output. + */ + +GLOBAL(void) +jpeg_finish_compress (j_compress_ptr cinfo) +{ + JDIMENSION iMCU_row; + + if (cinfo->global_state == CSTATE_SCANNING || + cinfo->global_state == CSTATE_RAW_OK) { + /* Terminate first pass */ + if (cinfo->next_scanline < cinfo->image_height) + ERREXIT(cinfo, JERR_TOO_LITTLE_DATA); + (*cinfo->master->finish_pass) (cinfo); + } else if (cinfo->global_state != CSTATE_WRCOEFS) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + /* Perform any remaining passes */ + while (! cinfo->master->is_last_pass) { + (*cinfo->master->prepare_for_pass) (cinfo); + for (iMCU_row = 0; iMCU_row < cinfo->total_iMCU_rows; iMCU_row++) { + if (cinfo->progress != NULL) { + cinfo->progress->pass_counter = (long) iMCU_row; + cinfo->progress->pass_limit = (long) cinfo->total_iMCU_rows; + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + } + /* We bypass the main controller and invoke coef controller directly; + * all work is being done from the coefficient buffer. + */ + if (! (*cinfo->codec->compress_data) (cinfo, (JSAMPIMAGE) NULL)) + ERREXIT(cinfo, JERR_CANT_SUSPEND); + } + (*cinfo->master->finish_pass) (cinfo); + } + /* Write EOI, do final cleanup */ + (*cinfo->marker->write_file_trailer) (cinfo); + (*cinfo->dest->term_destination) (cinfo); + /* We can use jpeg_abort to release memory and reset global_state */ + jpeg_abort((j_common_ptr) cinfo); +} + + +/* + * Write a special marker. + * This is only recommended for writing COM or APPn markers. + * Must be called after jpeg_start_compress() and before + * first call to jpeg_write_scanlines() or jpeg_write_raw_data(). + */ + +GLOBAL(void) +jpeg_write_marker (j_compress_ptr cinfo, int marker, + const JOCTET *dataptr, unsigned int datalen) +{ + JMETHOD(void, write_marker_byte, (j_compress_ptr info, int val)); + + if (cinfo->next_scanline != 0 || + (cinfo->global_state != CSTATE_SCANNING && + cinfo->global_state != CSTATE_RAW_OK && + cinfo->global_state != CSTATE_WRCOEFS)) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + (*cinfo->marker->write_marker_header) (cinfo, marker, datalen); + write_marker_byte = cinfo->marker->write_marker_byte; /* copy for speed */ + while (datalen--) { + (*write_marker_byte) (cinfo, *dataptr); + dataptr++; + } +} + +/* Same, but piecemeal. */ + +GLOBAL(void) +jpeg_write_m_header (j_compress_ptr cinfo, int marker, unsigned int datalen) +{ + if (cinfo->next_scanline != 0 || + (cinfo->global_state != CSTATE_SCANNING && + cinfo->global_state != CSTATE_RAW_OK && + cinfo->global_state != CSTATE_WRCOEFS)) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + (*cinfo->marker->write_marker_header) (cinfo, marker, datalen); +} + +GLOBAL(void) +jpeg_write_m_byte (j_compress_ptr cinfo, int val) +{ + (*cinfo->marker->write_marker_byte) (cinfo, val); +} + + +/* + * Alternate compression function: just write an abbreviated table file. + * Before calling this, all parameters and a data destination must be set up. + * + * To produce a pair of files containing abbreviated tables and abbreviated + * image data, one would proceed as follows: + * + * initialize JPEG object + * set JPEG parameters + * set destination to table file + * jpeg_write_tables(cinfo); + * set destination to image file + * jpeg_start_compress(cinfo, FALSE); + * write data... + * jpeg_finish_compress(cinfo); + * + * jpeg_write_tables has the side effect of marking all tables written + * (same as jpeg_suppress_tables(..., TRUE)). Thus a subsequent start_compress + * will not re-emit the tables unless it is passed write_all_tables=TRUE. + */ + +GLOBAL(void) +jpeg_write_tables (j_compress_ptr cinfo) +{ + if (cinfo->global_state != CSTATE_START) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + /* (Re)initialize error mgr and destination modules */ + (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo); + (*cinfo->dest->init_destination) (cinfo); + /* Initialize the marker writer ... bit of a crock to do it here. */ + jinit_marker_writer(cinfo); + /* Write them tables! */ + (*cinfo->marker->write_tables_only) (cinfo); + /* And clean up. */ + (*cinfo->dest->term_destination) (cinfo); + /* + * In library releases up through v6a, we called jpeg_abort() here to free + * any working memory allocated by the destination manager and marker + * writer. Some applications had a problem with that: they allocated space + * of their own from the library memory manager, and didn't want it to go + * away during write_tables. So now we do nothing. This will cause a + * memory leak if an app calls write_tables repeatedly without doing a full + * compression cycle or otherwise resetting the JPEG object. However, that + * seems less bad than unexpectedly freeing memory in the normal case. + * An app that prefers the old behavior can call jpeg_abort for itself after + * each call to jpeg_write_tables(). + */ +} diff --git a/Utilities/ITK/Utilities/itkjpeg/jcapistd.c b/Utilities/ITK/Utilities/itkjpeg/jcapistd.c new file mode 100644 index 0000000000000000000000000000000000000000..ee2a8496e09e24e29c02d7b192559d8894c680a9 --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jcapistd.c @@ -0,0 +1,161 @@ +/* + * jcapistd.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains application interface code for the compression half + * of the JPEG library. These are the "standard" API routines that are + * used in the normal full-compression case. They are not used by a + * transcoding-only application. Note that if an application links in + * jpeg_start_compress, it will end up linking in the entire compressor. + * We thus must separate this file from jcapimin.c to avoid linking the + * whole compression library into a transcoder. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* + * Compression initialization. + * Before calling this, all parameters and a data destination must be set up. + * + * We require a write_all_tables parameter as a failsafe check when writing + * multiple datastreams from the same compression object. Since prior runs + * will have left all the tables marked sent_table=TRUE, a subsequent run + * would emit an abbreviated stream (no tables) by default. This may be what + * is wanted, but for safety's sake it should not be the default behavior: + * programmers should have to make a deliberate choice to emit abbreviated + * images. Therefore the documentation and examples should encourage people + * to pass write_all_tables=TRUE; then it will take active thought to do the + * wrong thing. + */ + +GLOBAL(void) +jpeg_start_compress (j_compress_ptr cinfo, boolean write_all_tables) +{ + if (cinfo->global_state != CSTATE_START) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + if (write_all_tables) + jpeg_suppress_tables(cinfo, FALSE); /* mark all tables to be written */ + + /* (Re)initialize error mgr and destination modules */ + (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo); + (*cinfo->dest->init_destination) (cinfo); + /* Perform master selection of active modules */ + jinit_compress_master(cinfo); + /* Set up for the first pass */ + (*cinfo->master->prepare_for_pass) (cinfo); + /* Ready for application to drive first pass through jpeg_write_scanlines + * or jpeg_write_raw_data. + */ + cinfo->next_scanline = 0; + cinfo->global_state = (cinfo->raw_data_in ? CSTATE_RAW_OK : CSTATE_SCANNING); +} + + +/* + * Write some scanlines of data to the JPEG compressor. + * + * The return value will be the number of lines actually written. + * This should be less than the supplied num_lines only in case that + * the data destination module has requested suspension of the compressor, + * or if more than image_height scanlines are passed in. + * + * Note: we warn about excess calls to jpeg_write_scanlines() since + * this likely signals an application programmer error. However, + * excess scanlines passed in the last valid call are *silently* ignored, + * so that the application need not adjust num_lines for end-of-image + * when using a multiple-scanline buffer. + */ + +GLOBAL(JDIMENSION) +jpeg_write_scanlines (j_compress_ptr cinfo, JSAMPARRAY scanlines, + JDIMENSION num_lines) +{ + JDIMENSION row_ctr, rows_left; + + if (cinfo->global_state != CSTATE_SCANNING) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + if (cinfo->next_scanline >= cinfo->image_height) + WARNMS(cinfo, JWRN_TOO_MUCH_DATA); + + /* Call progress monitor hook if present */ + if (cinfo->progress != NULL) { + cinfo->progress->pass_counter = (long) cinfo->next_scanline; + cinfo->progress->pass_limit = (long) cinfo->image_height; + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + } + + /* Give master control module another chance if this is first call to + * jpeg_write_scanlines. This lets output of the frame/scan headers be + * delayed so that application can write COM, etc, markers between + * jpeg_start_compress and jpeg_write_scanlines. + */ + if (cinfo->master->call_pass_startup) + (*cinfo->master->pass_startup) (cinfo); + + /* Ignore any extra scanlines at bottom of image. */ + rows_left = cinfo->image_height - cinfo->next_scanline; + if (num_lines > rows_left) + num_lines = rows_left; + + row_ctr = 0; + (*cinfo->main->process_data) (cinfo, scanlines, &row_ctr, num_lines); + cinfo->next_scanline += row_ctr; + return row_ctr; +} + + +/* + * Alternate entry point to write raw data. + * Processes exactly one iMCU row per call, unless suspended. + */ + +GLOBAL(JDIMENSION) +jpeg_write_raw_data (j_compress_ptr cinfo, JSAMPIMAGE data, + JDIMENSION num_lines) +{ + JDIMENSION lines_per_iMCU_row; + + if (cinfo->global_state != CSTATE_RAW_OK) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + if (cinfo->next_scanline >= cinfo->image_height) { + WARNMS(cinfo, JWRN_TOO_MUCH_DATA); + return 0; + } + + /* Call progress monitor hook if present */ + if (cinfo->progress != NULL) { + cinfo->progress->pass_counter = (long) cinfo->next_scanline; + cinfo->progress->pass_limit = (long) cinfo->image_height; + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + } + + /* Give master control module another chance if this is first call to + * jpeg_write_raw_data. This lets output of the frame/scan headers be + * delayed so that application can write COM, etc, markers between + * jpeg_start_compress and jpeg_write_raw_data. + */ + if (cinfo->master->call_pass_startup) + (*cinfo->master->pass_startup) (cinfo); + + /* Verify that at least one iMCU row has been passed. */ + lines_per_iMCU_row = cinfo->max_v_samp_factor * cinfo->data_unit; + if (num_lines < lines_per_iMCU_row) + ERREXIT(cinfo, JERR_BUFFER_SIZE); + + /* Directly compress the row. */ + if (! (*cinfo->codec->compress_data) (cinfo, data)) { + /* If compressor did not consume the whole row, suspend processing. */ + return 0; + } + + /* OK, we processed one iMCU row. */ + cinfo->next_scanline += lines_per_iMCU_row; + return lines_per_iMCU_row; +} diff --git a/Utilities/ITK/Utilities/itkjpeg/jcarith.c b/Utilities/ITK/Utilities/itkjpeg/jcarith.c new file mode 100644 index 0000000000000000000000000000000000000000..7a1793610eee94e2d73c8a5687a454c23693b403 --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jcarith.c @@ -0,0 +1,24 @@ +/* + * jcarith.c + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file holds place for arithmetic entropy encoding routines. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* + * Module initialization routine for arithmetic entropy encoding. + */ + +GLOBAL(void) +jinit_arith_encoder (j_compress_ptr cinfo) +{ + ERREXIT(cinfo, JERR_ARITH_NOTIMPL); +} diff --git a/Utilities/ITK/Utilities/itkjpeg/jccoefct.c b/Utilities/ITK/Utilities/itkjpeg/jccoefct.c new file mode 100644 index 0000000000000000000000000000000000000000..cad73c87bb9e3cdb2c0f40e780c0c48c49c8e77d --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jccoefct.c @@ -0,0 +1,455 @@ +/* + * jccoefct.c + * + * Copyright (C) 1994-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the coefficient buffer controller for compression. + * This controller is the top level of the JPEG compressor proper. + * The coefficient buffer lies between forward-DCT and entropy encoding steps. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jlossy.h" /* Private declarations for lossy codec */ + + +/* We use a full-image coefficient buffer when doing Huffman optimization, + * and also for writing multiple-scan JPEG files. In all cases, the DCT + * step is run during the first pass, and subsequent passes need only read + * the buffered coefficients. + */ +#ifdef ENTROPY_OPT_SUPPORTED +#define FULL_COEF_BUFFER_SUPPORTED +#else +#ifdef C_MULTISCAN_FILES_SUPPORTED +#define FULL_COEF_BUFFER_SUPPORTED +#endif +#endif + + +/* Private buffer controller object */ + +typedef struct { + JDIMENSION iMCU_row_num; /* iMCU row # within image */ + JDIMENSION mcu_ctr; /* counts MCUs processed in current row */ + int MCU_vert_offset; /* counts MCU rows within iMCU row */ + int MCU_rows_per_iMCU_row; /* number of such rows needed */ + + /* For single-pass compression, it's sufficient to buffer just one MCU + * (although this may prove a bit slow in practice). We allocate a + * workspace of C_MAX_DATA_UNITS_IN_MCU coefficient blocks, and reuse it for + * each MCU constructed and sent. (On 80x86, the workspace is FAR even + * though it's not really very big; this is to keep the module interfaces + * unchanged when a large coefficient buffer is necessary.) + * In multi-pass modes, this array points to the current MCU's blocks + * within the virtual arrays. + */ + JBLOCKROW MCU_buffer[C_MAX_DATA_UNITS_IN_MCU]; + + /* In multi-pass modes, we need a virtual block array for each component. */ + jvirt_barray_ptr whole_image[MAX_COMPONENTS]; +} c_coef_controller; + +typedef c_coef_controller * c_coef_ptr; + + +/* Forward declarations */ +METHODDEF(boolean) compress_data + JPP((j_compress_ptr cinfo, JSAMPIMAGE input_buf)); +#ifdef FULL_COEF_BUFFER_SUPPORTED +METHODDEF(boolean) compress_first_pass + JPP((j_compress_ptr cinfo, JSAMPIMAGE input_buf)); +METHODDEF(boolean) compress_output + JPP((j_compress_ptr cinfo, JSAMPIMAGE input_buf)); +#endif + + +LOCAL(void) +start_iMCU_row (j_compress_ptr cinfo) +/* Reset within-iMCU-row counters for a new row */ +{ + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + c_coef_ptr coef = (c_coef_ptr) lossyc->coef_private; + + /* In an interleaved scan, an MCU row is the same as an iMCU row. + * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows. + * But at the bottom of the image, process only what's left. + */ + if (cinfo->comps_in_scan > 1) { + coef->MCU_rows_per_iMCU_row = 1; + } else { + if (coef->iMCU_row_num < (cinfo->total_iMCU_rows-1)) + coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor; + else + coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height; + } + + coef->mcu_ctr = 0; + coef->MCU_vert_offset = 0; +} + + +/* + * Initialize for a processing pass. + */ + +METHODDEF(void) +start_pass_coef (j_compress_ptr cinfo, J_BUF_MODE pass_mode) +{ + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + c_coef_ptr coef = (c_coef_ptr) lossyc->coef_private; + + coef->iMCU_row_num = 0; + start_iMCU_row(cinfo); + + switch (pass_mode) { + case JBUF_PASS_THRU: + if (coef->whole_image[0] != NULL) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + lossyc->pub.compress_data = compress_data; + break; +#ifdef FULL_COEF_BUFFER_SUPPORTED + case JBUF_SAVE_AND_PASS: + if (coef->whole_image[0] == NULL) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + lossyc->pub.compress_data = compress_first_pass; + break; + case JBUF_CRANK_DEST: + if (coef->whole_image[0] == NULL) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + lossyc->pub.compress_data = compress_output; + break; +#endif + default: + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + break; + } +} + + +/* + * Process some data in the single-pass case. + * We process the equivalent of one fully interleaved MCU row ("iMCU" row) + * per call, ie, v_samp_factor block rows for each component in the image. + * Returns TRUE if the iMCU row is completed, FALSE if suspended. + * + * NB: input_buf contains a plane for each component in image, + * which we index according to the component's SOF position. + */ + +METHODDEF(boolean) +compress_data (j_compress_ptr cinfo, JSAMPIMAGE input_buf) +{ + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + c_coef_ptr coef = (c_coef_ptr) lossyc->coef_private; + JDIMENSION MCU_col_num; /* index of current MCU within row */ + JDIMENSION last_MCU_col = cinfo->MCUs_per_row - 1; + JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; + int blkn, bi, ci, yindex, yoffset, blockcnt; + JDIMENSION ypos, xpos; + jpeg_component_info *compptr; + + /* Loop to write as much as one whole iMCU row */ + for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row; + yoffset++) { + for (MCU_col_num = coef->mcu_ctr; MCU_col_num <= last_MCU_col; + MCU_col_num++) { + /* Determine where data comes from in input_buf and do the DCT thing. + * Each call on forward_DCT processes a horizontal row of DCT blocks + * as wide as an MCU; we rely on having allocated the MCU_buffer[] blocks + * sequentially. Dummy blocks at the right or bottom edge are filled in + * specially. The data in them does not matter for image reconstruction, + * so we fill them with values that will encode to the smallest amount of + * data, viz: all zeroes in the AC entries, DC entries equal to previous + * block's DC value. (Thanks to Thomas Kinsman for this idea.) + */ + blkn = 0; + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + blockcnt = (MCU_col_num < last_MCU_col) ? compptr->MCU_width + : compptr->last_col_width; + xpos = MCU_col_num * compptr->MCU_sample_width; + ypos = yoffset * DCTSIZE; /* ypos == (yoffset+yindex) * DCTSIZE */ + for (yindex = 0; yindex < compptr->MCU_height; yindex++) { + if (coef->iMCU_row_num < last_iMCU_row || + yoffset+yindex < compptr->last_row_height) { + (*lossyc->fdct_forward_DCT) (cinfo, compptr, + input_buf[compptr->component_index], + coef->MCU_buffer[blkn], + ypos, xpos, (JDIMENSION) blockcnt); + if (blockcnt < compptr->MCU_width) { + /* Create some dummy blocks at the right edge of the image. */ + jzero_far((void FAR *) coef->MCU_buffer[blkn + blockcnt], + (compptr->MCU_width - blockcnt) * SIZEOF(JBLOCK)); + for (bi = blockcnt; bi < compptr->MCU_width; bi++) { + coef->MCU_buffer[blkn+bi][0][0] = coef->MCU_buffer[blkn+bi-1][0][0]; + } + } + } else { + /* Create a row of dummy blocks at the bottom of the image. */ + jzero_far((void FAR *) coef->MCU_buffer[blkn], + compptr->MCU_width * SIZEOF(JBLOCK)); + for (bi = 0; bi < compptr->MCU_width; bi++) { + coef->MCU_buffer[blkn+bi][0][0] = coef->MCU_buffer[blkn-1][0][0]; + } + } + blkn += compptr->MCU_width; + ypos += DCTSIZE; + } + } + /* Try to write the MCU. In event of a suspension failure, we will + * re-DCT the MCU on restart (a bit inefficient, could be fixed...) + */ + if (! (*lossyc->entropy_encode_mcu) (cinfo, coef->MCU_buffer)) { + /* Suspension forced; update state counters and exit */ + coef->MCU_vert_offset = yoffset; + coef->mcu_ctr = MCU_col_num; + return FALSE; + } + } + /* Completed an MCU row, but perhaps not an iMCU row */ + coef->mcu_ctr = 0; + } + /* Completed the iMCU row, advance counters for next one */ + coef->iMCU_row_num++; + start_iMCU_row(cinfo); + return TRUE; +} + + +#ifdef FULL_COEF_BUFFER_SUPPORTED + +/* + * Process some data in the first pass of a multi-pass case. + * We process the equivalent of one fully interleaved MCU row ("iMCU" row) + * per call, ie, v_samp_factor block rows for each component in the image. + * This amount of data is read from the source buffer, DCT'd and quantized, + * and saved into the virtual arrays. We also generate suitable dummy blocks + * as needed at the right and lower edges. (The dummy blocks are constructed + * in the virtual arrays, which have been padded appropriately.) This makes + * it possible for subsequent passes not to worry about real vs. dummy blocks. + * + * We must also emit the data to the entropy encoder. This is conveniently + * done by calling compress_output() after we've loaded the current strip + * of the virtual arrays. + * + * NB: input_buf contains a plane for each component in image. All + * components are DCT'd and loaded into the virtual arrays in this pass. + * However, it may be that only a subset of the components are emitted to + * the entropy encoder during this first pass; be careful about looking + * at the scan-dependent variables (MCU dimensions, etc). + */ + +METHODDEF(boolean) +compress_first_pass (j_compress_ptr cinfo, JSAMPIMAGE input_buf) +{ + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + c_coef_ptr coef = (c_coef_ptr) lossyc->coef_private; + JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; + JDIMENSION blocks_across, MCUs_across, MCUindex; + int bi, ci, h_samp_factor, block_row, block_rows, ndummy; + JCOEF lastDC; + jpeg_component_info *compptr; + JBLOCKARRAY buffer; + JBLOCKROW thisblockrow, lastblockrow; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Align the virtual buffer for this component. */ + buffer = (*cinfo->mem->access_virt_barray) + ((j_common_ptr) cinfo, coef->whole_image[ci], + coef->iMCU_row_num * compptr->v_samp_factor, + (JDIMENSION) compptr->v_samp_factor, TRUE); + /* Count non-dummy DCT block rows in this iMCU row. */ + if (coef->iMCU_row_num < last_iMCU_row) + block_rows = compptr->v_samp_factor; + else { + /* NB: can't use last_row_height here, since may not be set! */ + block_rows = (int) (compptr->height_in_data_units % compptr->v_samp_factor); + if (block_rows == 0) block_rows = compptr->v_samp_factor; + } + blocks_across = compptr->width_in_data_units; + h_samp_factor = compptr->h_samp_factor; + /* Count number of dummy blocks to be added at the right margin. */ + ndummy = (int) (blocks_across % h_samp_factor); + if (ndummy > 0) + ndummy = h_samp_factor - ndummy; + /* Perform DCT for all non-dummy blocks in this iMCU row. Each call + * on forward_DCT processes a complete horizontal row of DCT blocks. + */ + for (block_row = 0; block_row < block_rows; block_row++) { + thisblockrow = buffer[block_row]; + (*lossyc->fdct_forward_DCT) (cinfo, compptr, + input_buf[ci], thisblockrow, + (JDIMENSION) (block_row * DCTSIZE), + (JDIMENSION) 0, blocks_across); + if (ndummy > 0) { + /* Create dummy blocks at the right edge of the image. */ + thisblockrow += blocks_across; /* => first dummy block */ + jzero_far((void FAR *) thisblockrow, ndummy * SIZEOF(JBLOCK)); + lastDC = thisblockrow[-1][0]; + for (bi = 0; bi < ndummy; bi++) { + thisblockrow[bi][0] = lastDC; + } + } + } + /* If at end of image, create dummy block rows as needed. + * The tricky part here is that within each MCU, we want the DC values + * of the dummy blocks to match the last real block's DC value. + * This squeezes a few more bytes out of the resulting file... + */ + if (coef->iMCU_row_num == last_iMCU_row) { + blocks_across += ndummy; /* include lower right corner */ + MCUs_across = blocks_across / h_samp_factor; + for (block_row = block_rows; block_row < compptr->v_samp_factor; + block_row++) { + thisblockrow = buffer[block_row]; + lastblockrow = buffer[block_row-1]; + jzero_far((void FAR *) thisblockrow, + (size_t) (blocks_across * SIZEOF(JBLOCK))); + for (MCUindex = 0; MCUindex < MCUs_across; MCUindex++) { + lastDC = lastblockrow[h_samp_factor-1][0]; + for (bi = 0; bi < h_samp_factor; bi++) { + thisblockrow[bi][0] = lastDC; + } + thisblockrow += h_samp_factor; /* advance to next MCU in row */ + lastblockrow += h_samp_factor; + } + } + } + } + /* NB: compress_output will increment iMCU_row_num if successful. + * A suspension return will result in redoing all the work above next time. + */ + + /* Emit data to the entropy encoder, sharing code with subsequent passes */ + return compress_output(cinfo, input_buf); +} + + +/* + * Process some data in subsequent passes of a multi-pass case. + * We process the equivalent of one fully interleaved MCU row ("iMCU" row) + * per call, ie, v_samp_factor block rows for each component in the scan. + * The data is obtained from the virtual arrays and fed to the entropy coder. + * Returns TRUE if the iMCU row is completed, FALSE if suspended. + * + * NB: input_buf is ignored; it is likely to be a NULL pointer. + */ + +METHODDEF(boolean) +compress_output (j_compress_ptr cinfo, JSAMPIMAGE input_buf) +{ + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + c_coef_ptr coef = (c_coef_ptr) lossyc->coef_private; + JDIMENSION MCU_col_num; /* index of current MCU within row */ + int blkn, ci, xindex, yindex, yoffset; + JDIMENSION start_col; + JBLOCKARRAY buffer[MAX_COMPS_IN_SCAN]; + JBLOCKROW buffer_ptr; + jpeg_component_info *compptr; + (void)input_buf; + + /* Align the virtual buffers for the components used in this scan. + * NB: during first pass, this is safe only because the buffers will + * already be aligned properly, so jmemmgr.c won't need to do any I/O. + */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + buffer[ci] = (*cinfo->mem->access_virt_barray) + ((j_common_ptr) cinfo, coef->whole_image[compptr->component_index], + coef->iMCU_row_num * compptr->v_samp_factor, + (JDIMENSION) compptr->v_samp_factor, FALSE); + } + + /* Loop to process one whole iMCU row */ + for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row; + yoffset++) { + for (MCU_col_num = coef->mcu_ctr; MCU_col_num < cinfo->MCUs_per_row; + MCU_col_num++) { + /* Construct list of pointers to DCT blocks belonging to this MCU */ + blkn = 0; /* index of current DCT block within MCU */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + start_col = MCU_col_num * compptr->MCU_width; + for (yindex = 0; yindex < compptr->MCU_height; yindex++) { + buffer_ptr = buffer[ci][yindex+yoffset] + start_col; + for (xindex = 0; xindex < compptr->MCU_width; xindex++) { + coef->MCU_buffer[blkn++] = buffer_ptr++; + } + } + } + /* Try to write the MCU. */ + if (! (*lossyc->entropy_encode_mcu) (cinfo, coef->MCU_buffer)) { + /* Suspension forced; update state counters and exit */ + coef->MCU_vert_offset = yoffset; + coef->mcu_ctr = MCU_col_num; + return FALSE; + } + } + /* Completed an MCU row, but perhaps not an iMCU row */ + coef->mcu_ctr = 0; + } + /* Completed the iMCU row, advance counters for next one */ + coef->iMCU_row_num++; + start_iMCU_row(cinfo); + return TRUE; +} + +#endif /* FULL_COEF_BUFFER_SUPPORTED */ + + +/* + * Initialize coefficient buffer controller. + */ + +GLOBAL(void) +jinit_c_coef_controller (j_compress_ptr cinfo, boolean need_full_buffer) +{ + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + c_coef_ptr coef; + + coef = (c_coef_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(c_coef_controller)); + lossyc->coef_private = (struct jpeg_c_coef_controller *) coef; + lossyc->coef_start_pass = start_pass_coef; + + /* Create the coefficient buffer. */ + if (need_full_buffer) { +#ifdef FULL_COEF_BUFFER_SUPPORTED + /* Allocate a full-image virtual array for each component, */ + /* padded to a multiple of samp_factor DCT blocks in each direction. */ + int ci; + jpeg_component_info *compptr; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + coef->whole_image[ci] = (*cinfo->mem->request_virt_barray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE, + (JDIMENSION) jround_up((long) compptr->width_in_data_units, + (long) compptr->h_samp_factor), + (JDIMENSION) jround_up((long) compptr->height_in_data_units, + (long) compptr->v_samp_factor), + (JDIMENSION) compptr->v_samp_factor); + } +#else + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); +#endif + } else { + /* We only need a single-MCU buffer. */ + JBLOCKROW buffer; + int i; + + buffer = (JBLOCKROW) + (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE, + C_MAX_DATA_UNITS_IN_MCU * SIZEOF(JBLOCK)); + for (i = 0; i < C_MAX_DATA_UNITS_IN_MCU; i++) { + coef->MCU_buffer[i] = buffer + i; + } + coef->whole_image[0] = NULL; /* flag for no virtual arrays */ + } +} diff --git a/Utilities/ITK/Utilities/itkjpeg/jccolor.c b/Utilities/ITK/Utilities/itkjpeg/jccolor.c new file mode 100644 index 0000000000000000000000000000000000000000..a0afd61bb3de1b57c7dc004da8e5dd25879a7ba9 --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jccolor.c @@ -0,0 +1,460 @@ +/* + * jccolor.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains input colorspace conversion routines. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Private subobject */ + +typedef struct { + struct jpeg_color_converter pub; /* public fields */ + + /* Private state for RGB->YCC conversion */ + INT32 * rgb_ycc_tab; /* => table for RGB to YCbCr conversion */ +} my_color_converter; + +typedef my_color_converter * my_cconvert_ptr; + + +/**************** RGB -> YCbCr conversion: most common case **************/ + +/* + * YCbCr is defined per CCIR 601-1, except that Cb and Cr are + * normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5. + * The conversion equations to be implemented are therefore + * Y = 0.29900 * R + 0.58700 * G + 0.11400 * B + * Cb = -0.16874 * R - 0.33126 * G + 0.50000 * B + CENTERJSAMPLE + * Cr = 0.50000 * R - 0.41869 * G - 0.08131 * B + CENTERJSAMPLE + * (These numbers are derived from TIFF 6.0 section 21, dated 3-June-92.) + * Note: older versions of the IJG code used a zero offset of MAXJSAMPLE/2, + * rather than CENTERJSAMPLE, for Cb and Cr. This gave equal positive and + * negative swings for Cb/Cr, but meant that grayscale values (Cb=Cr=0) + * were not represented exactly. Now we sacrifice exact representation of + * maximum red and maximum blue in order to get exact grayscales. + * + * To avoid floating-point arithmetic, we represent the fractional constants + * as integers scaled up by 2^16 (about 4 digits precision); we have to divide + * the products by 2^16, with appropriate rounding, to get the correct answer. + * + * For even more speed, we avoid doing any multiplications in the inner loop + * by precalculating the constants times R,G,B for all possible values. + * For 8-bit JSAMPLEs this is very reasonable (only 256 entries per table); + * for 12-bit samples it is still acceptable. It's not very reasonable for + * 16-bit samples, but if you want lossless storage you shouldn't be changing + * colorspace anyway. + * The CENTERJSAMPLE offsets and the rounding fudge-factor of 0.5 are included + * in the tables to save adding them separately in the inner loop. + */ + +#define SCALEBITS 16 /* speediest right-shift on some machines */ +#define CBCR_OFFSET ((INT32) CENTERJSAMPLE << SCALEBITS) +#define ONE_HALF ((INT32) 1 << (SCALEBITS-1)) +#define FIX(x) ((INT32) ((x) * (1L<<SCALEBITS) + 0.5)) + +/* We allocate one big table and divide it up into eight parts, instead of + * doing eight alloc_small requests. This lets us use a single table base + * address, which can be held in a register in the inner loops on many + * machines (more than can hold all eight addresses, anyway). + */ + +#define R_Y_OFF 0 /* offset to R => Y section */ +#define G_Y_OFF (1*(MAXJSAMPLE+1)) /* offset to G => Y section */ +#define B_Y_OFF (2*(MAXJSAMPLE+1)) /* etc. */ +#define R_CB_OFF (3*(MAXJSAMPLE+1)) +#define G_CB_OFF (4*(MAXJSAMPLE+1)) +#define B_CB_OFF (5*(MAXJSAMPLE+1)) +#define R_CR_OFF B_CB_OFF /* B=>Cb, R=>Cr are the same */ +#define G_CR_OFF (6*(MAXJSAMPLE+1)) +#define B_CR_OFF (7*(MAXJSAMPLE+1)) +#define TABLE_SIZE (8*(MAXJSAMPLE+1)) + + +/* + * Initialize for RGB->YCC colorspace conversion. + */ + +METHODDEF(void) +rgb_ycc_start (j_compress_ptr cinfo) +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + INT32 * rgb_ycc_tab; + INT32 i; + + /* Allocate and fill in the conversion tables. */ + cconvert->rgb_ycc_tab = rgb_ycc_tab = (INT32 *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (TABLE_SIZE * SIZEOF(INT32))); + + for (i = 0; i <= MAXJSAMPLE; i++) { + rgb_ycc_tab[i+R_Y_OFF] = FIX(0.29900) * i; + rgb_ycc_tab[i+G_Y_OFF] = FIX(0.58700) * i; + rgb_ycc_tab[i+B_Y_OFF] = FIX(0.11400) * i + ONE_HALF; + rgb_ycc_tab[i+R_CB_OFF] = (-FIX(0.16874)) * i; + rgb_ycc_tab[i+G_CB_OFF] = (-FIX(0.33126)) * i; + /* We use a rounding fudge-factor of 0.5-epsilon for Cb and Cr. + * This ensures that the maximum output will round to MAXJSAMPLE + * not MAXJSAMPLE+1, and thus that we don't have to range-limit. + */ + rgb_ycc_tab[i+B_CB_OFF] = FIX(0.50000) * i + CBCR_OFFSET + ONE_HALF-1; +/* B=>Cb and R=>Cr tables are the same + rgb_ycc_tab[i+R_CR_OFF] = FIX(0.50000) * i + CBCR_OFFSET + ONE_HALF-1; +*/ + rgb_ycc_tab[i+G_CR_OFF] = (-FIX(0.41869)) * i; + rgb_ycc_tab[i+B_CR_OFF] = (-FIX(0.08131)) * i; + } +} + + +/* + * Convert some rows of samples to the JPEG colorspace. + * + * Note that we change from the application's interleaved-pixel format + * to our internal noninterleaved, one-plane-per-component format. + * The input buffer is therefore three times as wide as the output buffer. + * + * A starting row offset is provided only for the output buffer. The caller + * can easily adjust the passed input_buf value to accommodate any row + * offset required on that side. + */ + +METHODDEF(void) +rgb_ycc_convert (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows) +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + register int r, g, b; + register INT32 * ctab = cconvert->rgb_ycc_tab; + register JSAMPROW inptr; + register JSAMPROW outptr0, outptr1, outptr2; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->image_width; + + while (--num_rows >= 0) { + inptr = *input_buf++; + outptr0 = output_buf[0][output_row]; + outptr1 = output_buf[1][output_row]; + outptr2 = output_buf[2][output_row]; + output_row++; + for (col = 0; col < num_cols; col++) { + r = GETJSAMPLE(inptr[RGB_RED]); + g = GETJSAMPLE(inptr[RGB_GREEN]); + b = GETJSAMPLE(inptr[RGB_BLUE]); + inptr += RGB_PIXELSIZE; + /* If the inputs are 0..MAXJSAMPLE, the outputs of these equations + * must be too; we do not need an explicit range-limiting operation. + * Hence the value being shifted is never negative, and we don't + * need the general RIGHT_SHIFT macro. + */ + /* Y */ + outptr0[col] = (JSAMPLE) + ((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF]) + >> SCALEBITS); + /* Cb */ + outptr1[col] = (JSAMPLE) + ((ctab[r+R_CB_OFF] + ctab[g+G_CB_OFF] + ctab[b+B_CB_OFF]) + >> SCALEBITS); + /* Cr */ + outptr2[col] = (JSAMPLE) + ((ctab[r+R_CR_OFF] + ctab[g+G_CR_OFF] + ctab[b+B_CR_OFF]) + >> SCALEBITS); + } + } +} + + +/**************** Cases other than RGB -> YCbCr **************/ + + +/* + * Convert some rows of samples to the JPEG colorspace. + * This version handles RGB->grayscale conversion, which is the same + * as the RGB->Y portion of RGB->YCbCr. + * We assume rgb_ycc_start has been called (we only use the Y tables). + */ + +METHODDEF(void) +rgb_gray_convert (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows) +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + register int r, g, b; + register INT32 * ctab = cconvert->rgb_ycc_tab; + register JSAMPROW inptr; + register JSAMPROW outptr; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->image_width; + + while (--num_rows >= 0) { + inptr = *input_buf++; + outptr = output_buf[0][output_row]; + output_row++; + for (col = 0; col < num_cols; col++) { + r = GETJSAMPLE(inptr[RGB_RED]); + g = GETJSAMPLE(inptr[RGB_GREEN]); + b = GETJSAMPLE(inptr[RGB_BLUE]); + inptr += RGB_PIXELSIZE; + /* Y */ + outptr[col] = (JSAMPLE) + ((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF]) + >> SCALEBITS); + } + } +} + + +/* + * Convert some rows of samples to the JPEG colorspace. + * This version handles Adobe-style CMYK->YCCK conversion, + * where we convert R=1-C, G=1-M, and B=1-Y to YCbCr using the same + * conversion as above, while passing K (black) unchanged. + * We assume rgb_ycc_start has been called. + */ + +METHODDEF(void) +cmyk_ycck_convert (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows) +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + register int r, g, b; + register INT32 * ctab = cconvert->rgb_ycc_tab; + register JSAMPROW inptr; + register JSAMPROW outptr0, outptr1, outptr2, outptr3; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->image_width; + + while (--num_rows >= 0) { + inptr = *input_buf++; + outptr0 = output_buf[0][output_row]; + outptr1 = output_buf[1][output_row]; + outptr2 = output_buf[2][output_row]; + outptr3 = output_buf[3][output_row]; + output_row++; + for (col = 0; col < num_cols; col++) { + r = MAXJSAMPLE - GETJSAMPLE(inptr[0]); + g = MAXJSAMPLE - GETJSAMPLE(inptr[1]); + b = MAXJSAMPLE - GETJSAMPLE(inptr[2]); + /* K passes through as-is */ + outptr3[col] = inptr[3]; /* don't need GETJSAMPLE here */ + inptr += 4; + /* If the inputs are 0..MAXJSAMPLE, the outputs of these equations + * must be too; we do not need an explicit range-limiting operation. + * Hence the value being shifted is never negative, and we don't + * need the general RIGHT_SHIFT macro. + */ + /* Y */ + outptr0[col] = (JSAMPLE) + ((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF]) + >> SCALEBITS); + /* Cb */ + outptr1[col] = (JSAMPLE) + ((ctab[r+R_CB_OFF] + ctab[g+G_CB_OFF] + ctab[b+B_CB_OFF]) + >> SCALEBITS); + /* Cr */ + outptr2[col] = (JSAMPLE) + ((ctab[r+R_CR_OFF] + ctab[g+G_CR_OFF] + ctab[b+B_CR_OFF]) + >> SCALEBITS); + } + } +} + + +/* + * Convert some rows of samples to the JPEG colorspace. + * This version handles grayscale output with no conversion. + * The source can be either plain grayscale or YCbCr (since Y == gray). + */ + +METHODDEF(void) +grayscale_convert (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows) +{ + register JSAMPROW inptr; + register JSAMPROW outptr; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->image_width; + int instride = cinfo->input_components; + + while (--num_rows >= 0) { + inptr = *input_buf++; + outptr = output_buf[0][output_row]; + output_row++; + for (col = 0; col < num_cols; col++) { + outptr[col] = inptr[0]; /* don't need GETJSAMPLE() here */ + inptr += instride; + } + } +} + + +/* + * Convert some rows of samples to the JPEG colorspace. + * This version handles multi-component colorspaces without conversion. + * We assume input_components == num_components. + */ + +METHODDEF(void) +null_convert (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows) +{ + register JSAMPROW inptr; + register JSAMPROW outptr; + register JDIMENSION col; + register int ci; + int nc = cinfo->num_components; + JDIMENSION num_cols = cinfo->image_width; + + while (--num_rows >= 0) { + /* It seems fastest to make a separate pass for each component. */ + for (ci = 0; ci < nc; ci++) { + inptr = *input_buf; + outptr = output_buf[ci][output_row]; + for (col = 0; col < num_cols; col++) { + outptr[col] = inptr[ci]; /* don't need GETJSAMPLE() here */ + inptr += nc; + } + } + input_buf++; + output_row++; + } +} + + +/* + * Empty method for start_pass. + */ + +METHODDEF(void) +null_method (j_compress_ptr cinfo) +{ + (void)cinfo; + /* no work needed */ +} + + +/* + * Module initialization routine for input colorspace conversion. + */ + +GLOBAL(void) +jinit_color_converter (j_compress_ptr cinfo) +{ + my_cconvert_ptr cconvert; + + cconvert = (my_cconvert_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_color_converter)); + cinfo->cconvert = (struct jpeg_color_converter *) cconvert; + /* set start_pass to null method until we find out differently */ + cconvert->pub.start_pass = null_method; + + /* Make sure input_components agrees with in_color_space */ + switch (cinfo->in_color_space) { + case JCS_GRAYSCALE: + if (cinfo->input_components != 1) + ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE); + break; + + case JCS_RGB: +#if RGB_PIXELSIZE != 3 + if (cinfo->input_components != RGB_PIXELSIZE) + ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE); + break; +#endif /* else share code with YCbCr */ + + case JCS_YCbCr: + if (cinfo->input_components != 3) + ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE); + break; + + case JCS_CMYK: + case JCS_YCCK: + if (cinfo->input_components != 4) + ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE); + break; + + default: /* JCS_UNKNOWN can be anything */ + if (cinfo->input_components < 1) + ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE); + break; + } + + /* Check num_components, set conversion method based on requested space */ + switch (cinfo->jpeg_color_space) { + case JCS_GRAYSCALE: + if (cinfo->num_components != 1) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + if (cinfo->in_color_space == JCS_GRAYSCALE) + cconvert->pub.color_convert = grayscale_convert; + else if (cinfo->in_color_space == JCS_RGB) { + cconvert->pub.start_pass = rgb_ycc_start; + cconvert->pub.color_convert = rgb_gray_convert; + } else if (cinfo->in_color_space == JCS_YCbCr) + cconvert->pub.color_convert = grayscale_convert; + else + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + break; + + case JCS_RGB: + if (cinfo->num_components != 3) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + if (cinfo->in_color_space == JCS_RGB && RGB_PIXELSIZE == 3) + cconvert->pub.color_convert = null_convert; + else + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + break; + + case JCS_YCbCr: + if (cinfo->num_components != 3) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + if (cinfo->in_color_space == JCS_RGB) { + cconvert->pub.start_pass = rgb_ycc_start; + cconvert->pub.color_convert = rgb_ycc_convert; + } else if (cinfo->in_color_space == JCS_YCbCr) + cconvert->pub.color_convert = null_convert; + else + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + break; + + case JCS_CMYK: + if (cinfo->num_components != 4) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + if (cinfo->in_color_space == JCS_CMYK) + cconvert->pub.color_convert = null_convert; + else + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + break; + + case JCS_YCCK: + if (cinfo->num_components != 4) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + if (cinfo->in_color_space == JCS_CMYK) { + cconvert->pub.start_pass = rgb_ycc_start; + cconvert->pub.color_convert = cmyk_ycck_convert; + } else if (cinfo->in_color_space == JCS_YCCK) + cconvert->pub.color_convert = null_convert; + else + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + break; + + default: /* allow null conversion of JCS_UNKNOWN */ + if (cinfo->jpeg_color_space != cinfo->in_color_space || + cinfo->num_components != cinfo->input_components) + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + cconvert->pub.color_convert = null_convert; + break; + } +} diff --git a/Utilities/ITK/Utilities/itkjpeg/jcdctmgr.c b/Utilities/ITK/Utilities/itkjpeg/jcdctmgr.c new file mode 100644 index 0000000000000000000000000000000000000000..5b21799010cd40bcd41db0ff25fbeb531439811e --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jcdctmgr.c @@ -0,0 +1,390 @@ +/* + * jcdctmgr.c + * + * Copyright (C) 1994-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the forward-DCT management logic. + * This code selects a particular DCT implementation to be used, + * and it performs related housekeeping chores including coefficient + * quantization. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jlossy.h" /* Private declarations for lossy codec */ +#include "jdct.h" /* Private declarations for DCT subsystem */ + + +/* Private subobject for this module */ + +typedef struct { + /* Pointer to the DCT routine actually in use */ + forward_DCT_method_ptr do_dct; + + /* The actual post-DCT divisors --- not identical to the quant table + * entries, because of scaling (especially for an unnormalized DCT). + * Each table is given in normal array order. + */ + DCTELEM * divisors[NUM_QUANT_TBLS]; + +#ifdef DCT_FLOAT_SUPPORTED + /* Same as above for the floating-point case. */ + float_DCT_method_ptr do_float_dct; + FAST_FLOAT * float_divisors[NUM_QUANT_TBLS]; +#endif +} fdct_controller; + +typedef fdct_controller * fdct_ptr; + + +/* + * Initialize for a processing pass. + * Verify that all referenced Q-tables are present, and set up + * the divisor table for each one. + * In the current implementation, DCT of all components is done during + * the first pass, even if only some components will be output in the + * first scan. Hence all components should be examined here. + */ + +METHODDEF(void) +start_pass_fdctmgr (j_compress_ptr cinfo) +{ + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + fdct_ptr fdct = (fdct_ptr) lossyc->fdct_private; + int ci, qtblno, i; + jpeg_component_info *compptr; + JQUANT_TBL * qtbl; + DCTELEM * dtbl; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + qtblno = compptr->quant_tbl_no; + /* Make sure specified quantization table is present */ + if (qtblno < 0 || qtblno >= NUM_QUANT_TBLS || + cinfo->quant_tbl_ptrs[qtblno] == NULL) + ERREXIT1(cinfo, JERR_NO_QUANT_TABLE, qtblno); + qtbl = cinfo->quant_tbl_ptrs[qtblno]; + /* Compute divisors for this quant table */ + /* We may do this more than once for same table, but it's not a big deal */ + switch (cinfo->dct_method) { +#ifdef DCT_ISLOW_SUPPORTED + case JDCT_ISLOW: + /* For LL&M IDCT method, divisors are equal to raw quantization + * coefficients multiplied by 8 (to counteract scaling). + */ + if (fdct->divisors[qtblno] == NULL) { + fdct->divisors[qtblno] = (DCTELEM *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + DCTSIZE2 * SIZEOF(DCTELEM)); + } + dtbl = fdct->divisors[qtblno]; + for (i = 0; i < DCTSIZE2; i++) { + dtbl[i] = ((DCTELEM) qtbl->quantval[i]) << 3; + } + break; +#endif +#ifdef DCT_IFAST_SUPPORTED + case JDCT_IFAST: + { + /* For AA&N IDCT method, divisors are equal to quantization + * coefficients scaled by scalefactor[row]*scalefactor[col], where + * scalefactor[0] = 1 + * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7 + * We apply a further scale factor of 8. + */ +#define CONST_BITS 14 + static const INT16 aanscales[DCTSIZE2] = { + /* precomputed values scaled up by 14 bits */ + 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, + 22725, 31521, 29692, 26722, 22725, 17855, 12299, 6270, + 21407, 29692, 27969, 25172, 21407, 16819, 11585, 5906, + 19266, 26722, 25172, 22654, 19266, 15137, 10426, 5315, + 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, + 12873, 17855, 16819, 15137, 12873, 10114, 6967, 3552, + 8867, 12299, 11585, 10426, 8867, 6967, 4799, 2446, + 4520, 6270, 5906, 5315, 4520, 3552, 2446, 1247 + }; + SHIFT_TEMPS + + if (fdct->divisors[qtblno] == NULL) { + fdct->divisors[qtblno] = (DCTELEM *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + DCTSIZE2 * SIZEOF(DCTELEM)); + } + dtbl = fdct->divisors[qtblno]; + for (i = 0; i < DCTSIZE2; i++) { + dtbl[i] = (DCTELEM) + DESCALE(MULTIPLY16V16((INT32) qtbl->quantval[i], + (INT32) aanscales[i]), + CONST_BITS-3); + } + } + break; +#endif +#ifdef DCT_FLOAT_SUPPORTED + case JDCT_FLOAT: + { + /* For float AA&N IDCT method, divisors are equal to quantization + * coefficients scaled by scalefactor[row]*scalefactor[col], where + * scalefactor[0] = 1 + * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7 + * We apply a further scale factor of 8. + * What's actually stored is 1/divisor so that the inner loop can + * use a multiplication rather than a division. + */ + FAST_FLOAT * fdtbl; + int row, col; + static const double aanscalefactor[DCTSIZE] = { + 1.0, 1.387039845, 1.306562965, 1.175875602, + 1.0, 0.785694958, 0.541196100, 0.275899379 + }; + + if (fdct->float_divisors[qtblno] == NULL) { + fdct->float_divisors[qtblno] = (FAST_FLOAT *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + DCTSIZE2 * SIZEOF(FAST_FLOAT)); + } + fdtbl = fdct->float_divisors[qtblno]; + i = 0; + for (row = 0; row < DCTSIZE; row++) { + for (col = 0; col < DCTSIZE; col++) { + fdtbl[i] = (FAST_FLOAT) + (1.0 / (((double) qtbl->quantval[i] * + aanscalefactor[row] * aanscalefactor[col] * 8.0))); + i++; + } + } + } + break; +#endif + default: + ERREXIT(cinfo, JERR_NOT_COMPILED); + break; + } + } +} + + +/* + * Perform forward DCT on one or more blocks of a component. + * + * The input samples are taken from the sample_data[] array starting at + * position start_row/start_col, and moving to the right for any additional + * blocks. The quantized coefficients are returned in coef_blocks[]. + */ + +METHODDEF(void) +forward_DCT (j_compress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY sample_data, JBLOCKROW coef_blocks, + JDIMENSION start_row, JDIMENSION start_col, + JDIMENSION num_blocks) +/* This version is used for integer DCT implementations. */ +{ + /* This routine is heavily used, so it's worth coding it tightly. */ + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + fdct_ptr fdct = (fdct_ptr) lossyc->fdct_private; + forward_DCT_method_ptr do_dct = fdct->do_dct; + DCTELEM * divisors = fdct->divisors[compptr->quant_tbl_no]; + DCTELEM workspace[DCTSIZE2]; /* work area for FDCT subroutine */ + JDIMENSION bi; + + sample_data += start_row; /* fold in the vertical offset once */ + + for (bi = 0; bi < num_blocks; bi++, start_col += DCTSIZE) { + /* Load data into workspace, applying unsigned->signed conversion */ + { register DCTELEM *workspaceptr; + register JSAMPROW elemptr; + register int elemr; + + workspaceptr = workspace; + for (elemr = 0; elemr < DCTSIZE; elemr++) { + elemptr = sample_data[elemr] + start_col; +#if DCTSIZE == 8 /* unroll the inner loop */ + *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; + *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; + *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; + *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; + *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; + *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; + *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; + *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; +#else + { register int elemc; + for (elemc = DCTSIZE; elemc > 0; elemc--) { + *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; + } + } +#endif + } + } + + /* Perform the DCT */ + (*do_dct) (workspace); + + /* Quantize/descale the coefficients, and store into coef_blocks[] */ + { register DCTELEM temp, qval; + register int i; + register JCOEFPTR output_ptr = coef_blocks[bi]; + + for (i = 0; i < DCTSIZE2; i++) { + qval = divisors[i]; + temp = workspace[i]; + /* Divide the coefficient value by qval, ensuring proper rounding. + * Since C does not specify the direction of rounding for negative + * quotients, we have to force the dividend positive for portability. + * + * In most files, at least half of the output values will be zero + * (at default quantization settings, more like three-quarters...) + * so we should ensure that this case is fast. On many machines, + * a comparison is enough cheaper than a divide to make a special test + * a win. Since both inputs will be nonnegative, we need only test + * for a < b to discover whether a/b is 0. + * If your machine's division is fast enough, define FAST_DIVIDE. + */ +#ifdef FAST_DIVIDE +#define DIVIDE_BY(a,b) a /= b +#else +#define DIVIDE_BY(a,b) if (a >= b) a /= b; else a = 0 +#endif + if (temp < 0) { + temp = -temp; + temp += qval>>1; /* for rounding */ + DIVIDE_BY(temp, qval); + temp = -temp; + } else { + temp += qval>>1; /* for rounding */ + DIVIDE_BY(temp, qval); + } + output_ptr[i] = (JCOEF) temp; + } + } + } +} + + +#ifdef DCT_FLOAT_SUPPORTED + +METHODDEF(void) +forward_DCT_float (j_compress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY sample_data, JBLOCKROW coef_blocks, + JDIMENSION start_row, JDIMENSION start_col, + JDIMENSION num_blocks) +/* This version is used for floating-point DCT implementations. */ +{ + /* This routine is heavily used, so it's worth coding it tightly. */ + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + fdct_ptr fdct = (fdct_ptr) lossyc->fdct_private; + float_DCT_method_ptr do_dct = fdct->do_float_dct; + FAST_FLOAT * divisors = fdct->float_divisors[compptr->quant_tbl_no]; + FAST_FLOAT workspace[DCTSIZE2]; /* work area for FDCT subroutine */ + JDIMENSION bi; + + sample_data += start_row; /* fold in the vertical offset once */ + + for (bi = 0; bi < num_blocks; bi++, start_col += DCTSIZE) { + /* Load data into workspace, applying unsigned->signed conversion */ + { register FAST_FLOAT *workspaceptr; + register JSAMPROW elemptr; + register int elemr; + + workspaceptr = workspace; + for (elemr = 0; elemr < DCTSIZE; elemr++) { + elemptr = sample_data[elemr] + start_col; +#if DCTSIZE == 8 /* unroll the inner loop */ + *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE); + *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE); + *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE); + *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE); + *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE); + *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE); + *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE); + *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE); +#else + { register int elemc; + for (elemc = DCTSIZE; elemc > 0; elemc--) { + *workspaceptr++ = (FAST_FLOAT) + (GETJSAMPLE(*elemptr++) - CENTERJSAMPLE); + } + } +#endif + } + } + + /* Perform the DCT */ + (*do_dct) (workspace); + + /* Quantize/descale the coefficients, and store into coef_blocks[] */ + { register FAST_FLOAT temp; + register int i; + register JCOEFPTR output_ptr = coef_blocks[bi]; + + for (i = 0; i < DCTSIZE2; i++) { + /* Apply the quantization and scaling factor */ + temp = workspace[i] * divisors[i]; + /* Round to nearest integer. + * Since C does not specify the direction of rounding for negative + * quotients, we have to force the dividend positive for portability. + * The maximum coefficient size is +-16K (for 12-bit data), so this + * code should work for either 16-bit or 32-bit ints. + */ + output_ptr[i] = (JCOEF) ((int) (temp + (FAST_FLOAT) 16384.5) - 16384); + } + } + } +} + +#endif /* DCT_FLOAT_SUPPORTED */ + + +/* + * Initialize FDCT manager. + */ + +GLOBAL(void) +jinit_forward_dct (j_compress_ptr cinfo) +{ + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + fdct_ptr fdct; + int i; + + fdct = (fdct_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(fdct_controller)); + lossyc->fdct_private = (struct jpeg_forward_dct *) fdct; + lossyc->fdct_start_pass = start_pass_fdctmgr; + + switch (cinfo->dct_method) { +#ifdef DCT_ISLOW_SUPPORTED + case JDCT_ISLOW: + lossyc->fdct_forward_DCT = forward_DCT; + fdct->do_dct = jpeg_fdct_islow; + break; +#endif +#ifdef DCT_IFAST_SUPPORTED + case JDCT_IFAST: + lossyc->fdct_forward_DCT = forward_DCT; + fdct->do_dct = jpeg_fdct_ifast; + break; +#endif +#ifdef DCT_FLOAT_SUPPORTED + case JDCT_FLOAT: + lossyc->fdct_forward_DCT = forward_DCT_float; + fdct->do_float_dct = jpeg_fdct_float; + break; +#endif + default: + ERREXIT(cinfo, JERR_NOT_COMPILED); + break; + } + + /* Mark divisor tables unallocated */ + for (i = 0; i < NUM_QUANT_TBLS; i++) { + fdct->divisors[i] = NULL; +#ifdef DCT_FLOAT_SUPPORTED + fdct->float_divisors[i] = NULL; +#endif + } +} diff --git a/Utilities/ITK/Utilities/itkjpeg/jcdiffct.c b/Utilities/ITK/Utilities/itkjpeg/jcdiffct.c new file mode 100644 index 0000000000000000000000000000000000000000..d3953425c259f936c862c1205137d2c738d26b20 --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jcdiffct.c @@ -0,0 +1,410 @@ +/* + * jcdiffct.c + * + * Copyright (C) 1994-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the difference buffer controller for compression. + * This controller is the top level of the lossless JPEG compressor proper. + * The difference buffer lies between prediction/differencing and entropy + * encoding. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jlossls.h" /* Private declarations for lossless codec */ + + +#ifdef C_LOSSLESS_SUPPORTED + +/* We use a full-image sample buffer when doing Huffman optimization, + * and also for writing multiple-scan JPEG files. In all cases, the + * full-image buffer is filled during the first pass, and the scaling, + * prediction and differencing steps are run during subsequent passes. + */ +#ifdef ENTROPY_OPT_SUPPORTED +#define FULL_SAMP_BUFFER_SUPPORTED +#else +#ifdef C_MULTISCAN_FILES_SUPPORTED +#define FULL_SAMP_BUFFER_SUPPORTED +#endif +#endif + + +/* Private buffer controller object */ + +typedef struct { + JDIMENSION iMCU_row_num; /* iMCU row # within image */ + JDIMENSION mcu_ctr; /* counts MCUs processed in current row */ + int MCU_vert_offset; /* counts MCU rows within iMCU row */ + int MCU_rows_per_iMCU_row; /* number of such rows needed */ + + JSAMPROW cur_row[MAX_COMPONENTS]; /* row of point transformed samples */ + JSAMPROW prev_row[MAX_COMPONENTS]; /* previous row of Pt'd samples */ + JDIFFARRAY diff_buf[MAX_COMPONENTS]; /* iMCU row of differences */ + + /* In multi-pass modes, we need a virtual sample array for each component. */ + jvirt_sarray_ptr whole_image[MAX_COMPONENTS]; +} c_diff_controller; + +typedef c_diff_controller * c_diff_ptr; + + +/* Forward declarations */ +METHODDEF(boolean) compress_data + JPP((j_compress_ptr cinfo, JSAMPIMAGE input_buf)); +#ifdef FULL_SAMP_BUFFER_SUPPORTED +METHODDEF(boolean) compress_first_pass + JPP((j_compress_ptr cinfo, JSAMPIMAGE input_buf)); +METHODDEF(boolean) compress_output + JPP((j_compress_ptr cinfo, JSAMPIMAGE input_buf)); +#endif + + +LOCAL(void) +start_iMCU_row (j_compress_ptr cinfo) +/* Reset within-iMCU-row counters for a new row */ +{ + j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec; + c_diff_ptr diff = (c_diff_ptr) losslsc->diff_private; + + /* In an interleaved scan, an MCU row is the same as an iMCU row. + * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows. + * But at the bottom of the image, process only what's left. + */ + if (cinfo->comps_in_scan > 1) { + diff->MCU_rows_per_iMCU_row = 1; + } else { + if (diff->iMCU_row_num < (cinfo->total_iMCU_rows-1)) + diff->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor; + else + diff->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height; + } + + diff->mcu_ctr = 0; + diff->MCU_vert_offset = 0; +} + + +/* + * Initialize for a processing pass. + */ + +METHODDEF(void) +start_pass_diff (j_compress_ptr cinfo, J_BUF_MODE pass_mode) +{ + j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec; + c_diff_ptr diff = (c_diff_ptr) losslsc->diff_private; + + diff->iMCU_row_num = 0; + start_iMCU_row(cinfo); + + switch (pass_mode) { + case JBUF_PASS_THRU: + if (diff->whole_image[0] != NULL) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + losslsc->pub.compress_data = compress_data; + break; +#ifdef FULL_SAMP_BUFFER_SUPPORTED + case JBUF_SAVE_AND_PASS: + if (diff->whole_image[0] == NULL) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + losslsc->pub.compress_data = compress_first_pass; + break; + case JBUF_CRANK_DEST: + if (diff->whole_image[0] == NULL) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + losslsc->pub.compress_data = compress_output; + break; +#endif + default: + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + break; + } +} + + +#define SWAP_ROWS(rowa,rowb) {JSAMPROW temp; temp=rowa; rowa=rowb; rowb=temp;} + +/* + * Process some data in the single-pass case. + * We process the equivalent of one fully interleaved MCU row ("iMCU" row) + * per call, ie, v_samp_factor rows for each component in the image. + * Returns TRUE if the iMCU row is completed, FALSE if suspended. + * + * NB: input_buf contains a plane for each component in image, + * which we index according to the component's SOF position. + */ + +METHODDEF(boolean) +compress_data (j_compress_ptr cinfo, JSAMPIMAGE input_buf) +{ + j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec; + c_diff_ptr diff = (c_diff_ptr) losslsc->diff_private; + JDIMENSION MCU_col_num; /* index of current MCU within row */ + JDIMENSION MCU_count; /* number of MCUs encoded */ + /* JDIMENSION last_MCU_col = cinfo->MCUs_per_row - 1; */ + JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; + int comp, ci, yoffset, samp_row, samp_rows, samps_across; + jpeg_component_info *compptr; + + /* Loop to write as much as one whole iMCU row */ + for (yoffset = diff->MCU_vert_offset; yoffset < diff->MCU_rows_per_iMCU_row; + yoffset++) { + + MCU_col_num = diff->mcu_ctr; + + /* Scale and predict each scanline of the MCU-row separately. + * + * Note: We only do this if we are at the start of a MCU-row, ie, + * we don't want to reprocess a row suspended by the output. + */ + if (MCU_col_num == 0) { + for (comp = 0; comp < cinfo->comps_in_scan; comp++) { + compptr = cinfo->cur_comp_info[comp]; + ci = compptr->component_index; + if (diff->iMCU_row_num < last_iMCU_row) + samp_rows = compptr->v_samp_factor; + else { + /* NB: can't use last_row_height here, since may not be set! */ + samp_rows = (int) (compptr->height_in_data_units % compptr->v_samp_factor); + if (samp_rows == 0) samp_rows = compptr->v_samp_factor; + else { + /* Fill dummy difference rows at the bottom edge with zeros, which + * will encode to the smallest amount of data. + */ + for (samp_row = samp_rows; samp_row < compptr->v_samp_factor; + samp_row++) + MEMZERO(diff->diff_buf[ci][samp_row], + jround_up((long) compptr->width_in_data_units, + (long) compptr->h_samp_factor) * SIZEOF(JDIFF)); + } + } + samps_across = compptr->width_in_data_units; + + for (samp_row = 0; samp_row < samp_rows; samp_row++) { + (*losslsc->scaler_scale) (cinfo, + input_buf[ci][samp_row], + diff->cur_row[ci], samps_across); + (*losslsc->predict_difference[ci]) (cinfo, ci, + diff->cur_row[ci], + diff->prev_row[ci], + diff->diff_buf[ci][samp_row], + samps_across); + SWAP_ROWS(diff->cur_row[ci], diff->prev_row[ci]); + } + } + } + + /* Try to write the MCU-row (or remaining portion of suspended MCU-row). */ + MCU_count = + (*losslsc->entropy_encode_mcus) (cinfo, + diff->diff_buf, yoffset, MCU_col_num, + cinfo->MCUs_per_row - MCU_col_num); + if (MCU_count != cinfo->MCUs_per_row - MCU_col_num) { + /* Suspension forced; update state counters and exit */ + diff->MCU_vert_offset = yoffset; + diff->mcu_ctr += MCU_col_num; + return FALSE; + } + + /* Completed an MCU row, but perhaps not an iMCU row */ + diff->mcu_ctr = 0; + } + + /* Completed the iMCU row, advance counters for next one */ + diff->iMCU_row_num++; + start_iMCU_row(cinfo); + return TRUE; +} + + +#ifdef FULL_SAMP_BUFFER_SUPPORTED + +/* + * Process some data in the first pass of a multi-pass case. + * We process the equivalent of one fully interleaved MCU row ("iMCU" row) + * per call, ie, v_samp_factor rows for each component in the image. + * This amount of data is read from the source buffer and saved into the + * virtual arrays. + * + * We must also emit the data to the compressor. This is conveniently + * done by calling compress_output() after we've loaded the current strip + * of the virtual arrays. + * + * NB: input_buf contains a plane for each component in image. All components + * are loaded into the virtual arrays in this pass. However, it may be that + * only a subset of the components are emitted to the compressor during + * this first pass; be careful about looking at the scan-dependent variables + * (MCU dimensions, etc). + */ + +METHODDEF(boolean) +compress_first_pass (j_compress_ptr cinfo, JSAMPIMAGE input_buf) +{ + j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec; + c_diff_ptr diff = (c_diff_ptr) losslsc->diff_private; + JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; + JDIMENSION samps_across; + int ci, samp_row, samp_rows; + JSAMPARRAY buffer[MAX_COMPONENTS]; + jpeg_component_info *compptr; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Align the virtual buffers for this component. */ + buffer[ci] = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, diff->whole_image[ci], + diff->iMCU_row_num * compptr->v_samp_factor, + (JDIMENSION) compptr->v_samp_factor, TRUE); + + /* Count non-dummy sample rows in this iMCU row. */ + if (diff->iMCU_row_num < last_iMCU_row) + samp_rows = compptr->v_samp_factor; + else { + /* NB: can't use last_row_height here, since may not be set! */ + samp_rows = (int) (compptr->height_in_data_units % compptr->v_samp_factor); + if (samp_rows == 0) samp_rows = compptr->v_samp_factor; + } + samps_across = compptr->width_in_data_units; + + /* Perform point transform scaling and prediction/differencing for all + * non-dummy rows in this iMCU row. Each call on these functions + * process a complete row of samples. + */ + for (samp_row = 0; samp_row < samp_rows; samp_row++) { + MEMCOPY(buffer[ci][samp_row], input_buf[ci][samp_row], + samps_across * SIZEOF(JSAMPLE)); + } + } + + /* NB: compress_output will increment iMCU_row_num if successful. + * A suspension return will result in redoing all the work above next time. + */ + + /* Emit data to the compressor, sharing code with subsequent passes */ + return compress_output(cinfo, input_buf); +} + + +/* + * Process some data in subsequent passes of a multi-pass case. + * We process the equivalent of one fully interleaved MCU row ("iMCU" row) + * per call, ie, v_samp_factor rows for each component in the scan. + * The data is obtained from the virtual arrays and fed to the compressor. + * Returns TRUE if the iMCU row is completed, FALSE if suspended. + * + * NB: input_buf is ignored; it is likely to be a NULL pointer. + */ + +METHODDEF(boolean) +compress_output (j_compress_ptr cinfo, JSAMPIMAGE input_buf) +{ + j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec; + c_diff_ptr diff = (c_diff_ptr) losslsc->diff_private; + /* JDIMENSION MCU_col_num; */ /* index of current MCU within row */ + /* JDIMENSION MCU_count; */ /* number of MCUs encoded */ + int comp, ci /* , yoffset */ ; + JSAMPARRAY buffer[MAX_COMPONENTS]; + jpeg_component_info *compptr; + (void)input_buf; + + /* Align the virtual buffers for the components used in this scan. + * NB: during first pass, this is safe only because the buffers will + * already be aligned properly, so jmemmgr.c won't need to do any I/O. + */ + for (comp = 0; comp < cinfo->comps_in_scan; comp++) { + compptr = cinfo->cur_comp_info[comp]; + ci = compptr->component_index; + buffer[ci] = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, diff->whole_image[ci], + diff->iMCU_row_num * compptr->v_samp_factor, + (JDIMENSION) compptr->v_samp_factor, FALSE); + } + + return compress_data(cinfo, buffer); +} + +#endif /* FULL_SAMP_BUFFER_SUPPORTED */ + + +/* + * Initialize difference buffer controller. + */ + +GLOBAL(void) +jinit_c_diff_controller (j_compress_ptr cinfo, boolean need_full_buffer) +{ + j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec; + c_diff_ptr diff; + int ci, row; + jpeg_component_info *compptr; + + diff = (c_diff_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(c_diff_controller)); + losslsc->diff_private = (void *) diff; + losslsc->diff_start_pass = start_pass_diff; + + /* Create the prediction row buffers. */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + diff->cur_row[ci] = *(*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (JDIMENSION) jround_up((long) compptr->width_in_data_units, + (long) compptr->h_samp_factor), + (JDIMENSION) 1); + diff->prev_row[ci] = *(*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (JDIMENSION) jround_up((long) compptr->width_in_data_units, + (long) compptr->h_samp_factor), + (JDIMENSION) 1); + } + + /* Create the difference buffer. */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + diff->diff_buf[ci] = (*cinfo->mem->alloc_darray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (JDIMENSION) jround_up((long) compptr->width_in_data_units, + (long) compptr->h_samp_factor), + (JDIMENSION) compptr->v_samp_factor); + /* Prefill difference rows with zeros. We do this because only actual + * data is placed in the buffers during prediction/differencing, leaving + * any dummy differences at the right edge as zeros, which will encode + * to the smallest amount of data. + */ + for (row = 0; row < compptr->v_samp_factor; row++) + MEMZERO(diff->diff_buf[ci][row], + jround_up((long) compptr->width_in_data_units, + (long) compptr->h_samp_factor) * SIZEOF(JDIFF)); + } + + /* Create the sample buffer. */ + if (need_full_buffer) { +#ifdef FULL_SAMP_BUFFER_SUPPORTED + /* Allocate a full-image virtual array for each component, */ + /* padded to a multiple of samp_factor differences in each direction. */ + int ci; + jpeg_component_info *compptr; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + diff->whole_image[ci] = (*cinfo->mem->request_virt_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE, + (JDIMENSION) jround_up((long) compptr->width_in_data_units, + (long) compptr->h_samp_factor), + (JDIMENSION) jround_up((long) compptr->height_in_data_units, + (long) compptr->v_samp_factor), + (JDIMENSION) compptr->v_samp_factor); + } +#else + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); +#endif + } else + diff->whole_image[0] = NULL; /* flag for no virtual arrays */ +} + +#endif /* C_LOSSLESS_SUPPORTED */ diff --git a/Utilities/ITK/Utilities/itkjpeg/jchuff.c b/Utilities/ITK/Utilities/itkjpeg/jchuff.c new file mode 100644 index 0000000000000000000000000000000000000000..86683b14e4971e6a41f1872c1d16f078b01159e2 --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jchuff.c @@ -0,0 +1,274 @@ +/* + * jchuff.c + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains Huffman entropy decoding routines which are shared + * by the sequential, progressive and lossless decoders. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jchuff.h" /* Declarations shared with jc*huff.c */ + + +/* + * Compute the derived values for a Huffman table. + * This routine also performs some validation checks on the table. + */ + +GLOBAL(void) +jpeg_make_c_derived_tbl (j_compress_ptr cinfo, boolean isDC, int tblno, + c_derived_tbl ** pdtbl) +{ + JHUFF_TBL *htbl; + c_derived_tbl *dtbl; + int p, i, l, lastp, si, maxsymbol; + char huffsize[257]; + unsigned int huffcode[257]; + unsigned int code; + + /* Note that huffsize[] and huffcode[] are filled in code-length order, + * paralleling the order of the symbols themselves in htbl->huffval[]. + */ + + /* Find the input Huffman table */ + if (tblno < 0 || tblno >= NUM_HUFF_TBLS) + ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tblno); + htbl = + isDC ? cinfo->dc_huff_tbl_ptrs[tblno] : cinfo->ac_huff_tbl_ptrs[tblno]; + if (htbl == NULL) + ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tblno); + + /* Allocate a workspace if we haven't already done so. */ + if (*pdtbl == NULL) + *pdtbl = (c_derived_tbl *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(c_derived_tbl)); + dtbl = *pdtbl; + + /* Figure C.1: make table of Huffman code length for each symbol */ + + p = 0; + for (l = 1; l <= 16; l++) { + i = (int) htbl->bits[l]; + if (i < 0 || p + i > 256) /* protect against table overrun */ + ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); + while (i--) + huffsize[p++] = (char) l; + } + huffsize[p] = 0; + lastp = p; + + /* Figure C.2: generate the codes themselves */ + /* We also validate that the counts represent a legal Huffman code tree. */ + + code = 0; + si = huffsize[0]; + p = 0; + while (huffsize[p]) { + while (((int) huffsize[p]) == si) { + huffcode[p++] = code; + code++; + } + /* code is now 1 more than the last code used for codelength si; but + * it must still fit in si bits, since no code is allowed to be all ones. + * BUG FIX 2001-09-03: Comparison must be >, not >= + */ + if (((INT32) code) > (((INT32) 1) << si)) + ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); + code <<= 1; + si++; + } + + /* Figure C.3: generate encoding tables */ + /* These are code and size indexed by symbol value */ + + /* Set all codeless symbols to have code length 0; + * this lets us detect duplicate VAL entries here, and later + * allows emit_bits to detect any attempt to emit such symbols. + */ + MEMZERO(dtbl->ehufsi, SIZEOF(dtbl->ehufsi)); + + /* This is also a convenient place to check for out-of-range + * and duplicated VAL entries. We allow 0..255 for AC symbols + * but only 0..16 for DC. (We could constrain them further + * based on data depth and mode, but this seems enough.) + */ + maxsymbol = isDC ? 16 : 255; + + for (p = 0; p < lastp; p++) { + i = htbl->huffval[p]; + if (i < 0 || i > maxsymbol || dtbl->ehufsi[i]) + ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); + dtbl->ehufco[i] = huffcode[p]; + dtbl->ehufsi[i] = huffsize[p]; + } +} + + +/* + * Generate the best Huffman code table for the given counts, fill htbl. + * + * The JPEG standard requires that no symbol be assigned a codeword of all + * one bits (so that padding bits added at the end of a compressed segment + * can't look like a valid code). Because of the canonical ordering of + * codewords, this just means that there must be an unused slot in the + * longest codeword length category. Section K.2 of the JPEG spec suggests + * reserving such a slot by pretending that symbol 256 is a valid symbol + * with count 1. In theory that's not optimal; giving it count zero but + * including it in the symbol set anyway should give a better Huffman code. + * But the theoretically better code actually seems to come out worse in + * practice, because it produces more all-ones bytes (which incur stuffed + * zero bytes in the final file). In any case the difference is tiny. + * + * The JPEG standard requires Huffman codes to be no more than 16 bits long. + * If some symbols have a very small but nonzero probability, the Huffman tree + * must be adjusted to meet the code length restriction. We currently use + * the adjustment method suggested in JPEG section K.2. This method is *not* + * optimal; it may not choose the best possible limited-length code. But + * typically only very-low-frequency symbols will be given less-than-optimal + * lengths, so the code is almost optimal. Experimental comparisons against + * an optimal limited-length-code algorithm indicate that the difference is + * microscopic --- usually less than a hundredth of a percent of total size. + * So the extra complexity of an optimal algorithm doesn't seem worthwhile. + */ + +GLOBAL(void) +jpeg_gen_optimal_table (j_compress_ptr cinfo, JHUFF_TBL * htbl, long freq[]) +{ +#define MAX_CLEN 32 /* assumed maximum initial code length */ + UINT8 bits[MAX_CLEN+1]; /* bits[k] = # of symbols with code length k */ + int codesize[257]; /* codesize[k] = code length of symbol k */ + int others[257]; /* next symbol in current branch of tree */ + int c1, c2; + int p, i, j; + long v; + + /* This algorithm is explained in section K.2 of the JPEG standard */ + + MEMZERO(bits, SIZEOF(bits)); + MEMZERO(codesize, SIZEOF(codesize)); + for (i = 0; i < 257; i++) + others[i] = -1; /* init links to empty */ + + freq[256] = 1; /* make sure 256 has a nonzero count */ + /* Including the pseudo-symbol 256 in the Huffman procedure guarantees + * that no real symbol is given code-value of all ones, because 256 + * will be placed last in the largest codeword category. + */ + + /* Huffman's basic algorithm to assign optimal code lengths to symbols */ + + for (;;) { + /* Find the smallest nonzero frequency, set c1 = its symbol */ + /* In case of ties, take the larger symbol number */ + c1 = -1; + v = 1000000000L; + for (i = 0; i <= 256; i++) { + if (freq[i] && freq[i] <= v) { + v = freq[i]; + c1 = i; + } + } + + /* Find the next smallest nonzero frequency, set c2 = its symbol */ + /* In case of ties, take the larger symbol number */ + c2 = -1; + v = 1000000000L; + for (i = 0; i <= 256; i++) { + if (freq[i] && freq[i] <= v && i != c1) { + v = freq[i]; + c2 = i; + } + } + + /* Done if we've merged everything into one frequency */ + if (c2 < 0) + break; + + /* Else merge the two counts/trees */ + freq[c1] += freq[c2]; + freq[c2] = 0; + + /* Increment the codesize of everything in c1's tree branch */ + codesize[c1]++; + while (others[c1] >= 0) { + c1 = others[c1]; + codesize[c1]++; + } + + others[c1] = c2; /* chain c2 onto c1's tree branch */ + + /* Increment the codesize of everything in c2's tree branch */ + codesize[c2]++; + while (others[c2] >= 0) { + c2 = others[c2]; + codesize[c2]++; + } + } + + /* Now count the number of symbols of each code length */ + for (i = 0; i <= 256; i++) { + if (codesize[i]) { + /* The JPEG standard seems to think that this can't happen, */ + /* but I'm paranoid... */ + if (codesize[i] > MAX_CLEN) + ERREXIT(cinfo, JERR_HUFF_CLEN_OVERFLOW); + + bits[codesize[i]]++; + } + } + + /* JPEG doesn't allow symbols with code lengths over 16 bits, so if the pure + * Huffman procedure assigned any such lengths, we must adjust the coding. + * Here is what the JPEG spec says about how this next bit works: + * Since symbols are paired for the longest Huffman code, the symbols are + * removed from this length category two at a time. The prefix for the pair + * (which is one bit shorter) is allocated to one of the pair; then, + * skipping the BITS entry for that prefix length, a code word from the next + * shortest nonzero BITS entry is converted into a prefix for two code words + * one bit longer. + */ + + for (i = MAX_CLEN; i > 16; i--) { + while (bits[i] > 0) { + j = i - 2; /* find length of new prefix to be used */ + while (bits[j] == 0) + j--; + + bits[i] -= 2; /* remove two symbols */ + bits[i-1]++; /* one goes in this length */ + bits[j+1] += 2; /* two new symbols in this length */ + bits[j]--; /* symbol of this length is now a prefix */ + } + } + + /* Remove the count for the pseudo-symbol 256 from the largest codelength */ + while (bits[i] == 0) /* find largest codelength still in use */ + i--; + bits[i]--; + + /* Return final symbol counts (only for lengths 0..16) */ + MEMCOPY(htbl->bits, bits, SIZEOF(htbl->bits)); + + /* Return a list of the symbols sorted by code length */ + /* It's not real clear to me why we don't need to consider the codelength + * changes made above, but the JPEG spec seems to think this works. + */ + p = 0; + for (i = 1; i <= MAX_CLEN; i++) { + for (j = 0; j <= 255; j++) { + if (codesize[j] == i) { + htbl->huffval[p] = (UINT8) j; + p++; + } + } + } + + /* Set sent_table FALSE so updated table will be written to JPEG file. */ + htbl->sent_table = FALSE; +} diff --git a/Utilities/ITK/Utilities/itkjpeg/jchuff.h b/Utilities/ITK/Utilities/itkjpeg/jchuff.h new file mode 100644 index 0000000000000000000000000000000000000000..6b0570ea4b88ec53dac42454277911c4d2d0beeb --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jchuff.h @@ -0,0 +1,54 @@ +/* + * jchuff.h + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains declarations for Huffman entropy encoding routines + * that are shared between the sequential encoder (jchuff.c) and the + * progressive encoder (jcphuff.c). No other modules need to see these. + */ + +/* The legal range of a DCT coefficient is + * -1024 .. +1023 for 8-bit data; + * -16384 .. +16383 for 12-bit data. + * Hence the magnitude should always fit in 10 or 14 bits respectively. + */ + +#if BITS_IN_JSAMPLE == 8 +#define MAX_COEF_BITS 10 +#else +#define MAX_COEF_BITS 14 +#endif + +/* The legal range of a spatial difference is + * -32767 .. +32768. + * Hence the magnitude should always fit in 16 bits. + */ + +#define MAX_DIFF_BITS 16 + +/* Derived data constructed for each Huffman table */ + +typedef struct { + unsigned int ehufco[256]; /* code for each symbol */ + char ehufsi[256]; /* length of code for each symbol */ + /* If no code has been allocated for a symbol S, ehufsi[S] contains 0 */ +} c_derived_tbl; + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_make_c_derived_tbl jMkCDerived +#define jpeg_gen_optimal_table jGenOptTbl +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + +/* Expand a Huffman table definition into the derived format */ +EXTERN(void) jpeg_make_c_derived_tbl + JPP((j_compress_ptr cinfo, boolean isDC, int tblno, + c_derived_tbl ** pdtbl)); + +/* Generate an optimal table definition given the specified counts */ +EXTERN(void) jpeg_gen_optimal_table + JPP((j_compress_ptr cinfo, JHUFF_TBL * htbl, long freq[])); diff --git a/Utilities/ITK/Utilities/itkjpeg/jcinit.c b/Utilities/ITK/Utilities/itkjpeg/jcinit.c new file mode 100644 index 0000000000000000000000000000000000000000..b485a8e7e43a3fbcbbb2016c7de2305ee264f688 --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jcinit.c @@ -0,0 +1,57 @@ +/* + * jcinit.c + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains initialization logic for the JPEG compressor. + * This routine is in charge of selecting the modules to be executed and + * making an initialization call to each one. + * + * Logically, this code belongs in jcmaster.c. It's split out because + * linking this routine implies linking the entire compression library. + * For a transcoding-only application, we want to be able to use jcmaster.c + * without linking in the whole library. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* + * Master selection of compression modules. + * This is done once at the start of processing an image. We determine + * which modules will be used and give them appropriate initialization calls. + */ + +GLOBAL(void) +jinit_compress_master (j_compress_ptr cinfo) +{ + /* Initialize master control (includes parameter checking/processing) */ + jinit_c_master_control(cinfo, FALSE /* full compression */); + + /* Initialize compression codec */ + jinit_c_codec(cinfo); + + /* Preprocessing */ + if (! cinfo->raw_data_in) { + jinit_color_converter(cinfo); + jinit_downsampler(cinfo); + jinit_c_prep_controller(cinfo, FALSE /* never need full buffer here */); + } + + jinit_c_main_controller(cinfo, FALSE /* never need full buffer here */); + + jinit_marker_writer(cinfo); + + /* We can now tell the memory manager to allocate virtual arrays. */ + (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo); + + /* Write the datastream header (SOI) immediately. + * Frame and scan headers are postponed till later. + * This lets application insert special markers after the SOI. + */ + (*cinfo->marker->write_file_header) (cinfo); +} diff --git a/Utilities/ITK/Utilities/itkjpeg/jclhuff.c b/Utilities/ITK/Utilities/itkjpeg/jclhuff.c new file mode 100644 index 0000000000000000000000000000000000000000..a553ccee4ad48f48dab7fbe3ef10d2d18f3a3fd0 --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jclhuff.c @@ -0,0 +1,602 @@ +/* + * jclhuff.c + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains Huffman entropy encoding routines for lossless JPEG. + * + * Much of the complexity here has to do with supporting output suspension. + * If the data destination module demands suspension, we want to be able to + * back up to the start of the current MCU. To do this, we copy state + * variables into local working storage, and update them back to the + * permanent JPEG objects only upon successful completion of an MCU. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jlossls.h" /* Private declarations for lossless codec */ +#include "jchuff.h" /* Declarations shared with jc*huff.c */ + + +/* Expanded entropy encoder object for Huffman encoding. + * + * The savable_state subrecord contains fields that change within an MCU, + * but must not be updated permanently until we complete the MCU. + */ + +typedef struct { + INT32 put_buffer; /* current bit-accumulation buffer */ + int put_bits; /* # of bits now in it */ +} savable_state; + +/* This macro is to work around compilers with missing or broken + * structure assignment. You'll need to fix this code if you have + * such a compiler and you change MAX_COMPS_IN_SCAN. + */ + +#ifndef NO_STRUCT_ASSIGN +#define ASSIGN_STATE(dest,src) ((dest) = (src)) +#else +#define ASSIGN_STATE(dest,src) \ + ((dest).put_buffer = (src).put_buffer, \ + (dest).put_bits = (src).put_bits) +#endif + + +typedef struct { + int ci, yoffset, MCU_width; +} lhe_input_ptr_info; + + +typedef struct { + savable_state saved; /* Bit buffer at start of MCU */ + + /* These fields are NOT loaded into local working state. */ + unsigned int restarts_to_go; /* MCUs left in this restart interval */ + int next_restart_num; /* next restart number to write (0-7) */ + + /* Pointers to derived tables (these workspaces have image lifespan) */ + c_derived_tbl * derived_tbls[NUM_HUFF_TBLS]; + + /* Pointers to derived tables to be used for each data unit within an MCU */ + c_derived_tbl * cur_tbls[C_MAX_DATA_UNITS_IN_MCU]; + +#ifdef ENTROPY_OPT_SUPPORTED /* Statistics tables for optimization */ + long * count_ptrs[NUM_HUFF_TBLS]; + + /* Pointers to stats tables to be used for each data unit within an MCU */ + long * cur_counts[C_MAX_DATA_UNITS_IN_MCU]; +#endif + + /* Pointers to the proper input difference row for each group of data units + * within an MCU. For each component, there are Vi groups of Hi data units. + */ + JDIFFROW input_ptr[C_MAX_DATA_UNITS_IN_MCU]; + + /* Number of input pointers in use for the current MCU. This is the sum + * of all Vi in the MCU. + */ + int num_input_ptrs; + + /* Information used for positioning the input pointers within the input + * difference rows. + */ + lhe_input_ptr_info input_ptr_info[C_MAX_DATA_UNITS_IN_MCU]; + + /* Index of the proper input pointer for each data unit within an MCU */ + int input_ptr_index[C_MAX_DATA_UNITS_IN_MCU]; + +} lhuff_entropy_encoder; + +typedef lhuff_entropy_encoder * lhuff_entropy_ptr; + +/* Working state while writing an MCU. + * This struct contains all the fields that are needed by subroutines. + */ + +typedef struct { + JOCTET * next_output_byte; /* => next byte to write in buffer */ + size_t free_in_buffer; /* # of byte spaces remaining in buffer */ + savable_state cur; /* Current bit buffer & DC state */ + j_compress_ptr cinfo; /* dump_buffer needs access to this */ +} working_state; + + +/* Forward declarations */ +METHODDEF(JDIMENSION) encode_mcus_huff (j_compress_ptr cinfo, + JDIFFIMAGE diff_buf, + JDIMENSION MCU_row_num, + JDIMENSION MCU_col_num, + JDIMENSION nMCU); +METHODDEF(void) finish_pass_huff JPP((j_compress_ptr cinfo)); +#ifdef ENTROPY_OPT_SUPPORTED +METHODDEF(JDIMENSION) encode_mcus_gather (j_compress_ptr cinfo, + JDIFFIMAGE diff_buf, + JDIMENSION MCU_row_num, + JDIMENSION MCU_col_num, + JDIMENSION nMCU); +METHODDEF(void) finish_pass_gather JPP((j_compress_ptr cinfo)); +#endif + + +/* + * Initialize for a Huffman-compressed scan. + * If gather_statistics is TRUE, we do not output anything during the scan, + * just count the Huffman symbols used and generate Huffman code tables. + */ + +METHODDEF(void) +start_pass_huff (j_compress_ptr cinfo, boolean gather_statistics) +{ + j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec; + lhuff_entropy_ptr entropy = (lhuff_entropy_ptr) losslsc->entropy_private; + int ci, dctbl, sampn, ptrn, yoffset, xoffset; + jpeg_component_info * compptr; + + if (gather_statistics) { +#ifdef ENTROPY_OPT_SUPPORTED + losslsc->entropy_encode_mcus = encode_mcus_gather; + losslsc->pub.entropy_finish_pass = finish_pass_gather; +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else { + losslsc->entropy_encode_mcus = encode_mcus_huff; + losslsc->pub.entropy_finish_pass = finish_pass_huff; + } + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + dctbl = compptr->dc_tbl_no; + if (gather_statistics) { +#ifdef ENTROPY_OPT_SUPPORTED + /* Check for invalid table indexes */ + /* (make_c_derived_tbl does this in the other path) */ + if (dctbl < 0 || dctbl >= NUM_HUFF_TBLS) + ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, dctbl); + /* Allocate and zero the statistics tables */ + /* Note that jpeg_gen_optimal_table expects 257 entries in each table! */ + if (entropy->count_ptrs[dctbl] == NULL) + entropy->count_ptrs[dctbl] = (long *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + 257 * SIZEOF(long)); + MEMZERO(entropy->count_ptrs[dctbl], 257 * SIZEOF(long)); +#endif + } else { + /* Compute derived values for Huffman tables */ + /* We may do this more than once for a table, but it's not expensive */ + jpeg_make_c_derived_tbl(cinfo, TRUE, dctbl, + & entropy->derived_tbls[dctbl]); + } + } + + /* Precalculate encoding info for each sample in an MCU of this scan */ + for (sampn = 0, ptrn = 0; sampn < cinfo->data_units_in_MCU;) { + compptr = cinfo->cur_comp_info[cinfo->MCU_membership[sampn]]; + ci = compptr->component_index; + /* ci = cinfo->MCU_membership[sampn]; + compptr = cinfo->cur_comp_info[ci];*/ + for (yoffset = 0; yoffset < compptr->MCU_height; yoffset++, ptrn++) { + /* Precalculate the setup info for each input pointer */ + entropy->input_ptr_info[ptrn].ci = ci; + entropy->input_ptr_info[ptrn].yoffset = yoffset; + entropy->input_ptr_info[ptrn].MCU_width = compptr->MCU_width; + for (xoffset = 0; xoffset < compptr->MCU_width; xoffset++, sampn++) { + /* Precalculate the input pointer index for each sample */ + entropy->input_ptr_index[sampn] = ptrn; + /* Precalculate which tables to use for each sample */ + entropy->cur_tbls[sampn] = entropy->derived_tbls[compptr->dc_tbl_no]; + entropy->cur_counts[sampn] = entropy->count_ptrs[compptr->dc_tbl_no]; + } + } + } + entropy->num_input_ptrs = ptrn; + + /* Initialize bit buffer to empty */ + entropy->saved.put_buffer = 0; + entropy->saved.put_bits = 0; + + /* Initialize restart stuff */ + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num = 0; +} + + +/* Outputting bytes to the file */ + +/* Emit a byte, taking 'action' if must suspend. */ +#define emit_byte(state,val,action) \ + { *(state)->next_output_byte++ = (JOCTET) (val); \ + if (--(state)->free_in_buffer == 0) \ + if (! dump_buffer(state)) \ + { action; } } + + +LOCAL(boolean) +dump_buffer (working_state * state) +/* Empty the output buffer; return TRUE if successful, FALSE if must suspend */ +{ + struct jpeg_destination_mgr * dest = state->cinfo->dest; + + if (! (*dest->empty_output_buffer) (state->cinfo)) + return FALSE; + /* After a successful buffer dump, must reset buffer pointers */ + state->next_output_byte = dest->next_output_byte; + state->free_in_buffer = dest->free_in_buffer; + return TRUE; +} + + +/* Outputting bits to the file */ + +/* Only the right 24 bits of put_buffer are used; the valid bits are + * left-justified in this part. At most 16 bits can be passed to emit_bits + * in one call, and we never retain more than 7 bits in put_buffer + * between calls, so 24 bits are sufficient. + */ + +INLINE +LOCAL(boolean) +emit_bits (working_state * state, unsigned int code, int size) +/* Emit some bits; return TRUE if successful, FALSE if must suspend */ +{ + /* This routine is heavily used, so it's worth coding tightly. */ + register INT32 put_buffer = (INT32) code; + register int put_bits = state->cur.put_bits; + + /* if size is 0, caller used an invalid Huffman table entry */ + if (size == 0) + ERREXIT(state->cinfo, JERR_HUFF_MISSING_CODE); + + put_buffer &= (((INT32) 1)<<size) - 1; /* mask off any extra bits in code */ + + put_bits += size; /* new number of bits in buffer */ + + put_buffer <<= 24 - put_bits; /* align incoming bits */ + + put_buffer |= state->cur.put_buffer; /* and merge with old buffer contents */ + + while (put_bits >= 8) { + int c = (int) ((put_buffer >> 16) & 0xFF); + + emit_byte(state, c, return FALSE); + if (c == 0xFF) { /* need to stuff a zero byte? */ + emit_byte(state, 0, return FALSE); + } + put_buffer <<= 8; + put_bits -= 8; + } + + state->cur.put_buffer = put_buffer; /* update state variables */ + state->cur.put_bits = put_bits; + + return TRUE; +} + + +LOCAL(boolean) +flush_bits (working_state * state) +{ + if (! emit_bits(state, 0x7F, 7)) /* fill any partial byte with ones */ + return FALSE; + state->cur.put_buffer = 0; /* and reset bit-buffer to empty */ + state->cur.put_bits = 0; + return TRUE; +} + + +/* + * Emit a restart marker & resynchronize predictions. + */ + +LOCAL(boolean) +emit_restart (working_state * state, int restart_num) +{ + /* int ci; */ + + if (! flush_bits(state)) + return FALSE; + + emit_byte(state, 0xFF, return FALSE); + emit_byte(state, JPEG_RST0 + restart_num, return FALSE); + + /* The restart counter is not updated until we successfully write the MCU. */ + + return TRUE; +} + + +/* + * Encode and output one nMCU's worth of Huffman-compressed differences. + */ + +METHODDEF(JDIMENSION) +encode_mcus_huff (j_compress_ptr cinfo, JDIFFIMAGE diff_buf, + JDIMENSION MCU_row_num, JDIMENSION MCU_col_num, + JDIMENSION nMCU) +{ + j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec; + lhuff_entropy_ptr entropy = (lhuff_entropy_ptr) losslsc->entropy_private; + working_state state; + unsigned int mcu_num; + int sampn, ci, yoffset, MCU_width, ptrn; + /* jpeg_component_info * compptr; */ + + /* Load up working state */ + state.next_output_byte = cinfo->dest->next_output_byte; + state.free_in_buffer = cinfo->dest->free_in_buffer; + ASSIGN_STATE(state.cur, entropy->saved); + state.cinfo = cinfo; + + /* Emit restart marker if needed */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) + if (! emit_restart(&state, entropy->next_restart_num)) + return 0; + } + + /* Set input pointer locations based on MCU_col_num */ + for (ptrn = 0; ptrn < entropy->num_input_ptrs; ptrn++) { + ci = entropy->input_ptr_info[ptrn].ci; + yoffset = entropy->input_ptr_info[ptrn].yoffset; + MCU_width = entropy->input_ptr_info[ptrn].MCU_width; + entropy->input_ptr[ptrn] = + diff_buf[ci][MCU_row_num + yoffset] + (MCU_col_num * MCU_width); + } + + for (mcu_num = 0; mcu_num < nMCU; mcu_num++) { + + /* Inner loop handles the samples in the MCU */ + for (sampn = 0; sampn < cinfo->data_units_in_MCU; sampn++) { + register int temp, temp2 /* , temp3 */ ; + register int nbits; + c_derived_tbl *dctbl = entropy->cur_tbls[sampn]; + + /* Encode the difference per section H.1.2.2 */ + + /* Input the sample difference */ + temp = *entropy->input_ptr[entropy->input_ptr_index[sampn]]++; + + if (temp & 0x8000) { /* instead of temp < 0 */ + temp = (-temp) & 0x7FFF; /* absolute value, mod 2^16 */ + if (temp == 0) /* special case: magnitude = 32768 */ + temp2 = temp = 0x8000; + temp2 = ~ temp; /* one's complement of magnitude */ + } else { + temp &= 0x7FFF; /* abs value mod 2^16 */ + temp2 = temp; /* magnitude */ + } + + /* Find the number of bits needed for the magnitude of the difference */ + nbits = 0; + while (temp) { + nbits++; + temp >>= 1; + } + /* Check for out-of-range difference values. + */ + if (nbits > MAX_DIFF_BITS) + ERREXIT(cinfo, JERR_BAD_DIFF); + + /* Emit the Huffman-coded symbol for the number of bits */ + if (! emit_bits(&state, dctbl->ehufco[nbits], dctbl->ehufsi[nbits])) + return mcu_num; + + /* Emit that number of bits of the value, if positive, */ + /* or the complement of its magnitude, if negative. */ + if (nbits && /* emit_bits rejects calls with size 0 */ + nbits != 16) /* special case: no bits should be emitted */ + if (! emit_bits(&state, (unsigned int) temp2, nbits)) + return mcu_num; + } + + /* Completed MCU, so update state */ + cinfo->dest->next_output_byte = state.next_output_byte; + cinfo->dest->free_in_buffer = state.free_in_buffer; + ASSIGN_STATE(entropy->saved, state.cur); + + /* Update restart-interval state too */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) { + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num++; + entropy->next_restart_num &= 7; + } + entropy->restarts_to_go--; + } + + } + + return nMCU; +} + + +/* + * Finish up at the end of a Huffman-compressed scan. + */ + +METHODDEF(void) +finish_pass_huff (j_compress_ptr cinfo) +{ + j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec; + lhuff_entropy_ptr entropy = (lhuff_entropy_ptr) losslsc->entropy_private; + working_state state; + + /* Load up working state ... flush_bits needs it */ + state.next_output_byte = cinfo->dest->next_output_byte; + state.free_in_buffer = cinfo->dest->free_in_buffer; + ASSIGN_STATE(state.cur, entropy->saved); + state.cinfo = cinfo; + + /* Flush out the last data */ + if (! flush_bits(&state)) + ERREXIT(cinfo, JERR_CANT_SUSPEND); + + /* Update state */ + cinfo->dest->next_output_byte = state.next_output_byte; + cinfo->dest->free_in_buffer = state.free_in_buffer; + ASSIGN_STATE(entropy->saved, state.cur); +} + + +/* + * Huffman coding optimization. + * + * We first scan the supplied data and count the number of uses of each symbol + * that is to be Huffman-coded. (This process MUST agree with the code above.) + * Then we build a Huffman coding tree for the observed counts. + * Symbols which are not needed at all for the particular image are not + * assigned any code, which saves space in the DHT marker as well as in + * the compressed data. + */ + +#ifdef ENTROPY_OPT_SUPPORTED + +/* + * Trial-encode one nMCU's worth of Huffman-compressed differences. + * No data is actually output, so no suspension return is possible. + */ + +METHODDEF(JDIMENSION) +encode_mcus_gather (j_compress_ptr cinfo, JDIFFIMAGE diff_buf, + JDIMENSION MCU_row_num, JDIMENSION MCU_col_num, + JDIMENSION nMCU) +{ + j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec; + lhuff_entropy_ptr entropy = (lhuff_entropy_ptr) losslsc->entropy_private; + unsigned int mcu_num; + int sampn, ci, yoffset, MCU_width, ptrn; + /* jpeg_component_info * compptr; */ + + /* Take care of restart intervals if needed */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) { + /* Update restart state */ + entropy->restarts_to_go = cinfo->restart_interval; + } + entropy->restarts_to_go--; + } + + /* Set input pointer locations based on MCU_col_num */ + for (ptrn = 0; ptrn < entropy->num_input_ptrs; ptrn++) { + ci = entropy->input_ptr_info[ptrn].ci; + yoffset = entropy->input_ptr_info[ptrn].yoffset; + MCU_width = entropy->input_ptr_info[ptrn].MCU_width; + entropy->input_ptr[ptrn] = + diff_buf[ci][MCU_row_num + yoffset] + (MCU_col_num * MCU_width); + } + + for (mcu_num = 0; mcu_num < nMCU; mcu_num++) { + + /* Inner loop handles the samples in the MCU */ + for (sampn = 0; sampn < cinfo->data_units_in_MCU; sampn++) { + register int temp; + register int nbits; + /* c_derived_tbl *dctbl = entropy->cur_tbls[sampn]; */ + long * counts = entropy->cur_counts[sampn]; + + /* Encode the difference per section H.1.2.2 */ + + /* Input the sample difference */ + temp = *entropy->input_ptr[entropy->input_ptr_index[sampn]]++; + + if (temp & 0x8000) { /* instead of temp < 0 */ + temp = (-temp) & 0x7FFF; /* absolute value, mod 2^16 */ + if (temp == 0) /* special case: magnitude = 32768 */ + temp = 0x8000; + } else + temp &= 0x7FFF; /* abs value mod 2^16 */ + + /* Find the number of bits needed for the magnitude of the difference */ + nbits = 0; + while (temp) { + nbits++; + temp >>= 1; + } + /* Check for out-of-range difference values. + */ + if (nbits > MAX_DIFF_BITS) + ERREXIT(cinfo, JERR_BAD_DIFF); + + /* Count the Huffman symbol for the number of bits */ + counts[nbits]++; + } + } + + return nMCU; +} + + +/* + * Finish up a statistics-gathering pass and create the new Huffman tables. + */ + +METHODDEF(void) +finish_pass_gather (j_compress_ptr cinfo) +{ + j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec; + lhuff_entropy_ptr entropy = (lhuff_entropy_ptr) losslsc->entropy_private; + int ci, dctbl; + jpeg_component_info * compptr; + JHUFF_TBL **htblptr; + boolean did_dc[NUM_HUFF_TBLS]; + + /* It's important not to apply jpeg_gen_optimal_table more than once + * per table, because it clobbers the input frequency counts! + */ + MEMZERO(did_dc, SIZEOF(did_dc)); + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + dctbl = compptr->dc_tbl_no; + if (! did_dc[dctbl]) { + htblptr = & cinfo->dc_huff_tbl_ptrs[dctbl]; + if (*htblptr == NULL) + *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo); + jpeg_gen_optimal_table(cinfo, *htblptr, entropy->count_ptrs[dctbl]); + did_dc[dctbl] = TRUE; + } + } +} + + +#endif /* ENTROPY_OPT_SUPPORTED */ + + +METHODDEF(boolean) +need_optimization_pass (j_compress_ptr cinfo) +{ + (void)cinfo; + return TRUE; +} + + +/* + * Module initialization routine for Huffman entropy encoding. + */ + +GLOBAL(void) +jinit_lhuff_encoder (j_compress_ptr cinfo) +{ + j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec; + lhuff_entropy_ptr entropy; + int i; + + entropy = (lhuff_entropy_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(lhuff_entropy_encoder)); + losslsc->entropy_private = (struct jpeg_entropy_encoder *) entropy; + losslsc->pub.entropy_start_pass = start_pass_huff; + losslsc->pub.need_optimization_pass = need_optimization_pass; + + /* Mark tables unallocated */ + for (i = 0; i < NUM_HUFF_TBLS; i++) { + entropy->derived_tbls[i] = NULL; +#ifdef ENTROPY_OPT_SUPPORTED + entropy->count_ptrs[i] = NULL; +#endif + } +} diff --git a/Utilities/ITK/Utilities/itkjpeg/jclossls.c b/Utilities/ITK/Utilities/itkjpeg/jclossls.c new file mode 100644 index 0000000000000000000000000000000000000000..34c952942b163351434822a2a3403979fa526301 --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jclossls.c @@ -0,0 +1,78 @@ +/* + * jclossls.c + * + * Copyright (C) 1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the control logic for the lossless JPEG compressor. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jlossls.h" + + +#ifdef C_LOSSLESS_SUPPORTED + +/* + * Initialize for a processing pass. + */ + +METHODDEF(void) +start_pass (j_compress_ptr cinfo, J_BUF_MODE pass_mode) +{ + j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec; + + (*losslsc->scaler_start_pass) (cinfo); + (*losslsc->predict_start_pass) (cinfo); + (*losslsc->diff_start_pass) (cinfo, pass_mode); +} + + +/* + * Initialize the lossless compression codec. + * This is called only once, during master selection. + */ + +GLOBAL(void) +jinit_lossless_c_codec(j_compress_ptr cinfo) +{ + j_lossless_c_ptr losslsc; + + /* Create subobject in permanent pool */ + losslsc = (j_lossless_c_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + SIZEOF(jpeg_lossless_c_codec)); + cinfo->codec = (struct jpeg_c_codec *) losslsc; + + /* Initialize sub-modules */ + + /* Scaler */ + jinit_c_scaler(cinfo); + + /* Differencer */ + jinit_differencer(cinfo); + + /* Entropy encoding: either Huffman or arithmetic coding. */ + if (cinfo->arith_code) { + jinit_arith_encoder(cinfo); + } else { + jinit_lhuff_encoder(cinfo); + } + + /* Need a full-image difference buffer in any multi-pass mode. */ + jinit_c_diff_controller(cinfo, + (boolean) (cinfo->num_scans > 1 || + cinfo->optimize_coding)); + + /* Initialize method pointers. + * + * Note: entropy_start_pass and entropy_finish_pass are assigned in + * jclhuff.c and compress_data is assigned in jcdiffct.c. + */ + losslsc->pub.start_pass = start_pass; +} + +#endif /* C_LOSSLESS_SUPPORTED */ diff --git a/Utilities/ITK/Utilities/itkjpeg/jclossy.c b/Utilities/ITK/Utilities/itkjpeg/jclossy.c new file mode 100644 index 0000000000000000000000000000000000000000..4484714025e97379189e1f7319cac2a00369f60e --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jclossy.c @@ -0,0 +1,76 @@ +/* + * jclossy.c + * + * Copyright (C) 1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the control logic for the lossy JPEG compressor. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jlossy.h" + + +/* + * Initialize for a processing pass. + */ + +METHODDEF(void) +start_pass (j_compress_ptr cinfo, J_BUF_MODE pass_mode) +{ + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + + (*lossyc->fdct_start_pass) (cinfo); + (*lossyc->coef_start_pass) (cinfo, pass_mode); +} + + +/* + * Initialize the lossy compression codec. + * This is called only once, during master selection. + */ + +GLOBAL(void) +jinit_lossy_c_codec (j_compress_ptr cinfo) +{ + j_lossy_c_ptr lossyc; + + /* Create subobject in permanent pool */ + lossyc = (j_lossy_c_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + SIZEOF(jpeg_lossy_c_codec)); + cinfo->codec = (struct jpeg_c_codec *) lossyc; + + /* Initialize sub-modules */ + + /* Forward DCT */ + jinit_forward_dct(cinfo); + /* Entropy encoding: either Huffman or arithmetic coding. */ + if (cinfo->arith_code) { + jinit_arith_encoder(cinfo); + } else { + if (cinfo->process == JPROC_PROGRESSIVE) { +#ifdef C_PROGRESSIVE_SUPPORTED + jinit_phuff_encoder(cinfo); +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else + jinit_shuff_encoder(cinfo); + } + + /* Need a full-image coefficient buffer in any multi-pass mode. */ + jinit_c_coef_controller(cinfo, + (boolean) (cinfo->num_scans > 1 || + cinfo->optimize_coding)); + + /* Initialize method pointers. + * + * Note: entropy_start_pass and entropy_finish_pass are assigned in + * jcshuff.c or jcphuff.c and compress_data is assigned in jccoefct.c. + */ + lossyc->pub.start_pass = start_pass; +} diff --git a/Utilities/ITK/Utilities/itkjpeg/jcmainct.c b/Utilities/ITK/Utilities/itkjpeg/jcmainct.c new file mode 100644 index 0000000000000000000000000000000000000000..e0cd678a1973884d14ea7bab7e8c51a62cef5037 --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jcmainct.c @@ -0,0 +1,296 @@ +/* + * jcmainct.c + * + * Copyright (C) 1994-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the main buffer controller for compression. + * The main buffer lies between the pre-processor and the JPEG + * compressor proper; it holds downsampled data in the JPEG colorspace. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Note: currently, there is no operating mode in which a full-image buffer + * is needed at this step. If there were, that mode could not be used with + * "raw data" input, since this module is bypassed in that case. However, + * we've left the code here for possible use in special applications. + */ +#undef FULL_MAIN_BUFFER_SUPPORTED + + +/* Private buffer controller object */ + +typedef struct { + struct jpeg_c_main_controller pub; /* public fields */ + + JDIMENSION cur_iMCU_row; /* number of current iMCU row */ + JDIMENSION rowgroup_ctr; /* counts row groups received in iMCU row */ + boolean suspended; /* remember if we suspended output */ + J_BUF_MODE pass_mode; /* current operating mode */ + + /* If using just a strip buffer, this points to the entire set of buffers + * (we allocate one for each component). In the full-image case, this + * points to the currently accessible strips of the virtual arrays. + */ + JSAMPARRAY buffer[MAX_COMPONENTS]; + +#ifdef FULL_MAIN_BUFFER_SUPPORTED + /* If using full-image storage, this array holds pointers to virtual-array + * control blocks for each component. Unused if not full-image storage. + */ + jvirt_sarray_ptr whole_image[MAX_COMPONENTS]; +#endif +} my_main_controller; + +typedef my_main_controller * my_main_ptr; + + +/* Forward declarations */ +METHODDEF(void) process_data_simple_main + JPP((j_compress_ptr cinfo, JSAMPARRAY input_buf, + JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail)); +#ifdef FULL_MAIN_BUFFER_SUPPORTED +METHODDEF(void) process_data_buffer_main + JPP((j_compress_ptr cinfo, JSAMPARRAY input_buf, + JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail)); +#endif + + +/* + * Initialize for a processing pass. + */ + +METHODDEF(void) +start_pass_main (j_compress_ptr cinfo, J_BUF_MODE pass_mode) +{ + my_main_ptr mainPtr = (my_main_ptr) cinfo->main; + + /* Do nothing in raw-data mode. */ + if (cinfo->raw_data_in) + return; + + mainPtr->cur_iMCU_row = 0; /* initialize counters */ + mainPtr->rowgroup_ctr = 0; + mainPtr->suspended = FALSE; + mainPtr->pass_mode = pass_mode; /* save mode for use by process_data */ + + switch (pass_mode) { + case JBUF_PASS_THRU: +#ifdef FULL_MAIN_BUFFER_SUPPORTED + if (mainPtr->whole_image[0] != NULL) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); +#endif + mainPtr->pub.process_data = process_data_simple_main; + break; +#ifdef FULL_MAIN_BUFFER_SUPPORTED + case JBUF_SAVE_SOURCE: + case JBUF_CRANK_DEST: + case JBUF_SAVE_AND_PASS: + if (mainPtr->whole_image[0] == NULL) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + mainPtr->pub.process_data = process_data_buffer_main; + break; +#endif + default: + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + break; + } +} + + +/* + * Process some data. + * This routine handles the simple pass-through mode, + * where we have only a strip buffer. + */ + +METHODDEF(void) +process_data_simple_main (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JDIMENSION *in_row_ctr, + JDIMENSION in_rows_avail) +{ + my_main_ptr mainPtr = (my_main_ptr) cinfo->main; + JDIMENSION data_unit = (JDIMENSION)(cinfo->data_unit); + + while (mainPtr->cur_iMCU_row < cinfo->total_iMCU_rows) { + /* Read input data if we haven't filled the main buffer yet */ + if (mainPtr->rowgroup_ctr < data_unit) + (*cinfo->prep->pre_process_data) (cinfo, + input_buf, in_row_ctr, in_rows_avail, + mainPtr->buffer, &mainPtr->rowgroup_ctr, + (JDIMENSION) data_unit); + + /* If we don't have a full iMCU row buffered, return to application for + * more data. Note that preprocessor will always pad to fill the iMCU row + * at the bottom of the image. + */ + if (mainPtr->rowgroup_ctr != data_unit) + return; + + /* Send the completed row to the compressor */ + if (! (*cinfo->codec->compress_data) (cinfo, mainPtr->buffer)) { + /* If compressor did not consume the whole row, then we must need to + * suspend processing and return to the application. In this situation + * we pretend we didn't yet consume the last input row; otherwise, if + * it happened to be the last row of the image, the application would + * think we were done. + */ + if (! mainPtr->suspended) { + (*in_row_ctr)--; + mainPtr->suspended = TRUE; + } + return; + } + /* We did finish the row. Undo our little suspension hack if a previous + * call suspended; then mark the main buffer empty. + */ + if (mainPtr->suspended) { + (*in_row_ctr)++; + mainPtr->suspended = FALSE; + } + mainPtr->rowgroup_ctr = 0; + mainPtr->cur_iMCU_row++; + } +} + + +#ifdef FULL_MAIN_BUFFER_SUPPORTED + +/* + * Process some data. + * This routine handles all of the modes that use a full-size buffer. + */ + +METHODDEF(void) +process_data_buffer_main (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JDIMENSION *in_row_ctr, + JDIMENSION in_rows_avail) +{ + my_main_ptr main = (my_main_ptr) cinfo->main; + int ci; + jpeg_component_info *compptr; + boolean writing = (mainPtr->pass_mode != JBUF_CRANK_DEST); + JDIMENSION data_unit = (JDIMENSION)(cinfo->data_unit); + + while (mainPtr->cur_iMCU_row < cinfo->total_iMCU_rows) { + /* Realign the virtual buffers if at the start of an iMCU row. */ + if (mainPtr->rowgroup_ctr == 0) { + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + mainPtr->buffer[ci] = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, mainPtr->whole_image[ci], + mainPtr->cur_iMCU_row * (compptr->v_samp_factor * data_unit), + (JDIMENSION) (compptr->v_samp_factor * data_unit), writing); + } + /* In a read pass, pretend we just read some source data. */ + if (! writing) { + *in_row_ctr += cinfo->max_v_samp_factor * data_unit; + mainPtr->rowgroup_ctr = data_unit; + } + } + + /* If a write pass, read input data until the current iMCU row is full. */ + /* Note: preprocessor will pad if necessary to fill the last iMCU row. */ + if (writing) { + (*cinfo->prep->pre_process_data) (cinfo, + input_buf, in_row_ctr, in_rows_avail, + mainPtr->buffer, &mainPtr->rowgroup_ctr, + (JDIMENSION) data_unit); + /* Return to application if we need more data to fill the iMCU row. */ + if (mainPtr->rowgroup_ctr < data_unit) + return; + } + + /* Emit data, unless this is a sink-only pass. */ + if (mainPtr->pass_mode != JBUF_SAVE_SOURCE) { + if (! (*cinfo->codec->compress_data) (cinfo, mainPtr->buffer)) { + /* If compressor did not consume the whole row, then we must need to + * suspend processing and return to the application. In this situation + * we pretend we didn't yet consume the last input row; otherwise, if + * it happened to be the last row of the image, the application would + * think we were done. + */ + if (! mainPtr->suspended) { + (*in_row_ctr)--; + mainPtr->suspended = TRUE; + } + return; + } + /* We did finish the row. Undo our little suspension hack if a previous + * call suspended; then mark the main buffer empty. + */ + if (mainPtr->suspended) { + (*in_row_ctr)++; + mainPtr->suspended = FALSE; + } + } + + /* If get here, we are done with this iMCU row. Mark buffer empty. */ + mainPtr->rowgroup_ctr = 0; + mainPtr->cur_iMCU_row++; + } +} + +#endif /* FULL_MAIN_BUFFER_SUPPORTED */ + + +/* + * Initialize main buffer controller. + */ + +GLOBAL(void) +jinit_c_main_controller (j_compress_ptr cinfo, boolean need_full_buffer) +{ + my_main_ptr mainPtr; + int ci; + jpeg_component_info *compptr; + int data_unit = cinfo->data_unit; + + mainPtr = (my_main_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_main_controller)); + cinfo->main = (struct jpeg_c_main_controller *) mainPtr; + mainPtr->pub.start_pass = start_pass_main; + + /* We don't need to create a buffer in raw-data mode. */ + if (cinfo->raw_data_in) + return; + + /* Create the buffer. It holds downsampled data, so each component + * may be of a different size. + */ + if (need_full_buffer) { +#ifdef FULL_MAIN_BUFFER_SUPPORTED + /* Allocate a full-image virtual array for each component */ + /* Note we pad the bottom to a multiple of the iMCU height */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + mainPtr->whole_image[ci] = (*cinfo->mem->request_virt_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE, + compptr->width_in_data_units * data_unit, + (JDIMENSION) jround_up((long) compptr->height_in_data_units, + (long) compptr->v_samp_factor) * data_unit, + (JDIMENSION) (compptr->v_samp_factor * data_unit)); + } +#else + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); +#endif + } else { +#ifdef FULL_MAIN_BUFFER_SUPPORTED + mainPtr->whole_image[0] = NULL; /* flag for no virtual arrays */ +#endif + /* Allocate a strip buffer for each component */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + mainPtr->buffer[ci] = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + compptr->width_in_data_units * data_unit, + (JDIMENSION) (compptr->v_samp_factor * data_unit)); + } + } +} diff --git a/Utilities/ITK/Utilities/itkjpeg/jcmarker.c b/Utilities/ITK/Utilities/itkjpeg/jcmarker.c new file mode 100644 index 0000000000000000000000000000000000000000..fc388d579b44f0cb43cfb3cecf58558067713d4a --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jcmarker.c @@ -0,0 +1,678 @@ +/* + * jcmarker.c + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to write JPEG datastream markers. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +typedef enum { /* JPEG marker codes */ + M_SOF0 = 0xc0, + M_SOF1 = 0xc1, + M_SOF2 = 0xc2, + M_SOF3 = 0xc3, + + M_SOF5 = 0xc5, + M_SOF6 = 0xc6, + M_SOF7 = 0xc7, + + M_JPG = 0xc8, + M_SOF9 = 0xc9, + M_SOF10 = 0xca, + M_SOF11 = 0xcb, + + M_SOF13 = 0xcd, + M_SOF14 = 0xce, + M_SOF15 = 0xcf, + + M_DHT = 0xc4, + + M_DAC = 0xcc, + + M_RST0 = 0xd0, + M_RST1 = 0xd1, + M_RST2 = 0xd2, + M_RST3 = 0xd3, + M_RST4 = 0xd4, + M_RST5 = 0xd5, + M_RST6 = 0xd6, + M_RST7 = 0xd7, + + M_SOI = 0xd8, + M_EOI = 0xd9, + M_SOS = 0xda, + M_DQT = 0xdb, + M_DNL = 0xdc, + M_DRI = 0xdd, + M_DHP = 0xde, + M_EXP = 0xdf, + + M_APP0 = 0xe0, + M_APP1 = 0xe1, + M_APP2 = 0xe2, + M_APP3 = 0xe3, + M_APP4 = 0xe4, + M_APP5 = 0xe5, + M_APP6 = 0xe6, + M_APP7 = 0xe7, + M_APP8 = 0xe8, + M_APP9 = 0xe9, + M_APP10 = 0xea, + M_APP11 = 0xeb, + M_APP12 = 0xec, + M_APP13 = 0xed, + M_APP14 = 0xee, + M_APP15 = 0xef, + + M_JPG0 = 0xf0, + M_JPG13 = 0xfd, + M_COM = 0xfe, + + M_TEM = 0x01, + + M_ERROR = 0x100 +} JPEG_MARKER; + + +/* Private state */ + +typedef struct { + struct jpeg_marker_writer pub; /* public fields */ + + unsigned int last_restart_interval; /* last DRI value emitted; 0 after SOI */ +} my_marker_writer; + +typedef my_marker_writer * my_marker_ptr; + + +/* + * Basic output routines. + * + * Note that we do not support suspension while writing a marker. + * Therefore, an application using suspension must ensure that there is + * enough buffer space for the initial markers (typ. 600-700 bytes) before + * calling jpeg_start_compress, and enough space to write the trailing EOI + * (a few bytes) before calling jpeg_finish_compress. Multipass compression + * modes are not supported at all with suspension, so those two are the only + * points where markers will be written. + */ + +LOCAL(void) +emit_byte (j_compress_ptr cinfo, int val) +/* Emit a byte */ +{ + struct jpeg_destination_mgr * dest = cinfo->dest; + + *(dest->next_output_byte)++ = (JOCTET) val; + if (--dest->free_in_buffer == 0) { + if (! (*dest->empty_output_buffer) (cinfo)) + ERREXIT(cinfo, JERR_CANT_SUSPEND); + } +} + + +LOCAL(void) +emit_marker (j_compress_ptr cinfo, JPEG_MARKER mark) +/* Emit a marker code */ +{ + emit_byte(cinfo, 0xFF); + emit_byte(cinfo, (int) mark); +} + + +LOCAL(void) +emit_2bytes (j_compress_ptr cinfo, int value) +/* Emit a 2-byte integer; these are always MSB first in JPEG files */ +{ + emit_byte(cinfo, (value >> 8) & 0xFF); + emit_byte(cinfo, value & 0xFF); +} + + +/* + * Routines to write specific marker types. + */ + +LOCAL(int) +emit_dqt (j_compress_ptr cinfo, int index) +/* Emit a DQT marker */ +/* Returns the precision used (0 = 8bits, 1 = 16bits) for baseline checking */ +{ + JQUANT_TBL * qtbl = cinfo->quant_tbl_ptrs[index]; + int prec; + int i; + + if (qtbl == NULL) + ERREXIT1(cinfo, JERR_NO_QUANT_TABLE, index); + + prec = 0; + for (i = 0; i < DCTSIZE2; i++) { + if (qtbl->quantval[i] > 255) + prec = 1; + } + + if (! qtbl->sent_table) { + emit_marker(cinfo, M_DQT); + + emit_2bytes(cinfo, prec ? DCTSIZE2*2 + 1 + 2 : DCTSIZE2 + 1 + 2); + + emit_byte(cinfo, index + (prec<<4)); + + for (i = 0; i < DCTSIZE2; i++) { + /* The table entries must be emitted in zigzag order. */ + unsigned int qval = qtbl->quantval[jpeg_natural_order[i]]; + if (prec) + emit_byte(cinfo, (int) (qval >> 8)); + emit_byte(cinfo, (int) (qval & 0xFF)); + } + + qtbl->sent_table = TRUE; + } + + return prec; +} + + +LOCAL(void) +emit_dht (j_compress_ptr cinfo, int index, boolean is_ac) +/* Emit a DHT marker */ +{ + JHUFF_TBL * htbl; + int length, i; + + if (is_ac) { + htbl = cinfo->ac_huff_tbl_ptrs[index]; + index += 0x10; /* output index has AC bit set */ + } else { + htbl = cinfo->dc_huff_tbl_ptrs[index]; + } + + if (htbl == NULL) + ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, index); + + if (! htbl->sent_table) { + emit_marker(cinfo, M_DHT); + + length = 0; + for (i = 1; i <= 16; i++) + length += htbl->bits[i]; + + emit_2bytes(cinfo, length + 2 + 1 + 16); + emit_byte(cinfo, index); + + for (i = 1; i <= 16; i++) + emit_byte(cinfo, htbl->bits[i]); + + for (i = 0; i < length; i++) + emit_byte(cinfo, htbl->huffval[i]); + + htbl->sent_table = TRUE; + } +} + + +LOCAL(void) +emit_dac (j_compress_ptr cinfo) +/* Emit a DAC marker */ +/* Since the useful info is so small, we want to emit all the tables in */ +/* one DAC marker. Therefore this routine does its own scan of the table. */ +{ +#ifdef C_ARITH_CODING_SUPPORTED + char dc_in_use[NUM_ARITH_TBLS]; + char ac_in_use[NUM_ARITH_TBLS]; + int length, i; + jpeg_component_info *compptr; + + for (i = 0; i < NUM_ARITH_TBLS; i++) + dc_in_use[i] = ac_in_use[i] = 0; + + for (i = 0; i < cinfo->comps_in_scan; i++) { + compptr = cinfo->cur_comp_info[i]; + dc_in_use[compptr->dc_tbl_no] = 1; + ac_in_use[compptr->ac_tbl_no] = 1; + } + + length = 0; + for (i = 0; i < NUM_ARITH_TBLS; i++) + length += dc_in_use[i] + ac_in_use[i]; + + emit_marker(cinfo, M_DAC); + + emit_2bytes(cinfo, length*2 + 2); + + for (i = 0; i < NUM_ARITH_TBLS; i++) { + if (dc_in_use[i]) { + emit_byte(cinfo, i); + emit_byte(cinfo, cinfo->arith_dc_L[i] + (cinfo->arith_dc_U[i]<<4)); + } + if (ac_in_use[i]) { + emit_byte(cinfo, i + 0x10); + emit_byte(cinfo, cinfo->arith_ac_K[i]); + } + } +#else + (void)cinfo; +#endif /* C_ARITH_CODING_SUPPORTED */ +} + + +LOCAL(void) +emit_dri (j_compress_ptr cinfo) +/* Emit a DRI marker */ +{ + emit_marker(cinfo, M_DRI); + + emit_2bytes(cinfo, 4); /* fixed length */ + + emit_2bytes(cinfo, (int) cinfo->restart_interval); +} + + +LOCAL(void) +emit_sof (j_compress_ptr cinfo, JPEG_MARKER code) +/* Emit a SOF marker */ +{ + int ci; + jpeg_component_info *compptr; + + emit_marker(cinfo, code); + + emit_2bytes(cinfo, 3 * cinfo->num_components + 2 + 5 + 1); /* length */ + + /* Make sure image isn't bigger than SOF field can handle */ + if ((long) cinfo->image_height > 65535L || + (long) cinfo->image_width > 65535L) + ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) 65535); + + emit_byte(cinfo, cinfo->data_precision); + emit_2bytes(cinfo, (int) cinfo->image_height); + emit_2bytes(cinfo, (int) cinfo->image_width); + + emit_byte(cinfo, cinfo->num_components); + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + emit_byte(cinfo, compptr->component_id); + emit_byte(cinfo, (compptr->h_samp_factor << 4) + compptr->v_samp_factor); + emit_byte(cinfo, compptr->quant_tbl_no); + } +} + + +LOCAL(void) +emit_sos (j_compress_ptr cinfo) +/* Emit a SOS marker */ +{ + int i, td, ta; + jpeg_component_info *compptr; + + emit_marker(cinfo, M_SOS); + + emit_2bytes(cinfo, 2 * cinfo->comps_in_scan + 2 + 1 + 3); /* length */ + + emit_byte(cinfo, cinfo->comps_in_scan); + + for (i = 0; i < cinfo->comps_in_scan; i++) { + compptr = cinfo->cur_comp_info[i]; + emit_byte(cinfo, compptr->component_id); + td = compptr->dc_tbl_no; + ta = compptr->ac_tbl_no; + if (cinfo->process == JPROC_PROGRESSIVE) { + /* Progressive mode: only DC or only AC tables are used in one scan; + * furthermore, Huffman coding of DC refinement uses no table at all. + * We emit 0 for unused field(s); this is recommended by the P&M text + * but does not seem to be specified in the standard. + */ + if (cinfo->Ss == 0) { + ta = 0; /* DC scan */ + if (cinfo->Ah != 0 && !cinfo->arith_code) + td = 0; /* no DC table either */ + } else { + td = 0; /* AC scan */ + } + } + emit_byte(cinfo, (td << 4) + ta); + } + + emit_byte(cinfo, cinfo->Ss); + emit_byte(cinfo, cinfo->Se); + emit_byte(cinfo, (cinfo->Ah << 4) + cinfo->Al); +} + + +LOCAL(void) +emit_jfif_app0 (j_compress_ptr cinfo) +/* Emit a JFIF-compliant APP0 marker */ +{ + /* + * Length of APP0 block (2 bytes) + * Block ID (4 bytes - ASCII "JFIF") + * Zero byte (1 byte to terminate the ID string) + * Version Major, Minor (2 bytes - major first) + * Units (1 byte - 0x00 = none, 0x01 = inch, 0x02 = cm) + * Xdpu (2 bytes - dots per unit horizontal) + * Ydpu (2 bytes - dots per unit vertical) + * Thumbnail X size (1 byte) + * Thumbnail Y size (1 byte) + */ + + emit_marker(cinfo, M_APP0); + + emit_2bytes(cinfo, 2 + 4 + 1 + 2 + 1 + 2 + 2 + 1 + 1); /* length */ + + emit_byte(cinfo, 0x4A); /* Identifier: ASCII "JFIF" */ + emit_byte(cinfo, 0x46); + emit_byte(cinfo, 0x49); + emit_byte(cinfo, 0x46); + emit_byte(cinfo, 0); + emit_byte(cinfo, cinfo->JFIF_major_version); /* Version fields */ + emit_byte(cinfo, cinfo->JFIF_minor_version); + emit_byte(cinfo, cinfo->density_unit); /* Pixel size information */ + emit_2bytes(cinfo, (int) cinfo->X_density); + emit_2bytes(cinfo, (int) cinfo->Y_density); + emit_byte(cinfo, 0); /* No thumbnail image */ + emit_byte(cinfo, 0); +} + + +LOCAL(void) +emit_adobe_app14 (j_compress_ptr cinfo) +/* Emit an Adobe APP14 marker */ +{ + /* + * Length of APP14 block (2 bytes) + * Block ID (5 bytes - ASCII "Adobe") + * Version Number (2 bytes - currently 100) + * Flags0 (2 bytes - currently 0) + * Flags1 (2 bytes - currently 0) + * Color transform (1 byte) + * + * Although Adobe TN 5116 mentions Version = 101, all the Adobe files + * now in circulation seem to use Version = 100, so that's what we write. + * + * We write the color transform byte as 1 if the JPEG color space is + * YCbCr, 2 if it's YCCK, 0 otherwise. Adobe's definition has to do with + * whether the encoder performed a transformation, which is pretty useless. + */ + + emit_marker(cinfo, M_APP14); + + emit_2bytes(cinfo, 2 + 5 + 2 + 2 + 2 + 1); /* length */ + + emit_byte(cinfo, 0x41); /* Identifier: ASCII "Adobe" */ + emit_byte(cinfo, 0x64); + emit_byte(cinfo, 0x6F); + emit_byte(cinfo, 0x62); + emit_byte(cinfo, 0x65); + emit_2bytes(cinfo, 100); /* Version */ + emit_2bytes(cinfo, 0); /* Flags0 */ + emit_2bytes(cinfo, 0); /* Flags1 */ + switch (cinfo->jpeg_color_space) { + case JCS_YCbCr: + emit_byte(cinfo, 1); /* Color transform = 1 */ + break; + case JCS_YCCK: + emit_byte(cinfo, 2); /* Color transform = 2 */ + break; + default: + emit_byte(cinfo, 0); /* Color transform = 0 */ + break; + } +} + + +/* + * These routines allow writing an arbitrary marker with parameters. + * The only intended use is to emit COM or APPn markers after calling + * write_file_header and before calling write_frame_header. + * Other uses are not guaranteed to produce desirable results. + * Counting the parameter bytes properly is the caller's responsibility. + */ + +METHODDEF(void) +write_marker_header (j_compress_ptr cinfo, int marker, unsigned int datalen) +/* Emit an arbitrary marker header */ +{ + if (datalen > (unsigned int) 65533) /* safety check */ + ERREXIT(cinfo, JERR_BAD_LENGTH); + + emit_marker(cinfo, (JPEG_MARKER) marker); + + emit_2bytes(cinfo, (int) (datalen + 2)); /* total length */ +} + +METHODDEF(void) +write_marker_byte (j_compress_ptr cinfo, int val) +/* Emit one byte of marker parameters following write_marker_header */ +{ + emit_byte(cinfo, val); +} + + +/* + * Write datastream header. + * This consists of an SOI and optional APPn markers. + * We recommend use of the JFIF marker, but not the Adobe marker, + * when using YCbCr or grayscale data. The JFIF marker should NOT + * be used for any other JPEG colorspace. The Adobe marker is helpful + * to distinguish RGB, CMYK, and YCCK colorspaces. + * Note that an application can write additional header markers after + * jpeg_start_compress returns. + */ + +METHODDEF(void) +write_file_header (j_compress_ptr cinfo) +{ + my_marker_ptr marker = (my_marker_ptr) cinfo->marker; + + emit_marker(cinfo, M_SOI); /* first the SOI */ + + /* SOI is defined to reset restart interval to 0 */ + marker->last_restart_interval = 0; + + if (cinfo->write_JFIF_header) /* next an optional JFIF APP0 */ + emit_jfif_app0(cinfo); + if (cinfo->write_Adobe_marker) /* next an optional Adobe APP14 */ + emit_adobe_app14(cinfo); +} + + +/* + * Write frame header. + * This consists of DQT and SOFn markers. + * Note that we do not emit the SOF until we have emitted the DQT(s). + * This avoids compatibility problems with incorrect implementations that + * try to error-check the quant table numbers as soon as they see the SOF. + */ + +METHODDEF(void) +write_frame_header (j_compress_ptr cinfo) +{ + int ci, prec; + boolean is_baseline; + jpeg_component_info *compptr; + + prec = 0; + if (cinfo->process != JPROC_LOSSLESS) { + /* Emit DQT for each quantization table. + * Note that emit_dqt() suppresses any duplicate tables. + */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + prec += emit_dqt(cinfo, compptr->quant_tbl_no); + } + /* now prec is nonzero iff there are any 16-bit quant tables. */ + } + + /* Check for a non-baseline specification. + * Note we assume that Huffman table numbers won't be changed later. + */ + if (cinfo->arith_code || cinfo->process != JPROC_SEQUENTIAL || + cinfo->data_precision != 8) { + is_baseline = FALSE; + } else { + is_baseline = TRUE; + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + if (compptr->dc_tbl_no > 1 || compptr->ac_tbl_no > 1) + is_baseline = FALSE; + } + if (prec && is_baseline) { + is_baseline = FALSE; + /* If it's baseline except for quantizer size, warn the user */ + TRACEMS(cinfo, 0, JTRC_16BIT_TABLES); + } + } + + /* Emit the proper SOF marker */ + if (cinfo->arith_code) { + if (cinfo->process == JPROC_PROGRESSIVE) + emit_sof(cinfo, M_SOF10); /* SOF code for progressive arithmetic */ + else if (cinfo->process == JPROC_LOSSLESS) + emit_sof(cinfo, M_SOF11); /* SOF code for lossless arithmetic */ + else + emit_sof(cinfo, M_SOF9); /* SOF code for sequential arithmetic */ + } else { + if (cinfo->process == JPROC_PROGRESSIVE) + emit_sof(cinfo, M_SOF2); /* SOF code for progressive Huffman */ + else if (cinfo->process == JPROC_LOSSLESS) + emit_sof(cinfo, M_SOF3); /* SOF code for lossless Huffman */ + else if (is_baseline) + emit_sof(cinfo, M_SOF0); /* SOF code for baseline implementation */ + else + emit_sof(cinfo, M_SOF1); /* SOF code for non-baseline Huffman file */ + } +} + + +/* + * Write scan header. + * This consists of DHT or DAC markers, optional DRI, and SOS. + * Compressed data will be written following the SOS. + */ + +METHODDEF(void) +write_scan_header (j_compress_ptr cinfo) +{ + my_marker_ptr marker = (my_marker_ptr) cinfo->marker; + int i; + jpeg_component_info *compptr; + + if (cinfo->arith_code) { + /* Emit arith conditioning info. We may have some duplication + * if the file has multiple scans, but it's so small it's hardly + * worth worrying about. + */ + emit_dac(cinfo); + } else { + /* Emit Huffman tables. + * Note that emit_dht() suppresses any duplicate tables. + */ + for (i = 0; i < cinfo->comps_in_scan; i++) { + compptr = cinfo->cur_comp_info[i]; + if (cinfo->process == JPROC_PROGRESSIVE) { + /* Progressive mode: only DC or only AC tables are used in one scan */ + if (cinfo->Ss == 0) { + if (cinfo->Ah == 0) /* DC needs no table for refinement scan */ + emit_dht(cinfo, compptr->dc_tbl_no, FALSE); + } else { + emit_dht(cinfo, compptr->ac_tbl_no, TRUE); + } + } else if (cinfo->process == JPROC_LOSSLESS) { + /* Lossless mode: only DC tables are used */ + emit_dht(cinfo, compptr->dc_tbl_no, FALSE); + } else { + /* Sequential mode: need both DC and AC tables */ + emit_dht(cinfo, compptr->dc_tbl_no, FALSE); + emit_dht(cinfo, compptr->ac_tbl_no, TRUE); + } + } + } + + /* Emit DRI if required --- note that DRI value could change for each scan. + * We avoid wasting space with unnecessary DRIs, however. + */ + if (cinfo->restart_interval != marker->last_restart_interval) { + emit_dri(cinfo); + marker->last_restart_interval = cinfo->restart_interval; + } + + emit_sos(cinfo); +} + + +/* + * Write datastream trailer. + */ + +METHODDEF(void) +write_file_trailer (j_compress_ptr cinfo) +{ + emit_marker(cinfo, M_EOI); +} + + +/* + * Write an abbreviated table-specification datastream. + * This consists of SOI, DQT and DHT tables, and EOI. + * Any table that is defined and not marked sent_table = TRUE will be + * emitted. Note that all tables will be marked sent_table = TRUE at exit. + */ + +METHODDEF(void) +write_tables_only (j_compress_ptr cinfo) +{ + int i; + + emit_marker(cinfo, M_SOI); + + for (i = 0; i < NUM_QUANT_TBLS; i++) { + if (cinfo->quant_tbl_ptrs[i] != NULL) + (void) emit_dqt(cinfo, i); + } + + if (! cinfo->arith_code) { + for (i = 0; i < NUM_HUFF_TBLS; i++) { + if (cinfo->dc_huff_tbl_ptrs[i] != NULL) + emit_dht(cinfo, i, FALSE); + if (cinfo->ac_huff_tbl_ptrs[i] != NULL) + emit_dht(cinfo, i, TRUE); + } + } + + emit_marker(cinfo, M_EOI); +} + + +/* + * Initialize the marker writer module. + */ + +GLOBAL(void) +jinit_marker_writer (j_compress_ptr cinfo) +{ + my_marker_ptr marker; + + /* Create the subobject */ + marker = (my_marker_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_marker_writer)); + cinfo->marker = (struct jpeg_marker_writer *) marker; + /* Initialize method pointers */ + marker->pub.write_file_header = write_file_header; + marker->pub.write_frame_header = write_frame_header; + marker->pub.write_scan_header = write_scan_header; + marker->pub.write_file_trailer = write_file_trailer; + marker->pub.write_tables_only = write_tables_only; + marker->pub.write_marker_header = write_marker_header; + marker->pub.write_marker_byte = write_marker_byte; + /* Initialize private state */ + marker->last_restart_interval = 0; +} diff --git a/Utilities/ITK/Utilities/itkjpeg/jcmaster.c b/Utilities/ITK/Utilities/itkjpeg/jcmaster.c new file mode 100644 index 0000000000000000000000000000000000000000..c9851268b7a6bc540edff46af9b9b8ad5c2a2c0e --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jcmaster.c @@ -0,0 +1,648 @@ +/* + * jcmaster.c + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains master control logic for the JPEG compressor. + * These routines are concerned with parameter validation, initial setup, + * and inter-pass control (determining the number of passes and the work + * to be done in each pass). + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jlossy.h" /* Private declarations for lossy codec */ + + +/* Private state */ + +typedef enum { + main_pass, /* input data, also do first output step */ + huff_opt_pass, /* Huffman code optimization pass */ + output_pass /* data output pass */ +} c_pass_type; + +typedef struct { + struct jpeg_comp_master pub; /* public fields */ + + c_pass_type pass_type; /* the type of the current pass */ + + int pass_number; /* # of passes completed */ + int total_passes; /* total # of passes needed */ + + int scan_number; /* current index in scan_info[] */ +} my_comp_master; + +typedef my_comp_master * my_master_ptr; + + +/* + * Support routines that do various essential calculations. + */ + +LOCAL(void) +initial_setup (j_compress_ptr cinfo) +/* Do computations that are needed before master selection phase */ +{ + int ci; + jpeg_component_info *compptr; + long samplesperrow; + JDIMENSION jd_samplesperrow; + int data_unit = cinfo->data_unit; + + /* Sanity check on image dimensions */ + if (cinfo->image_height <= 0 || cinfo->image_width <= 0 + || cinfo->num_components <= 0 || cinfo->input_components <= 0) + ERREXIT(cinfo, JERR_EMPTY_IMAGE); + + /* Make sure image isn't bigger than I can handle */ + if ((long) cinfo->image_height > (long) JPEG_MAX_DIMENSION || + (long) cinfo->image_width > (long) JPEG_MAX_DIMENSION) + ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) JPEG_MAX_DIMENSION); + + /* Width of an input scanline must be representable as JDIMENSION. */ + samplesperrow = (long) cinfo->image_width * (long) cinfo->input_components; + jd_samplesperrow = (JDIMENSION) samplesperrow; + if ((long) jd_samplesperrow != samplesperrow) + ERREXIT(cinfo, JERR_WIDTH_OVERFLOW); + + /* For now, precision must match compiled-in value... */ + if (cinfo->data_precision != BITS_IN_JSAMPLE) + ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision); + + /* Check that number of components won't exceed internal array sizes */ + if (cinfo->num_components > MAX_COMPONENTS) + ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components, + MAX_COMPONENTS); + + /* Compute maximum sampling factors; check factor validity */ + cinfo->max_h_samp_factor = 1; + cinfo->max_v_samp_factor = 1; + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + if (compptr->h_samp_factor<=0 || compptr->h_samp_factor>MAX_SAMP_FACTOR || + compptr->v_samp_factor<=0 || compptr->v_samp_factor>MAX_SAMP_FACTOR) + ERREXIT(cinfo, JERR_BAD_SAMPLING); + cinfo->max_h_samp_factor = MAX(cinfo->max_h_samp_factor, + compptr->h_samp_factor); + cinfo->max_v_samp_factor = MAX(cinfo->max_v_samp_factor, + compptr->v_samp_factor); + } + + /* Compute dimensions of components */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Fill in the correct component_index value; don't rely on application */ + compptr->component_index = ci; + /* For compression, we never do any codec-based processing. */ + compptr->codec_data_unit = data_unit; + /* Size in data units */ + compptr->width_in_data_units = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor, + (long) (cinfo->max_h_samp_factor * data_unit)); + compptr->height_in_data_units = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor, + (long) (cinfo->max_v_samp_factor * data_unit)); + /* Size in samples */ + compptr->downsampled_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor, + (long) cinfo->max_h_samp_factor); + compptr->downsampled_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor, + (long) cinfo->max_v_samp_factor); + /* Mark component needed (this flag isn't actually used for compression) */ + compptr->component_needed = TRUE; + } + + /* Compute number of fully interleaved MCU rows (number of times that + * main controller will call coefficient controller). + */ + cinfo->total_iMCU_rows = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height, + (long) (cinfo->max_v_samp_factor*data_unit)); +} + +#ifdef C_MULTISCAN_FILES_SUPPORTED +#define NEED_SCAN_SCRIPT +#else +#ifdef C_LOSSLESS_SUPPORTED +#define NEED_SCAN_SCRIPT +#endif +#endif + +#ifdef NEED_SCAN_SCRIPT + +LOCAL(void) +validate_script (j_compress_ptr cinfo) +/* Verify that the scan script in cinfo->scan_info[] is valid; also + * determine whether it uses progressive JPEG, and set cinfo->process. + */ +{ + const jpeg_scan_info * scanptr; + int scanno, ncomps, ci, coefi, thisi; + int Ss, Se, Ah, Al; + boolean component_sent[MAX_COMPONENTS]; +#ifdef C_PROGRESSIVE_SUPPORTED + int * last_bitpos_ptr; + int last_bitpos[MAX_COMPONENTS][DCTSIZE2]; + /* -1 until that coefficient has been seen; then last Al for it */ +#endif + + if (cinfo->num_scans <= 0) + ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, 0); + +#ifndef C_MULTISCAN_FILES_SUPPORTED + if (cinfo->num_scans > 1) + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + + scanptr = cinfo->scan_info; + if (cinfo->lossless) { +#ifdef C_LOSSLESS_SUPPORTED + cinfo->process = JPROC_LOSSLESS; + for (ci = 0; ci < cinfo->num_components; ci++) + component_sent[ci] = FALSE; +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } + /* For sequential JPEG, all scans must have Ss=0, Se=DCTSIZE2-1; + * for progressive JPEG, no scan can have this. + */ + else if (scanptr->Ss != 0 || scanptr->Se != DCTSIZE2-1) { +#ifdef C_PROGRESSIVE_SUPPORTED + cinfo->process = JPROC_PROGRESSIVE; + last_bitpos_ptr = & last_bitpos[0][0]; + for (ci = 0; ci < cinfo->num_components; ci++) + for (coefi = 0; coefi < DCTSIZE2; coefi++) + *last_bitpos_ptr++ = -1; +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else { + cinfo->process = JPROC_SEQUENTIAL; + for (ci = 0; ci < cinfo->num_components; ci++) + component_sent[ci] = FALSE; + } + + for (scanno = 1; scanno <= cinfo->num_scans; scanptr++, scanno++) { + /* Validate component indexes */ + ncomps = scanptr->comps_in_scan; + if (ncomps <= 0 || ncomps > MAX_COMPS_IN_SCAN) + ERREXIT2(cinfo, JERR_COMPONENT_COUNT, ncomps, MAX_COMPS_IN_SCAN); + for (ci = 0; ci < ncomps; ci++) { + thisi = scanptr->component_index[ci]; + if (thisi < 0 || thisi >= cinfo->num_components) + ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, scanno); + /* Components must appear in SOF order within each scan */ + if (ci > 0 && thisi <= scanptr->component_index[ci-1]) + ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, scanno); + } + /* Validate progression parameters */ + Ss = scanptr->Ss; + Se = scanptr->Se; + Ah = scanptr->Ah; + Al = scanptr->Al; + if (cinfo->process == JPROC_LOSSLESS) { +#ifdef C_LOSSLESS_SUPPORTED + /* The JPEG spec simply gives the range 0..15 for Al (Pt), but that + * seems wrong: the upper bound ought to depend on data precision. + * Perhaps they really meant 0..N-1 for N-bit precision, which is what + * we allow here. + */ + if (Ss < 1 || Ss > 7 || /* predictor selector */ + Se != 0 || Ah != 0 || + Al < 0 || Al >= cinfo->data_precision) /* point transform */ + ERREXIT1(cinfo, JERR_BAD_LOSSLESS_SCRIPT, scanno); + /* Make sure components are not sent twice */ + for (ci = 0; ci < ncomps; ci++) { + thisi = scanptr->component_index[ci]; + if (component_sent[thisi]) + ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, scanno); + component_sent[thisi] = TRUE; + } +#endif + } else if (cinfo->process == JPROC_PROGRESSIVE) { +#ifdef C_PROGRESSIVE_SUPPORTED + /* The JPEG spec simply gives the ranges 0..13 for Ah and Al, but that + * seems wrong: the upper bound ought to depend on data precision. + * Perhaps they really meant 0..N+1 for N-bit precision. + * Here we allow 0..10 for 8-bit data; Al larger than 10 results in + * out-of-range reconstructed DC values during the first DC scan, + * which might cause problems for some decoders. + */ +#if BITS_IN_JSAMPLE == 8 +#define MAX_AH_AL 10 +#else +#define MAX_AH_AL 13 +#endif + if (Ss < 0 || Ss >= DCTSIZE2 || Se < Ss || Se >= DCTSIZE2 || + Ah < 0 || Ah > MAX_AH_AL || Al < 0 || Al > MAX_AH_AL) + ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno); + if (Ss == 0) { + if (Se != 0) /* DC and AC together not OK */ + ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno); + } else { + if (ncomps != 1) /* AC scans must be for only one component */ + ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno); + } + for (ci = 0; ci < ncomps; ci++) { + last_bitpos_ptr = & last_bitpos[scanptr->component_index[ci]][0]; + if (Ss != 0 && last_bitpos_ptr[0] < 0) /* AC without prior DC scan */ + ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno); + for (coefi = Ss; coefi <= Se; coefi++) { + if (last_bitpos_ptr[coefi] < 0) { + /* first scan of this coefficient */ + if (Ah != 0) + ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno); + } else { + /* not first scan */ + if (Ah != last_bitpos_ptr[coefi] || Al != Ah-1) + ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno); + } + last_bitpos_ptr[coefi] = Al; + } + } +#endif + } else { + /* For sequential JPEG, all progression parameters must be these: */ + if (Ss != 0 || Se != DCTSIZE2-1 || Ah != 0 || Al != 0) + ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno); + /* Make sure components are not sent twice */ + for (ci = 0; ci < ncomps; ci++) { + thisi = scanptr->component_index[ci]; + if (component_sent[thisi]) + ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, scanno); + component_sent[thisi] = TRUE; + } + } + } + + /* Now verify that everything got sent. */ + if (cinfo->process == JPROC_PROGRESSIVE) { +#ifdef C_PROGRESSIVE_SUPPORTED + /* For progressive mode, we only check that at least some DC data + * got sent for each component; the spec does not require that all bits + * of all coefficients be transmitted. Would it be wiser to enforce + * transmission of all coefficient bits?? + */ + for (ci = 0; ci < cinfo->num_components; ci++) { + if (last_bitpos[ci][0] < 0) + ERREXIT(cinfo, JERR_MISSING_DATA); + } +#endif + } else { + for (ci = 0; ci < cinfo->num_components; ci++) { + if (! component_sent[ci]) + ERREXIT(cinfo, JERR_MISSING_DATA); + } + } +} + +#endif /* NEED_SCAN_SCRIPT */ + + +LOCAL(void) +select_scan_parameters (j_compress_ptr cinfo) +/* Set up the scan parameters for the current scan */ +{ + int ci; + +#ifdef NEED_SCAN_SCRIPT + if (cinfo->scan_info != NULL) { + /* Prepare for current scan --- the script is already validated */ + my_master_ptr master = (my_master_ptr) cinfo->master; + const jpeg_scan_info * scanptr = cinfo->scan_info + master->scan_number; + + cinfo->comps_in_scan = scanptr->comps_in_scan; + for (ci = 0; ci < scanptr->comps_in_scan; ci++) { + cinfo->cur_comp_info[ci] = + &cinfo->comp_info[scanptr->component_index[ci]]; + } + cinfo->Ss = scanptr->Ss; + cinfo->Se = scanptr->Se; + cinfo->Ah = scanptr->Ah; + cinfo->Al = scanptr->Al; + } else +#endif + { + /* Prepare for single sequential-JPEG scan containing all components */ + if (cinfo->num_components > MAX_COMPS_IN_SCAN) + ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components, + MAX_COMPS_IN_SCAN); + cinfo->comps_in_scan = cinfo->num_components; + for (ci = 0; ci < cinfo->num_components; ci++) { + cinfo->cur_comp_info[ci] = &cinfo->comp_info[ci]; + } + if (cinfo->lossless) { +#ifdef C_LOSSLESS_SUPPORTED + /* If we fall through to here, the user specified lossless, but did not + * provide a scan script. + */ + ERREXIT(cinfo, JERR_NO_LOSSLESS_SCRIPT); +#endif + } else { + cinfo->process = JPROC_SEQUENTIAL; + cinfo->Ss = 0; + cinfo->Se = DCTSIZE2-1; + cinfo->Ah = 0; + cinfo->Al = 0; + } + } +} + + +LOCAL(void) +per_scan_setup (j_compress_ptr cinfo) +/* Do computations that are needed before processing a JPEG scan */ +/* cinfo->comps_in_scan and cinfo->cur_comp_info[] are already set */ +{ + int ci, mcublks, tmp; + jpeg_component_info *compptr; + int data_unit = cinfo->data_unit; + + if (cinfo->comps_in_scan == 1) { + + /* Noninterleaved (single-component) scan */ + compptr = cinfo->cur_comp_info[0]; + + /* Overall image size in MCUs */ + cinfo->MCUs_per_row = compptr->width_in_data_units; + cinfo->MCU_rows_in_scan = compptr->height_in_data_units; + + /* For noninterleaved scan, always one block per MCU */ + compptr->MCU_width = 1; + compptr->MCU_height = 1; + compptr->MCU_data_units = 1; + compptr->MCU_sample_width = data_unit; + compptr->last_col_width = 1; + /* For noninterleaved scans, it is convenient to define last_row_height + * as the number of block rows present in the last iMCU row. + */ + tmp = (int) (compptr->height_in_data_units % compptr->v_samp_factor); + if (tmp == 0) tmp = compptr->v_samp_factor; + compptr->last_row_height = tmp; + + /* Prepare array describing MCU composition */ + cinfo->data_units_in_MCU = 1; + cinfo->MCU_membership[0] = 0; + + } else { + + /* Interleaved (multi-component) scan */ + if (cinfo->comps_in_scan <= 0 || cinfo->comps_in_scan > MAX_COMPS_IN_SCAN) + ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->comps_in_scan, + MAX_COMPS_IN_SCAN); + + /* Overall image size in MCUs */ + cinfo->MCUs_per_row = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width, + (long) (cinfo->max_h_samp_factor*data_unit)); + cinfo->MCU_rows_in_scan = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height, + (long) (cinfo->max_v_samp_factor*data_unit)); + + cinfo->data_units_in_MCU = 0; + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + /* Sampling factors give # of blocks of component in each MCU */ + compptr->MCU_width = compptr->h_samp_factor; + compptr->MCU_height = compptr->v_samp_factor; + compptr->MCU_data_units = compptr->MCU_width * compptr->MCU_height; + compptr->MCU_sample_width = compptr->MCU_width * data_unit; + /* Figure number of non-dummy blocks in last MCU column & row */ + tmp = (int) (compptr->width_in_data_units % compptr->MCU_width); + if (tmp == 0) tmp = compptr->MCU_width; + compptr->last_col_width = tmp; + tmp = (int) (compptr->height_in_data_units % compptr->MCU_height); + if (tmp == 0) tmp = compptr->MCU_height; + compptr->last_row_height = tmp; + /* Prepare array describing MCU composition */ + mcublks = compptr->MCU_data_units; + if (cinfo->data_units_in_MCU + mcublks > C_MAX_DATA_UNITS_IN_MCU) + ERREXIT(cinfo, JERR_BAD_MCU_SIZE); + while (mcublks-- > 0) { + cinfo->MCU_membership[cinfo->data_units_in_MCU++] = ci; + } + } + + } + + /* Convert restart specified in rows to actual MCU count. */ + /* Note that count must fit in 16 bits, so we provide limiting. */ + if (cinfo->restart_in_rows > 0) { + long nominal = (long) cinfo->restart_in_rows * (long) cinfo->MCUs_per_row; + cinfo->restart_interval = (unsigned int) MIN(nominal, 65535L); + } +} + + +/* + * Per-pass setup. + * This is called at the beginning of each pass. We determine which modules + * will be active during this pass and give them appropriate start_pass calls. + * We also set is_last_pass to indicate whether any more passes will be + * required. + */ + +METHODDEF(void) +prepare_for_pass (j_compress_ptr cinfo) +{ + /* j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; */ + my_master_ptr master = (my_master_ptr) cinfo->master; + + switch (master->pass_type) { + case main_pass: + /* Initial pass: will collect input data, and do either Huffman + * optimization or data output for the first scan. + */ + select_scan_parameters(cinfo); + per_scan_setup(cinfo); + if (! cinfo->raw_data_in) { + (*cinfo->cconvert->start_pass) (cinfo); + (*cinfo->downsample->start_pass) (cinfo); + (*cinfo->prep->start_pass) (cinfo, JBUF_PASS_THRU); + } + (*cinfo->codec->entropy_start_pass) (cinfo, cinfo->optimize_coding); + (*cinfo->codec->start_pass) (cinfo, + (master->total_passes > 1 ? + JBUF_SAVE_AND_PASS : JBUF_PASS_THRU)); + (*cinfo->main->start_pass) (cinfo, JBUF_PASS_THRU); + if (cinfo->optimize_coding) { + /* No immediate data output; postpone writing frame/scan headers */ + master->pub.call_pass_startup = FALSE; + } else { + /* Will write frame/scan headers at first jpeg_write_scanlines call */ + master->pub.call_pass_startup = TRUE; + } + break; +#ifdef ENTROPY_OPT_SUPPORTED + case huff_opt_pass: + /* Do Huffman optimization for a scan after the first one. */ + select_scan_parameters(cinfo); + per_scan_setup(cinfo); + if ((*cinfo->codec->need_optimization_pass) (cinfo)) { + (*cinfo->codec->entropy_start_pass) (cinfo, TRUE); + (*cinfo->codec->start_pass) (cinfo, JBUF_CRANK_DEST); + master->pub.call_pass_startup = FALSE; + break; + } + /* Special case: Huffman DC refinement scans need no Huffman table + * and therefore we can skip the optimization pass for them. + */ + master->pass_type = output_pass; + master->pass_number++; + /*FALLTHROUGH*/ +#endif + case output_pass: + /* Do a data-output pass. */ + /* We need not repeat per-scan setup if prior optimization pass did it. */ + if (! cinfo->optimize_coding) { + select_scan_parameters(cinfo); + per_scan_setup(cinfo); + } + (*cinfo->codec->entropy_start_pass) (cinfo, FALSE); + (*cinfo->codec->start_pass) (cinfo, JBUF_CRANK_DEST); + /* We emit frame/scan headers now */ + if (master->scan_number == 0) + (*cinfo->marker->write_frame_header) (cinfo); + (*cinfo->marker->write_scan_header) (cinfo); + master->pub.call_pass_startup = FALSE; + break; + default: + ERREXIT(cinfo, JERR_NOT_COMPILED); + } + + master->pub.is_last_pass = (master->pass_number == master->total_passes-1); + + /* Set up progress monitor's pass info if present */ + if (cinfo->progress != NULL) { + cinfo->progress->completed_passes = master->pass_number; + cinfo->progress->total_passes = master->total_passes; + } +} + + +/* + * Special start-of-pass hook. + * This is called by jpeg_write_scanlines if call_pass_startup is TRUE. + * In single-pass processing, we need this hook because we don't want to + * write frame/scan headers during jpeg_start_compress; we want to let the + * application write COM markers etc. between jpeg_start_compress and the + * jpeg_write_scanlines loop. + * In multi-pass processing, this routine is not used. + */ + +METHODDEF(void) +pass_startup (j_compress_ptr cinfo) +{ + cinfo->master->call_pass_startup = FALSE; /* reset flag so call only once */ + + (*cinfo->marker->write_frame_header) (cinfo); + (*cinfo->marker->write_scan_header) (cinfo); +} + + +/* + * Finish up at end of pass. + */ + +METHODDEF(void) +finish_pass_master (j_compress_ptr cinfo) +{ + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + my_master_ptr master = (my_master_ptr) cinfo->master; + + /* The entropy coder always needs an end-of-pass call, + * either to analyze statistics or to flush its output buffer. + */ + (*lossyc->pub.entropy_finish_pass) (cinfo); + + /* Update state for next pass */ + switch (master->pass_type) { + case main_pass: + /* next pass is either output of scan 0 (after optimization) + * or output of scan 1 (if no optimization). + */ + master->pass_type = output_pass; + if (! cinfo->optimize_coding) + master->scan_number++; + break; + case huff_opt_pass: + /* next pass is always output of current scan */ + master->pass_type = output_pass; + break; + case output_pass: + /* next pass is either optimization or output of next scan */ + if (cinfo->optimize_coding) + master->pass_type = huff_opt_pass; + master->scan_number++; + break; + } + + master->pass_number++; +} + + +/* + * Initialize master compression control. + */ + +GLOBAL(void) +jinit_c_master_control (j_compress_ptr cinfo, boolean transcode_only) +{ + my_master_ptr master; + + master = (my_master_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_comp_master)); + cinfo->master = (struct jpeg_comp_master *) master; + master->pub.prepare_for_pass = prepare_for_pass; + master->pub.pass_startup = pass_startup; + master->pub.finish_pass = finish_pass_master; + master->pub.is_last_pass = FALSE; + + cinfo->data_unit = cinfo->lossless ? 1 : DCTSIZE; + + /* Validate parameters, determine derived values */ + initial_setup(cinfo); + + if (cinfo->scan_info != NULL) { +#ifdef NEED_SCAN_SCRIPT + validate_script(cinfo); +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else { + cinfo->process = JPROC_SEQUENTIAL; + cinfo->num_scans = 1; + } + + if ((cinfo->arith_code == 0) && + (cinfo->process == JPROC_PROGRESSIVE || /* TEMPORARY HACK ??? */ + cinfo->process == JPROC_LOSSLESS)) + cinfo->optimize_coding = TRUE; /* assume default tables no good for + * progressive mode or lossless mode */ + + /* Initialize my private state */ + if (transcode_only) { + /* no main pass in transcoding */ + if (cinfo->optimize_coding) + master->pass_type = huff_opt_pass; + else + master->pass_type = output_pass; + } else { + /* for normal compression, first pass is always this type: */ + master->pass_type = main_pass; + } + master->scan_number = 0; + master->pass_number = 0; + if (cinfo->optimize_coding) + master->total_passes = cinfo->num_scans * 2; + else + master->total_passes = cinfo->num_scans; +} diff --git a/Utilities/ITK/Utilities/itkjpeg/jcodec.c b/Utilities/ITK/Utilities/itkjpeg/jcodec.c new file mode 100644 index 0000000000000000000000000000000000000000..9529caaa1bfc183c8f0fd25b7d1b6ad91704a586 --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jcodec.c @@ -0,0 +1,53 @@ +/* + * jcodec.c + * + * Copyright (C) 1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains utility functions for the JPEG codec(s). + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jlossy.h" +#include "jlossls.h" + + +/* + * Initialize the compression codec. + * This is called only once, during master selection. + */ + +GLOBAL(void) +jinit_c_codec (j_compress_ptr cinfo) +{ + if (cinfo->process == JPROC_LOSSLESS) { +#ifdef C_LOSSLESS_SUPPORTED + jinit_lossless_c_codec(cinfo); +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else + jinit_lossy_c_codec(cinfo); +} + + +/* + * Initialize the decompression codec. + * This is called only once, during master selection. + */ + +GLOBAL(void) +jinit_d_codec (j_decompress_ptr cinfo) +{ + if (cinfo->process == JPROC_LOSSLESS) { +#ifdef D_LOSSLESS_SUPPORTED + jinit_lossless_d_codec(cinfo); +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else + jinit_lossy_d_codec(cinfo); +} diff --git a/Utilities/ITK/Utilities/itkjpeg/jcomapi.c b/Utilities/ITK/Utilities/itkjpeg/jcomapi.c new file mode 100644 index 0000000000000000000000000000000000000000..2d45449a855f97303af981b8cb3f3e24cf93ad46 --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jcomapi.c @@ -0,0 +1,106 @@ +/* + * jcomapi.c + * + * Copyright (C) 1994-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains application interface routines that are used for both + * compression and decompression. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* + * Abort processing of a JPEG compression or decompression operation, + * but don't destroy the object itself. + * + * For this, we merely clean up all the nonpermanent memory pools. + * Note that temp files (virtual arrays) are not allowed to belong to + * the permanent pool, so we will be able to close all temp files here. + * Closing a data source or destination, if necessary, is the application's + * responsibility. + */ + +GLOBAL(void) +jpeg_abort (j_common_ptr cinfo) +{ + int pool; + + /* Do nothing if called on a not-initialized or destroyed JPEG object. */ + if (cinfo->mem == NULL) + return; + + /* Releasing pools in reverse order might help avoid fragmentation + * with some (brain-damaged) malloc libraries. + */ + for (pool = JPOOL_NUMPOOLS-1; pool > JPOOL_PERMANENT; pool--) { + (*cinfo->mem->free_pool) (cinfo, pool); + } + + /* Reset overall state for possible reuse of object */ + if (cinfo->is_decompressor) { + cinfo->global_state = DSTATE_START; + /* Try to keep application from accessing now-deleted marker list. + * A bit kludgy to do it here, but this is the most central place. + */ + ((j_decompress_ptr) cinfo)->marker_list = NULL; + } else { + cinfo->global_state = CSTATE_START; + } +} + + +/* + * Destruction of a JPEG object. + * + * Everything gets deallocated except the master jpeg_compress_struct itself + * and the error manager struct. Both of these are supplied by the application + * and must be freed, if necessary, by the application. (Often they are on + * the stack and so don't need to be freed anyway.) + * Closing a data source or destination, if necessary, is the application's + * responsibility. + */ + +GLOBAL(void) +jpeg_destroy (j_common_ptr cinfo) +{ + /* We need only tell the memory manager to release everything. */ + /* NB: mem pointer is NULL if memory mgr failed to initialize. */ + if (cinfo->mem != NULL) + (*cinfo->mem->self_destruct) (cinfo); + cinfo->mem = NULL; /* be safe if jpeg_destroy is called twice */ + cinfo->global_state = 0; /* mark it destroyed */ +} + + +/* + * Convenience routines for allocating quantization and Huffman tables. + * (Would jutils.c be a more reasonable place to put these?) + */ + +GLOBAL(JQUANT_TBL *) +jpeg_alloc_quant_table (j_common_ptr cinfo) +{ + JQUANT_TBL *tbl; + + tbl = (JQUANT_TBL *) + (*cinfo->mem->alloc_small) (cinfo, JPOOL_PERMANENT, SIZEOF(JQUANT_TBL)); + tbl->sent_table = FALSE; /* make sure this is false in any new table */ + return tbl; +} + + +GLOBAL(JHUFF_TBL *) +jpeg_alloc_huff_table (j_common_ptr cinfo) +{ + JHUFF_TBL *tbl; + + tbl = (JHUFF_TBL *) + (*cinfo->mem->alloc_small) (cinfo, JPOOL_PERMANENT, SIZEOF(JHUFF_TBL)); + tbl->sent_table = FALSE; /* make sure this is false in any new table */ + return tbl; +} diff --git a/Utilities/ITK/Utilities/itkjpeg/jconfig.doc b/Utilities/ITK/Utilities/itkjpeg/jconfig.doc new file mode 100644 index 0000000000000000000000000000000000000000..c18d1c064b77287209ab5d5d6b83e591b702df9f --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jconfig.doc @@ -0,0 +1,155 @@ +/* + * jconfig.doc + * + * Copyright (C) 1991-1994, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file documents the configuration options that are required to + * customize the JPEG software for a particular system. + * + * The actual configuration options for a particular installation are stored + * in jconfig.h. On many machines, jconfig.h can be generated automatically + * or copied from one of the "canned" jconfig files that we supply. But if + * you need to generate a jconfig.h file by hand, this file tells you how. + * + * DO NOT EDIT THIS FILE --- IT WON'T ACCOMPLISH ANYTHING. + * EDIT A COPY NAMED JCONFIG.H. + */ + + +/* + * These symbols indicate the properties of your machine or compiler. + * #define the symbol if yes, #undef it if no. + */ + +/* Does your compiler support function prototypes? + * (If not, you also need to use ansi2knr, see install.doc) + */ +#define HAVE_PROTOTYPES + +/* Does your compiler support the declaration "unsigned char" ? + * How about "unsigned short" ? + */ +#define HAVE_UNSIGNED_CHAR +#define HAVE_UNSIGNED_SHORT + +/* Define "void" as "char" if your compiler doesn't know about type void. + * NOTE: be sure to define void such that "void *" represents the most general + * pointer type, e.g., that returned by malloc(). + */ +/* #define void char */ + +/* Define "const" as empty if your compiler doesn't know the "const" keyword. + */ +/* #define const */ + +/* Define this if an ordinary "char" type is unsigned. + * If you're not sure, leaving it undefined will work at some cost in speed. + * If you defined HAVE_UNSIGNED_CHAR then the speed difference is minimal. + */ +#undef CHAR_IS_UNSIGNED + +/* Define this if your system has an ANSI-conforming <stddef.h> file. + */ +#define HAVE_STDDEF_H + +/* Define this if your system has an ANSI-conforming <stdlib.h> file. + */ +#define HAVE_STDLIB_H + +/* Define this if your system does not have an ANSI/SysV <string.h>, + * but does have a BSD-style <strings.h>. + */ +#undef NEED_BSD_STRINGS + +/* Define this if your system does not provide typedef size_t in any of the + * ANSI-standard places (stddef.h, stdlib.h, or stdio.h), but places it in + * <sys/types.h> instead. + */ +#undef NEED_SYS_TYPES_H + +/* For 80x86 machines, you need to define NEED_FAR_POINTERS, + * unless you are using a large-data memory model or 80386 flat-memory mode. + * On less brain-damaged CPUs this symbol must not be defined. + * (Defining this symbol causes large data structures to be referenced through + * "far" pointers and to be allocated with a special version of malloc.) + */ +#undef NEED_FAR_POINTERS + +/* Define this if your linker needs global names to be unique in less + * than the first 15 characters. + */ +#undef NEED_SHORT_EXTERNAL_NAMES + +/* Although a real ANSI C compiler can deal perfectly well with pointers to + * unspecified structures (see "incomplete types" in the spec), a few pre-ANSI + * and pseudo-ANSI compilers get confused. To keep one of these bozos happy, + * define INCOMPLETE_TYPES_BROKEN. This is not recommended unless you + * actually get "missing structure definition" warnings or errors while + * compiling the JPEG code. + */ +#undef INCOMPLETE_TYPES_BROKEN + + +/* + * The following options affect code selection within the JPEG library, + * but they don't need to be visible to applications using the library. + * To minimize application namespace pollution, the symbols won't be + * defined unless JPEG_INTERNALS has been defined. + */ + +#ifdef JPEG_INTERNALS + +/* Define this if your compiler implements ">>" on signed values as a logical + * (unsigned) shift; leave it undefined if ">>" is a signed (arithmetic) shift, + * which is the normal and rational definition. + */ +#undef RIGHT_SHIFT_IS_UNSIGNED + + +#endif /* JPEG_INTERNALS */ + + +/* + * The remaining options do not affect the JPEG library proper, + * but only the sample applications cjpeg/djpeg (see cjpeg.c, djpeg.c). + * Other applications can ignore these. + */ + +#ifdef JPEG_CJPEG_DJPEG + +/* These defines indicate which image (non-JPEG) file formats are allowed. */ + +#define BMP_SUPPORTED /* BMP image file format */ +#define GIF_SUPPORTED /* GIF image file format */ +#define PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */ +#undef RLE_SUPPORTED /* Utah RLE image file format */ +#define TARGA_SUPPORTED /* Targa image file format */ + +/* Define this if you want to name both input and output files on the command + * line, rather than using stdout and optionally stdin. You MUST do this if + * your system can't cope with binary I/O to stdin/stdout. See comments at + * head of cjpeg.c or djpeg.c. + */ +#undef TWO_FILE_COMMANDLINE + +/* Define this if your system needs explicit cleanup of temporary files. + * This is crucial under MS-DOS, where the temporary "files" may be areas + * of extended memory; on most other systems it's not as important. + */ +#undef NEED_SIGNAL_CATCHER + +/* By default, we open image files with fopen(...,"rb") or fopen(...,"wb"). + * This is necessary on systems that distinguish text files from binary files, + * and is harmless on most systems that don't. If you have one of the rare + * systems that complains about the "b" spec, define this symbol. + */ +#undef DONT_USE_B_MODE + +/* Define this if you want percent-done progress reports from cjpeg/djpeg. + */ +#undef PROGRESS_REPORT + + +#endif /* JPEG_CJPEG_DJPEG */ diff --git a/Utilities/ITK/Utilities/itkjpeg/jconfig.h.in b/Utilities/ITK/Utilities/itkjpeg/jconfig.h.in new file mode 100644 index 0000000000000000000000000000000000000000..66aaa74bf482db8902e87840310fa53b8bb0baca --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jconfig.h.in @@ -0,0 +1,69 @@ +/* jconfig.h --- source file edited by configure script */ +/* see jconfig.doc for explanations */ + +#define HAVE_PROTOTYPES +#define HAVE_UNSIGNED_CHAR +#define HAVE_UNSIGNED_SHORT +#undef void +#undef const +#undef CHAR_IS_UNSIGNED +#ifndef HAVE_STDDEF_H +#define HAVE_STDDEF_H +#endif +#ifndef HAVE_STDLIB_H +#define HAVE_STDLIB_H +#endif +#undef NEED_BSD_STRINGS +#undef NEED_SYS_TYPES_H +#undef NEED_FAR_POINTERS +#undef NEED_SHORT_EXTERNAL_NAMES +/* Define this if you get warnings about undefined structures. */ +#undef INCOMPLETE_TYPES_BROKEN + + +#if defined(_WIN32) && !(defined(__CYGWIN__) || defined(__MINGW32__)) +/* Define "boolean" as unsigned char, not int, per Windows custom */ +/* don't conflict if rpcndr.h already read; Note that the w32api headers + used by Cygwin and Mingw do not define "boolean", so jmorecfg.h + handles it later. */ +#ifndef __RPCNDR_H__ +typedef unsigned char boolean; +#endif +#define HAVE_BOOLEAN /* prevent jmorecfg.h from redefining it */ +#endif + +#ifdef JPEG_INTERNALS + +#undef RIGHT_SHIFT_IS_UNSIGNED +#define INLINE +/* These are for configuring the JPEG memory manager. */ +#undef DEFAULT_MAX_MEM +#undef NO_MKTEMP + +#endif /* JPEG_INTERNALS */ + +#ifdef JPEG_CJPEG_DJPEG + +#define BMP_SUPPORTED /* BMP image file format */ +#define GIF_SUPPORTED /* GIF image file format */ +#define PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */ +#undef RLE_SUPPORTED /* Utah RLE image file format */ +#define TARGA_SUPPORTED /* Targa image file format */ + +#undef TWO_FILE_COMMANDLINE +#undef NEED_SIGNAL_CATCHER +#undef DONT_USE_B_MODE + +/* Define this if you want percent-done progress reports from cjpeg/djpeg. */ +#undef PROGRESS_REPORT + +#endif /* JPEG_CJPEG_DJPEG */ + + +/* names mangling */ + +#include "@BITS_TYPE_JPEG_MANGLE_NAME@" + +#if defined(__BORLANDC__) +#pragma warn -8004 /* Disable "foo is assigned a value that is never used." */ +#endif diff --git a/Utilities/ITK/Utilities/itkjpeg/jcparam.c b/Utilities/ITK/Utilities/itkjpeg/jcparam.c new file mode 100644 index 0000000000000000000000000000000000000000..1f3d0022eaacf1e41d1dc9f094233c5282c46a20 --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jcparam.c @@ -0,0 +1,687 @@ +/* + * jcparam.c + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains optional default-setting code for the JPEG compressor. + * Applications do not have to use this file, but those that don't use it + * must know a lot more about the innards of the JPEG code. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* + * Quantization table setup routines + */ + +GLOBAL(void) +jpeg_add_quant_table (j_compress_ptr cinfo, int which_tbl, + const unsigned int *basic_table, + int scale_factor, boolean force_baseline) +/* Define a quantization table equal to the basic_table times + * a scale factor (given as a percentage). + * If force_baseline is TRUE, the computed quantization table entries + * are limited to 1..255 for JPEG baseline compatibility. + */ +{ + JQUANT_TBL ** qtblptr; + int i; + long temp; + + /* Safety check to ensure start_compress not called yet. */ + if (cinfo->global_state != CSTATE_START) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + if (which_tbl < 0 || which_tbl >= NUM_QUANT_TBLS) + ERREXIT1(cinfo, JERR_DQT_INDEX, which_tbl); + + qtblptr = & cinfo->quant_tbl_ptrs[which_tbl]; + + if (*qtblptr == NULL) + *qtblptr = jpeg_alloc_quant_table((j_common_ptr) cinfo); + + for (i = 0; i < DCTSIZE2; i++) { + temp = ((long) basic_table[i] * scale_factor + 50L) / 100L; + /* limit the values to the valid range */ + if (temp <= 0L) temp = 1L; + if (temp > 32767L) temp = 32767L; /* max quantizer needed for 12 bits */ + if (force_baseline && temp > 255L) + temp = 255L; /* limit to baseline range if requested */ + (*qtblptr)->quantval[i] = (UINT16) temp; + } + + /* Initialize sent_table FALSE so table will be written to JPEG file. */ + (*qtblptr)->sent_table = FALSE; +} + + +GLOBAL(void) +jpeg_set_linear_quality (j_compress_ptr cinfo, int scale_factor, + boolean force_baseline) +/* Set or change the 'quality' (quantization) setting, using default tables + * and a straight percentage-scaling quality scale. In most cases it's better + * to use jpeg_set_quality (below); this entry point is provided for + * applications that insist on a linear percentage scaling. + */ +{ + /* These are the sample quantization tables given in JPEG spec section K.1. + * The spec says that the values given produce "good" quality, and + * when divided by 2, "very good" quality. + */ + static const unsigned int std_luminance_quant_tbl[DCTSIZE2] = { + 16, 11, 10, 16, 24, 40, 51, 61, + 12, 12, 14, 19, 26, 58, 60, 55, + 14, 13, 16, 24, 40, 57, 69, 56, + 14, 17, 22, 29, 51, 87, 80, 62, + 18, 22, 37, 56, 68, 109, 103, 77, + 24, 35, 55, 64, 81, 104, 113, 92, + 49, 64, 78, 87, 103, 121, 120, 101, + 72, 92, 95, 98, 112, 100, 103, 99 + }; + static const unsigned int std_chrominance_quant_tbl[DCTSIZE2] = { + 17, 18, 24, 47, 99, 99, 99, 99, + 18, 21, 26, 66, 99, 99, 99, 99, + 24, 26, 56, 99, 99, 99, 99, 99, + 47, 66, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99 + }; + + /* Set up two quantization tables using the specified scaling */ + jpeg_add_quant_table(cinfo, 0, std_luminance_quant_tbl, + scale_factor, force_baseline); + jpeg_add_quant_table(cinfo, 1, std_chrominance_quant_tbl, + scale_factor, force_baseline); +} + + +GLOBAL(int) +jpeg_quality_scaling (int quality) +/* Convert a user-specified quality rating to a percentage scaling factor + * for an underlying quantization table, using our recommended scaling curve. + * The input 'quality' factor should be 0 (terrible) to 100 (very good). + */ +{ + /* Safety limit on quality factor. Convert 0 to 1 to avoid zero divide. */ + if (quality <= 0) quality = 1; + if (quality > 100) quality = 100; + + /* The basic table is used as-is (scaling 100) for a quality of 50. + * Qualities 50..100 are converted to scaling percentage 200 - 2*Q; + * note that at Q=100 the scaling is 0, which will cause jpeg_add_quant_table + * to make all the table entries 1 (hence, minimum quantization loss). + * Qualities 1..50 are converted to scaling percentage 5000/Q. + */ + if (quality < 50) + quality = 5000 / quality; + else + quality = 200 - quality*2; + + return quality; +} + + +GLOBAL(void) +jpeg_set_quality (j_compress_ptr cinfo, int quality, boolean force_baseline) +/* Set or change the 'quality' (quantization) setting, using default tables. + * This is the standard quality-adjusting entry point for typical user + * interfaces; only those who want detailed control over quantization tables + * would use the preceding three routines directly. + */ +{ + /* Convert user 0-100 rating to percentage scaling */ + quality = jpeg_quality_scaling(quality); + + /* Set up standard quality tables */ + jpeg_set_linear_quality(cinfo, quality, force_baseline); +} + + +/* + * Huffman table setup routines + */ + +LOCAL(void) +add_huff_table (j_compress_ptr cinfo, + JHUFF_TBL **htblptr, const UINT8 *bits, const UINT8 *val) +/* Define a Huffman table */ +{ + int nsymbols, len; + + if (*htblptr == NULL) + *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo); + + /* Copy the number-of-symbols-of-each-code-length counts */ + MEMCOPY((*htblptr)->bits, bits, SIZEOF((*htblptr)->bits)); + + /* Validate the counts. We do this here mainly so we can copy the right + * number of symbols from the val[] array, without risking marching off + * the end of memory. jchuff.c will do a more thorough test later. + */ + nsymbols = 0; + for (len = 1; len <= 16; len++) + nsymbols += bits[len]; + if (nsymbols < 1 || nsymbols > 256) + ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); + + MEMCOPY((*htblptr)->huffval, val, nsymbols * SIZEOF(UINT8)); + + /* Initialize sent_table FALSE so table will be written to JPEG file. */ + (*htblptr)->sent_table = FALSE; +} + + +LOCAL(void) +std_huff_tables (j_compress_ptr cinfo) +/* Set up the standard Huffman tables (cf. JPEG standard section K.3) */ +/* IMPORTANT: these are only valid for 8-bit data precision! */ +{ + static const UINT8 bits_dc_luminance[17] = + { /* 0-base */ 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 }; + static const UINT8 val_dc_luminance[] = + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }; + + static const UINT8 bits_dc_chrominance[17] = + { /* 0-base */ 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 }; + static const UINT8 val_dc_chrominance[] = + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }; + + static const UINT8 bits_ac_luminance[17] = + { /* 0-base */ 0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d }; + static const UINT8 val_ac_luminance[] = + { 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, + 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, + 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, + 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, + 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, + 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, + 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, + 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, + 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, + 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, + 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, + 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, + 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, + 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, + 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, + 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, + 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, + 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, + 0xf9, 0xfa }; + + static const UINT8 bits_ac_chrominance[17] = + { /* 0-base */ 0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77 }; + static const UINT8 val_ac_chrominance[] = + { 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, + 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, + 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, + 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, + 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, + 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, + 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, + 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, + 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, + 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, + 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, + 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, + 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, + 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, + 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, + 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, + 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, + 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, + 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, + 0xf9, 0xfa }; + + add_huff_table(cinfo, &cinfo->dc_huff_tbl_ptrs[0], + bits_dc_luminance, val_dc_luminance); + add_huff_table(cinfo, &cinfo->ac_huff_tbl_ptrs[0], + bits_ac_luminance, val_ac_luminance); + add_huff_table(cinfo, &cinfo->dc_huff_tbl_ptrs[1], + bits_dc_chrominance, val_dc_chrominance); + add_huff_table(cinfo, &cinfo->ac_huff_tbl_ptrs[1], + bits_ac_chrominance, val_ac_chrominance); +} + + +/* + * Default parameter setup for compression. + * + * Applications that don't choose to use this routine must do their + * own setup of all these parameters. Alternately, you can call this + * to establish defaults and then alter parameters selectively. This + * is the recommended approach since, if we add any new parameters, + * your code will still work (they'll be set to reasonable defaults). + */ + +GLOBAL(void) +jpeg_set_defaults (j_compress_ptr cinfo) +{ + int i; + + /* Safety check to ensure start_compress not called yet. */ + if (cinfo->global_state != CSTATE_START) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + /* Allocate comp_info array large enough for maximum component count. + * Array is made permanent in case application wants to compress + * multiple images at same param settings. + */ + if (cinfo->comp_info == NULL) + cinfo->comp_info = (jpeg_component_info *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + MAX_COMPONENTS * SIZEOF(jpeg_component_info)); + + /* Initialize everything not dependent on the color space */ + + cinfo->lossless = FALSE; + cinfo->data_precision = BITS_IN_JSAMPLE; + /* Set up two quantization tables using default quality of 75 */ + jpeg_set_quality(cinfo, 75, TRUE); + /* Set up two Huffman tables */ + std_huff_tables(cinfo); + + /* Initialize default arithmetic coding conditioning */ + for (i = 0; i < NUM_ARITH_TBLS; i++) { + cinfo->arith_dc_L[i] = 0; + cinfo->arith_dc_U[i] = 1; + cinfo->arith_ac_K[i] = 5; + } + + /* Default is no multiple-scan output */ + cinfo->scan_info = NULL; + cinfo->num_scans = 0; + + /* Expect normal source image, not raw downsampled data */ + cinfo->raw_data_in = FALSE; + + /* Use Huffman coding, not arithmetic coding, by default */ + cinfo->arith_code = FALSE; + + /* By default, don't do extra passes to optimize entropy coding */ + cinfo->optimize_coding = FALSE; + /* The standard Huffman tables are only valid for 8-bit data precision. + * If the precision is higher, force optimization on so that usable + * tables will be computed. This test can be removed if default tables + * are supplied that are valid for the desired precision. + */ + if (cinfo->data_precision > 8) + cinfo->optimize_coding = TRUE; + + /* By default, use the simpler non-cosited sampling alignment */ + cinfo->CCIR601_sampling = FALSE; + + /* No input smoothing */ + cinfo->smoothing_factor = 0; + + /* DCT algorithm preference */ + cinfo->dct_method = JDCT_DEFAULT; + + /* No restart markers */ + cinfo->restart_interval = 0; + cinfo->restart_in_rows = 0; + + /* Fill in default JFIF marker parameters. Note that whether the marker + * will actually be written is determined by jpeg_set_colorspace. + * + * By default, the library emits JFIF version code 1.01. + * An application that wants to emit JFIF 1.02 extension markers should set + * JFIF_minor_version to 2. We could probably get away with just defaulting + * to 1.02, but there may still be some decoders in use that will complain + * about that; saying 1.01 should minimize compatibility problems. + */ + cinfo->JFIF_major_version = 1; /* Default JFIF version = 1.01 */ + cinfo->JFIF_minor_version = 1; + cinfo->density_unit = 0; /* Pixel size is unknown by default */ + cinfo->X_density = 1; /* Pixel aspect ratio is square by default */ + cinfo->Y_density = 1; + + /* Choose JPEG colorspace based on input space, set defaults accordingly */ + + jpeg_default_colorspace(cinfo); +} + + +/* + * Select an appropriate JPEG colorspace for in_color_space. + */ + +GLOBAL(void) +jpeg_default_colorspace (j_compress_ptr cinfo) +{ + if (cinfo->lossless) + jpeg_set_colorspace(cinfo, cinfo->in_color_space); + else { /* lossy */ + switch (cinfo->in_color_space) { + case JCS_GRAYSCALE: + jpeg_set_colorspace(cinfo, JCS_GRAYSCALE); + break; + case JCS_RGB: + jpeg_set_colorspace(cinfo, JCS_YCbCr); + break; + case JCS_YCbCr: + jpeg_set_colorspace(cinfo, JCS_YCbCr); + break; + case JCS_CMYK: + jpeg_set_colorspace(cinfo, JCS_CMYK); /* By default, no translation */ + break; + case JCS_YCCK: + jpeg_set_colorspace(cinfo, JCS_YCCK); + break; + case JCS_UNKNOWN: + jpeg_set_colorspace(cinfo, JCS_UNKNOWN); + break; + default: + ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE); + } + } +} + + +/* + * Set the JPEG colorspace, and choose colorspace-dependent default values. + */ + +GLOBAL(void) +jpeg_set_colorspace (j_compress_ptr cinfo, J_COLOR_SPACE colorspace) +{ + jpeg_component_info * compptr; + int ci; + +#define SET_COMP(index,id,hsamp,vsamp,quant,dctbl,actbl) \ + (compptr = &cinfo->comp_info[index], \ + compptr->component_id = (id), \ + compptr->h_samp_factor = (hsamp), \ + compptr->v_samp_factor = (vsamp), \ + compptr->quant_tbl_no = (quant), \ + compptr->dc_tbl_no = (dctbl), \ + compptr->ac_tbl_no = (actbl) ) + + /* Safety check to ensure start_compress not called yet. */ + if (cinfo->global_state != CSTATE_START) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + /* For all colorspaces, we use Q and Huff tables 0 for luminance components, + * tables 1 for chrominance components. + */ + + cinfo->jpeg_color_space = colorspace; + + cinfo->write_JFIF_header = FALSE; /* No marker for non-JFIF colorspaces */ + cinfo->write_Adobe_marker = FALSE; /* write no Adobe marker by default */ + + switch (colorspace) { + case JCS_GRAYSCALE: + cinfo->write_JFIF_header = TRUE; /* Write a JFIF marker */ + cinfo->num_components = 1; + /* JFIF specifies component ID 1 */ + SET_COMP(0, 1, 1,1, 0, 0,0); + break; + case JCS_RGB: + cinfo->write_Adobe_marker = TRUE; /* write Adobe marker to flag RGB */ + cinfo->num_components = 3; + SET_COMP(0, 0x52 /* 'R' */, 1,1, 0, 0,0); + SET_COMP(1, 0x47 /* 'G' */, 1,1, 0, 0,0); + SET_COMP(2, 0x42 /* 'B' */, 1,1, 0, 0,0); + break; + case JCS_YCbCr: + cinfo->write_JFIF_header = TRUE; /* Write a JFIF marker */ + cinfo->num_components = 3; + /* JFIF specifies component IDs 1,2,3 */ + if (cinfo->lossless) { + SET_COMP(0, 1, 1,1, 0, 0,0); + SET_COMP(1, 2, 1,1, 1, 1,1); + SET_COMP(2, 3, 1,1, 1, 1,1); + } else { /* lossy */ + /* We default to 2x2 subsamples of chrominance */ + SET_COMP(0, 1, 2,2, 0, 0,0); + SET_COMP(1, 2, 1,1, 1, 1,1); + SET_COMP(2, 3, 1,1, 1, 1,1); + } + break; + case JCS_CMYK: + cinfo->write_Adobe_marker = TRUE; /* write Adobe marker to flag CMYK */ + cinfo->num_components = 4; + SET_COMP(0, 0x43 /* 'C' */, 1,1, 0, 0,0); + SET_COMP(1, 0x4D /* 'M' */, 1,1, 0, 0,0); + SET_COMP(2, 0x59 /* 'Y' */, 1,1, 0, 0,0); + SET_COMP(3, 0x4B /* 'K' */, 1,1, 0, 0,0); + break; + case JCS_YCCK: + cinfo->write_Adobe_marker = TRUE; /* write Adobe marker to flag YCCK */ + cinfo->num_components = 4; + if (cinfo->lossless) { + SET_COMP(0, 1, 1,1, 0, 0,0); + SET_COMP(1, 2, 1,1, 1, 1,1); + SET_COMP(2, 3, 1,1, 1, 1,1); + SET_COMP(3, 4, 1,1, 0, 0,0); + } else { /* lossy */ + SET_COMP(0, 1, 2,2, 0, 0,0); + SET_COMP(1, 2, 1,1, 1, 1,1); + SET_COMP(2, 3, 1,1, 1, 1,1); + SET_COMP(3, 4, 2,2, 0, 0,0); + } + break; + case JCS_UNKNOWN: + cinfo->num_components = cinfo->input_components; + if (cinfo->num_components < 1 || cinfo->num_components > MAX_COMPONENTS) + ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components, + MAX_COMPONENTS); + for (ci = 0; ci < cinfo->num_components; ci++) { + SET_COMP(ci, ci, 1,1, 0, 0,0); + } + break; + default: + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + } +} + + +#ifdef C_PROGRESSIVE_SUPPORTED + +LOCAL(jpeg_scan_info *) +fill_scans (jpeg_scan_info * scanptr, int ncomps, + int Ss, int Se, int Ah, int Al) +/* Support routine: generate one scan for each component */ +{ + int ci; + + for (ci = 0; ci < ncomps; ci++) { + scanptr->comps_in_scan = 1; + scanptr->component_index[0] = ci; + scanptr->Ss = Ss; + scanptr->Se = Se; + scanptr->Ah = Ah; + scanptr->Al = Al; + scanptr++; + } + return scanptr; +} + + +LOCAL(jpeg_scan_info *) +fill_a_scan (jpeg_scan_info * scanptr, int ci, + int Ss, int Se, int Ah, int Al) +/* Support routine: generate one scan for specified component */ +{ + scanptr->comps_in_scan = 1; + scanptr->component_index[0] = ci; + scanptr->Ss = Ss; + scanptr->Se = Se; + scanptr->Ah = Ah; + scanptr->Al = Al; + scanptr++; + return scanptr; +} + +LOCAL(jpeg_scan_info *) +fill_dc_scans (jpeg_scan_info * scanptr, int ncomps, int Ah, int Al) +/* Support routine: generate interleaved DC scan if possible, else N scans */ +{ + int ci; + + if (ncomps <= MAX_COMPS_IN_SCAN) { + /* Single interleaved DC scan */ + scanptr->comps_in_scan = ncomps; + for (ci = 0; ci < ncomps; ci++) + scanptr->component_index[ci] = ci; + scanptr->Ss = scanptr->Se = 0; + scanptr->Ah = Ah; + scanptr->Al = Al; + scanptr++; + } else { + /* Noninterleaved DC scan for each component */ + scanptr = fill_scans(scanptr, ncomps, 0, 0, Ah, Al); + } + return scanptr; +} + + +/* + * Create a recommended progressive-JPEG script. + * cinfo->num_components and cinfo->jpeg_color_space must be correct. + */ + +GLOBAL(void) +jpeg_simple_progression (j_compress_ptr cinfo) +{ + int ncomps = cinfo->num_components; + int nscans; + jpeg_scan_info * scanptr; + + /* Safety check to ensure start_compress not called yet. */ + if (cinfo->global_state != CSTATE_START) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + /* Figure space needed for script. Calculation must match code below! */ + if (ncomps == 3 && cinfo->jpeg_color_space == JCS_YCbCr) { + /* Custom script for YCbCr color images. */ + nscans = 10; + } else { + /* All-purpose script for other color spaces. */ + if (ncomps > MAX_COMPS_IN_SCAN) + nscans = 6 * ncomps; /* 2 DC + 4 AC scans per component */ + else + nscans = 2 + 4 * ncomps; /* 2 DC scans; 4 AC scans per component */ + } + + /* Allocate space for script. + * We need to put it in the permanent pool in case the application performs + * multiple compressions without changing the settings. To avoid a memory + * leak if jpeg_simple_progression is called repeatedly for the same JPEG + * object, we try to re-use previously allocated space, and we allocate + * enough space to handle YCbCr even if initially asked for grayscale. + */ + if (cinfo->script_space == NULL || cinfo->script_space_size < nscans) { + cinfo->script_space_size = MAX(nscans, 10); + cinfo->script_space = (jpeg_scan_info *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + cinfo->script_space_size * SIZEOF(jpeg_scan_info)); + } + scanptr = cinfo->script_space; + cinfo->scan_info = scanptr; + cinfo->num_scans = nscans; + + if (ncomps == 3 && cinfo->jpeg_color_space == JCS_YCbCr) { + /* Custom script for YCbCr color images. */ + /* Initial DC scan */ + scanptr = fill_dc_scans(scanptr, ncomps, 0, 1); + /* Initial AC scan: get some luma data out in a hurry */ + scanptr = fill_a_scan(scanptr, 0, 1, 5, 0, 2); + /* Chroma data is too small to be worth expending many scans on */ + scanptr = fill_a_scan(scanptr, 2, 1, 63, 0, 1); + scanptr = fill_a_scan(scanptr, 1, 1, 63, 0, 1); + /* Complete spectral selection for luma AC */ + scanptr = fill_a_scan(scanptr, 0, 6, 63, 0, 2); + /* Refine next bit of luma AC */ + scanptr = fill_a_scan(scanptr, 0, 1, 63, 2, 1); + /* Finish DC successive approximation */ + scanptr = fill_dc_scans(scanptr, ncomps, 1, 0); + /* Finish AC successive approximation */ + scanptr = fill_a_scan(scanptr, 2, 1, 63, 1, 0); + scanptr = fill_a_scan(scanptr, 1, 1, 63, 1, 0); + /* Luma bottom bit comes last since it's usually largest scan */ + scanptr = fill_a_scan(scanptr, 0, 1, 63, 1, 0); + } else { + /* All-purpose script for other color spaces. */ + /* Successive approximation first pass */ + scanptr = fill_dc_scans(scanptr, ncomps, 0, 1); + scanptr = fill_scans(scanptr, ncomps, 1, 5, 0, 2); + scanptr = fill_scans(scanptr, ncomps, 6, 63, 0, 2); + /* Successive approximation second pass */ + scanptr = fill_scans(scanptr, ncomps, 1, 63, 2, 1); + /* Successive approximation final pass */ + scanptr = fill_dc_scans(scanptr, ncomps, 1, 0); + scanptr = fill_scans(scanptr, ncomps, 1, 63, 1, 0); + } +} + +#endif /* C_PROGRESSIVE_SUPPORTED */ + + +#ifdef C_LOSSLESS_SUPPORTED + +/* + * Create a single-entry lossless-JPEG script containing all components. + * cinfo->num_components must be correct. + */ + +GLOBAL(void) +jpeg_simple_lossless (j_compress_ptr cinfo, int predictor, int point_transform) +{ + int ncomps = cinfo->num_components; + int nscans = 1; + int ci; + jpeg_scan_info * scanptr; + + /* Safety check to ensure start_compress not called yet. */ + if (cinfo->global_state != CSTATE_START) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + cinfo->lossless = TRUE; + + /* Set jpeg_color_space. */ + jpeg_default_colorspace(cinfo); + + /* Check to ensure that all components will fit in one scan. */ + if (cinfo->num_components > MAX_COMPS_IN_SCAN) + ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components, + MAX_COMPS_IN_SCAN); + + /* Allocate space for script. + * We need to put it in the permanent pool in case the application performs + * multiple compressions without changing the settings. To avoid a memory + * leak if jpeg_simple_lossless is called repeatedly for the same JPEG + * object, we try to re-use previously allocated space. + */ + if (cinfo->script_space == NULL || cinfo->script_space_size < nscans) { + cinfo->script_space_size = nscans; + cinfo->script_space = (jpeg_scan_info *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + cinfo->script_space_size * SIZEOF(jpeg_scan_info)); + } + scanptr = cinfo->script_space; + cinfo->scan_info = scanptr; + cinfo->num_scans = nscans; + + /* Fill the script. */ + scanptr->comps_in_scan = ncomps; + for (ci = 0; ci < ncomps; ci++) + scanptr->component_index[ci] = ci; + scanptr->Ss = predictor; + scanptr->Se = 0; + scanptr->Ah = 0; + scanptr->Al = point_transform; +} + +#endif /* C_LOSSLESS_SUPPORTED */ diff --git a/Utilities/ITK/Utilities/itkjpeg/jcphuff.c b/Utilities/ITK/Utilities/itkjpeg/jcphuff.c new file mode 100644 index 0000000000000000000000000000000000000000..63b9e461e3dbf2b468879e3192ae7604c5ee3ff7 --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jcphuff.c @@ -0,0 +1,848 @@ +/* + * jcphuff.c + * + * Copyright (C) 1995-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains Huffman entropy encoding routines for progressive JPEG. + * + * We do not support output suspension in this module, since the library + * currently does not allow multiple-scan files to be written with output + * suspension. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jlossy.h" /* Private declarations for lossy codec */ +#include "jchuff.h" /* Declarations shared with jc*huff.c */ + +#ifdef C_PROGRESSIVE_SUPPORTED + +/* Expanded entropy encoder object for progressive Huffman encoding. */ + +typedef struct { + /* Mode flag: TRUE for optimization, FALSE for actual data output */ + boolean gather_statistics; + + /* Bit-level coding status. + * next_output_byte/free_in_buffer are local copies of cinfo->dest fields. + */ + JOCTET * next_output_byte; /* => next byte to write in buffer */ + size_t free_in_buffer; /* # of byte spaces remaining in buffer */ + INT32 put_buffer; /* current bit-accumulation buffer */ + int put_bits; /* # of bits now in it */ + j_compress_ptr cinfo; /* link to cinfo (needed for dump_buffer) */ + + /* Coding status for DC components */ + int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */ + + /* Coding status for AC components */ + int ac_tbl_no; /* the table number of the single component */ + unsigned int EOBRUN; /* run length of EOBs */ + unsigned int BE; /* # of buffered correction bits before MCU */ + char * bit_buffer; /* buffer for correction bits (1 per char) */ + /* packing correction bits tightly would save some space but cost time... */ + + unsigned int restarts_to_go; /* MCUs left in this restart interval */ + int next_restart_num; /* next restart number to write (0-7) */ + + /* Pointers to derived tables (these workspaces have image lifespan). + * Since any one scan codes only DC or only AC, we only need one set + * of tables, not one for DC and one for AC. + */ + c_derived_tbl * derived_tbls[NUM_HUFF_TBLS]; + + /* Statistics tables for optimization; again, one set is enough */ + long * count_ptrs[NUM_HUFF_TBLS]; +} phuff_entropy_encoder; + +typedef phuff_entropy_encoder * phuff_entropy_ptr; + +/* MAX_CORR_BITS is the number of bits the AC refinement correction-bit + * buffer can hold. Larger sizes may slightly improve compression, but + * 1000 is already well into the realm of overkill. + * The minimum safe size is 64 bits. + */ + +#define MAX_CORR_BITS 1000 /* Max # of correction bits I can buffer */ + +/* IRIGHT_SHIFT is like RIGHT_SHIFT, but works on int rather than INT32. + * We assume that int right shift is unsigned if INT32 right shift is, + * which should be safe. + */ + +#ifdef RIGHT_SHIFT_IS_UNSIGNED +#define ISHIFT_TEMPS int ishift_temp; +#define IRIGHT_SHIFT(x,shft) \ + ((ishift_temp = (x)) < 0 ? \ + (ishift_temp >> (shft)) | ((~0) << (16-(shft))) : \ + (ishift_temp >> (shft))) +#else +#define ISHIFT_TEMPS +#define IRIGHT_SHIFT(x,shft) ((x) >> (shft)) +#endif + +/* Forward declarations */ +METHODDEF(boolean) encode_mcu_DC_first JPP((j_compress_ptr cinfo, + JBLOCKROW *MCU_data)); +METHODDEF(boolean) encode_mcu_AC_first JPP((j_compress_ptr cinfo, + JBLOCKROW *MCU_data)); +METHODDEF(boolean) encode_mcu_DC_refine JPP((j_compress_ptr cinfo, + JBLOCKROW *MCU_data)); +METHODDEF(boolean) encode_mcu_AC_refine JPP((j_compress_ptr cinfo, + JBLOCKROW *MCU_data)); +METHODDEF(void) finish_pass_phuff JPP((j_compress_ptr cinfo)); +METHODDEF(void) finish_pass_gather_phuff JPP((j_compress_ptr cinfo)); + + +/* + * Initialize for a Huffman-compressed scan using progressive JPEG. + */ + +METHODDEF(void) +start_pass_phuff (j_compress_ptr cinfo, boolean gather_statistics) +{ + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + phuff_entropy_ptr entropy = (phuff_entropy_ptr) lossyc->entropy_private; + boolean is_DC_band; + int ci, tbl; + jpeg_component_info * compptr; + + entropy->cinfo = cinfo; + entropy->gather_statistics = gather_statistics; + + is_DC_band = (cinfo->Ss == 0); + + /* We assume jcmaster.c already validated the scan parameters. */ + + /* Select execution routines */ + if (cinfo->Ah == 0) { + if (is_DC_band) + lossyc->entropy_encode_mcu = encode_mcu_DC_first; + else + lossyc->entropy_encode_mcu = encode_mcu_AC_first; + } else { + if (is_DC_band) + lossyc->entropy_encode_mcu = encode_mcu_DC_refine; + else { + lossyc->entropy_encode_mcu = encode_mcu_AC_refine; + /* AC refinement needs a correction bit buffer */ + if (entropy->bit_buffer == NULL) + entropy->bit_buffer = (char *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + MAX_CORR_BITS * SIZEOF(char)); + } + } + if (gather_statistics) + lossyc->pub.entropy_finish_pass = finish_pass_gather_phuff; + else + lossyc->pub.entropy_finish_pass = finish_pass_phuff; + + /* Only DC coefficients may be interleaved, so cinfo->comps_in_scan = 1 + * for AC coefficients. + */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + /* Initialize DC predictions to 0 */ + entropy->last_dc_val[ci] = 0; + /* Get table index */ + if (is_DC_band) { + if (cinfo->Ah != 0) /* DC refinement needs no table */ + continue; + tbl = compptr->dc_tbl_no; + } else { + entropy->ac_tbl_no = tbl = compptr->ac_tbl_no; + } + if (gather_statistics) { + /* Check for invalid table index */ + /* (make_c_derived_tbl does this in the other path) */ + if (tbl < 0 || tbl >= NUM_HUFF_TBLS) + ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tbl); + /* Allocate and zero the statistics tables */ + /* Note that jpeg_gen_optimal_table expects 257 entries in each table! */ + if (entropy->count_ptrs[tbl] == NULL) + entropy->count_ptrs[tbl] = (long *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + 257 * SIZEOF(long)); + MEMZERO(entropy->count_ptrs[tbl], 257 * SIZEOF(long)); + } else { + /* Compute derived values for Huffman table */ + /* We may do this more than once for a table, but it's not expensive */ + jpeg_make_c_derived_tbl(cinfo, is_DC_band, tbl, + & entropy->derived_tbls[tbl]); + } + } + + /* Initialize AC stuff */ + entropy->EOBRUN = 0; + entropy->BE = 0; + + /* Initialize bit buffer to empty */ + entropy->put_buffer = 0; + entropy->put_bits = 0; + + /* Initialize restart stuff */ + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num = 0; +} + + +/* Outputting bytes to the file. + * NB: these must be called only when actually outputting, + * that is, entropy->gather_statistics == FALSE. + */ + +/* Emit a byte */ +#define emit_byte(entropy,val) \ + { *(entropy)->next_output_byte++ = (JOCTET) (val); \ + if (--(entropy)->free_in_buffer == 0) \ + dump_buffer(entropy); } + + +LOCAL(void) +dump_buffer (phuff_entropy_ptr entropy) +/* Empty the output buffer; we do not support suspension in this module. */ +{ + struct jpeg_destination_mgr * dest = entropy->cinfo->dest; + + if (! (*dest->empty_output_buffer) (entropy->cinfo)) + ERREXIT(entropy->cinfo, JERR_CANT_SUSPEND); + /* After a successful buffer dump, must reset buffer pointers */ + entropy->next_output_byte = dest->next_output_byte; + entropy->free_in_buffer = dest->free_in_buffer; +} + + +/* Outputting bits to the file */ + +/* Only the right 24 bits of put_buffer are used; the valid bits are + * left-justified in this part. At most 16 bits can be passed to emit_bits + * in one call, and we never retain more than 7 bits in put_buffer + * between calls, so 24 bits are sufficient. + */ + +INLINE +LOCAL(void) +emit_bits (phuff_entropy_ptr entropy, unsigned int code, int size) +/* Emit some bits, unless we are in gather mode */ +{ + /* This routine is heavily used, so it's worth coding tightly. */ + register INT32 put_buffer = (INT32) code; + register int put_bits = entropy->put_bits; + + /* if size is 0, caller used an invalid Huffman table entry */ + if (size == 0) + ERREXIT(entropy->cinfo, JERR_HUFF_MISSING_CODE); + + if (entropy->gather_statistics) + return; /* do nothing if we're only getting stats */ + + put_buffer &= (((INT32) 1)<<size) - 1; /* mask off any extra bits in code */ + + put_bits += size; /* new number of bits in buffer */ + + put_buffer <<= 24 - put_bits; /* align incoming bits */ + + put_buffer |= entropy->put_buffer; /* and merge with old buffer contents */ + + while (put_bits >= 8) { + int c = (int) ((put_buffer >> 16) & 0xFF); + + emit_byte(entropy, c); + if (c == 0xFF) { /* need to stuff a zero byte? */ + emit_byte(entropy, 0); + } + put_buffer <<= 8; + put_bits -= 8; + } + + entropy->put_buffer = put_buffer; /* update variables */ + entropy->put_bits = put_bits; +} + + +LOCAL(void) +flush_bits (phuff_entropy_ptr entropy) +{ + emit_bits(entropy, 0x7F, 7); /* fill any partial byte with ones */ + entropy->put_buffer = 0; /* and reset bit-buffer to empty */ + entropy->put_bits = 0; +} + + +/* + * Emit (or just count) a Huffman symbol. + */ + +INLINE +LOCAL(void) +emit_symbol (phuff_entropy_ptr entropy, int tbl_no, int symbol) +{ + if (entropy->gather_statistics) + entropy->count_ptrs[tbl_no][symbol]++; + else { + c_derived_tbl * tbl = entropy->derived_tbls[tbl_no]; + emit_bits(entropy, tbl->ehufco[symbol], tbl->ehufsi[symbol]); + } +} + + +/* + * Emit bits from a correction bit buffer. + */ + +LOCAL(void) +emit_buffered_bits (phuff_entropy_ptr entropy, char * bufstart, + unsigned int nbits) +{ + if (entropy->gather_statistics) + return; /* no real work */ + + while (nbits > 0) { + emit_bits(entropy, (unsigned int) (*bufstart), 1); + bufstart++; + nbits--; + } +} + + +/* + * Emit any pending EOBRUN symbol. + */ + +LOCAL(void) +emit_eobrun (phuff_entropy_ptr entropy) +{ + register int temp, nbits; + + if (entropy->EOBRUN > 0) { /* if there is any pending EOBRUN */ + temp = entropy->EOBRUN; + nbits = 0; + while ((temp >>= 1)) + nbits++; + /* safety check: shouldn't happen given limited correction-bit buffer */ + if (nbits > 14) + ERREXIT(entropy->cinfo, JERR_HUFF_MISSING_CODE); + + emit_symbol(entropy, entropy->ac_tbl_no, nbits << 4); + if (nbits) + emit_bits(entropy, entropy->EOBRUN, nbits); + + entropy->EOBRUN = 0; + + /* Emit any buffered correction bits */ + emit_buffered_bits(entropy, entropy->bit_buffer, entropy->BE); + entropy->BE = 0; + } +} + + +/* + * Emit a restart marker & resynchronize predictions. + */ + +LOCAL(void) +emit_restart (phuff_entropy_ptr entropy, int restart_num) +{ + int ci; + + emit_eobrun(entropy); + + if (! entropy->gather_statistics) { + flush_bits(entropy); + emit_byte(entropy, 0xFF); + emit_byte(entropy, JPEG_RST0 + restart_num); + } + + if (entropy->cinfo->Ss == 0) { + /* Re-initialize DC predictions to 0 */ + for (ci = 0; ci < entropy->cinfo->comps_in_scan; ci++) + entropy->last_dc_val[ci] = 0; + } else { + /* Re-initialize all AC-related fields to 0 */ + entropy->EOBRUN = 0; + entropy->BE = 0; + } +} + + +/* + * MCU encoding for DC initial scan (either spectral selection, + * or first pass of successive approximation). + */ + +METHODDEF(boolean) +encode_mcu_DC_first (j_compress_ptr cinfo, JBLOCKROW *MCU_data) +{ + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + phuff_entropy_ptr entropy = (phuff_entropy_ptr) lossyc->entropy_private; + register int temp, temp2; + register int nbits; + int blkn, ci; + int Al = cinfo->Al; + JBLOCKROW block; + jpeg_component_info * compptr; + ISHIFT_TEMPS + + entropy->next_output_byte = cinfo->dest->next_output_byte; + entropy->free_in_buffer = cinfo->dest->free_in_buffer; + + /* Emit restart marker if needed */ + if (cinfo->restart_interval) + if (entropy->restarts_to_go == 0) + emit_restart(entropy, entropy->next_restart_num); + + /* Encode the MCU data blocks */ + for (blkn = 0; blkn < cinfo->data_units_in_MCU; blkn++) { + block = MCU_data[blkn]; + ci = cinfo->MCU_membership[blkn]; + compptr = cinfo->cur_comp_info[ci]; + + /* Compute the DC value after the required point transform by Al. + * This is simply an arithmetic right shift. + */ + temp2 = IRIGHT_SHIFT((int) ((*block)[0]), Al); + + /* DC differences are figured on the point-transformed values. */ + temp = temp2 - entropy->last_dc_val[ci]; + entropy->last_dc_val[ci] = temp2; + + /* Encode the DC coefficient difference per section G.1.2.1 */ + temp2 = temp; + if (temp < 0) { + temp = -temp; /* temp is abs value of input */ + /* For a negative input, want temp2 = bitwise complement of abs(input) */ + /* This code assumes we are on a two's complement machine */ + temp2--; + } + + /* Find the number of bits needed for the magnitude of the coefficient */ + nbits = 0; + while (temp) { + nbits++; + temp >>= 1; + } + /* Check for out-of-range coefficient values. + * Since we're encoding a difference, the range limit is twice as much. + */ + if (nbits > MAX_COEF_BITS+1) + ERREXIT(cinfo, JERR_BAD_DCT_COEF); + + /* Count/emit the Huffman-coded symbol for the number of bits */ + emit_symbol(entropy, compptr->dc_tbl_no, nbits); + + /* Emit that number of bits of the value, if positive, */ + /* or the complement of its magnitude, if negative. */ + if (nbits) /* emit_bits rejects calls with size 0 */ + emit_bits(entropy, (unsigned int) temp2, nbits); + } + + cinfo->dest->next_output_byte = entropy->next_output_byte; + cinfo->dest->free_in_buffer = entropy->free_in_buffer; + + /* Update restart-interval state too */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) { + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num++; + entropy->next_restart_num &= 7; + } + entropy->restarts_to_go--; + } + + return TRUE; +} + + +/* + * MCU encoding for AC initial scan (either spectral selection, + * or first pass of successive approximation). + */ + +METHODDEF(boolean) +encode_mcu_AC_first (j_compress_ptr cinfo, JBLOCKROW *MCU_data) +{ + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + phuff_entropy_ptr entropy = (phuff_entropy_ptr) lossyc->entropy_private; + register int temp, temp2; + register int nbits; + register int r, k; + int Se = cinfo->Se; + int Al = cinfo->Al; + JBLOCKROW block; + + entropy->next_output_byte = cinfo->dest->next_output_byte; + entropy->free_in_buffer = cinfo->dest->free_in_buffer; + + /* Emit restart marker if needed */ + if (cinfo->restart_interval) + if (entropy->restarts_to_go == 0) + emit_restart(entropy, entropy->next_restart_num); + + /* Encode the MCU data block */ + block = MCU_data[0]; + + /* Encode the AC coefficients per section G.1.2.2, fig. G.3 */ + + r = 0; /* r = run length of zeros */ + + for (k = cinfo->Ss; k <= Se; k++) { + if ((temp = (*block)[jpeg_natural_order[k]]) == 0) { + r++; + continue; + } + /* We must apply the point transform by Al. For AC coefficients this + * is an integer division with rounding towards 0. To do this portably + * in C, we shift after obtaining the absolute value; so the code is + * interwoven with finding the abs value (temp) and output bits (temp2). + */ + if (temp < 0) { + temp = -temp; /* temp is abs value of input */ + temp >>= Al; /* apply the point transform */ + /* For a negative coef, want temp2 = bitwise complement of abs(coef) */ + temp2 = ~temp; + } else { + temp >>= Al; /* apply the point transform */ + temp2 = temp; + } + /* Watch out for case that nonzero coef is zero after point transform */ + if (temp == 0) { + r++; + continue; + } + + /* Emit any pending EOBRUN */ + if (entropy->EOBRUN > 0) + emit_eobrun(entropy); + /* if run length > 15, must emit special run-length-16 codes (0xF0) */ + while (r > 15) { + emit_symbol(entropy, entropy->ac_tbl_no, 0xF0); + r -= 16; + } + + /* Find the number of bits needed for the magnitude of the coefficient */ + nbits = 1; /* there must be at least one 1 bit */ + while ((temp >>= 1)) + nbits++; + /* Check for out-of-range coefficient values */ + if (nbits > MAX_COEF_BITS) + ERREXIT(cinfo, JERR_BAD_DCT_COEF); + + /* Count/emit Huffman symbol for run length / number of bits */ + emit_symbol(entropy, entropy->ac_tbl_no, (r << 4) + nbits); + + /* Emit that number of bits of the value, if positive, */ + /* or the complement of its magnitude, if negative. */ + emit_bits(entropy, (unsigned int) temp2, nbits); + + r = 0; /* reset zero run length */ + } + + if (r > 0) { /* If there are trailing zeroes, */ + entropy->EOBRUN++; /* count an EOB */ + if (entropy->EOBRUN == 0x7FFF) + emit_eobrun(entropy); /* force it out to avoid overflow */ + } + + cinfo->dest->next_output_byte = entropy->next_output_byte; + cinfo->dest->free_in_buffer = entropy->free_in_buffer; + + /* Update restart-interval state too */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) { + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num++; + entropy->next_restart_num &= 7; + } + entropy->restarts_to_go--; + } + + return TRUE; +} + + +/* + * MCU encoding for DC successive approximation refinement scan. + * Note: we assume such scans can be multi-component, although the spec + * is not very clear on the point. + */ + +METHODDEF(boolean) +encode_mcu_DC_refine (j_compress_ptr cinfo, JBLOCKROW *MCU_data) +{ + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + phuff_entropy_ptr entropy = (phuff_entropy_ptr) lossyc->entropy_private; + register int temp; + int blkn; + int Al = cinfo->Al; + JBLOCKROW block; + + entropy->next_output_byte = cinfo->dest->next_output_byte; + entropy->free_in_buffer = cinfo->dest->free_in_buffer; + + /* Emit restart marker if needed */ + if (cinfo->restart_interval) + if (entropy->restarts_to_go == 0) + emit_restart(entropy, entropy->next_restart_num); + + /* Encode the MCU data blocks */ + for (blkn = 0; blkn < cinfo->data_units_in_MCU; blkn++) { + block = MCU_data[blkn]; + + /* We simply emit the Al'th bit of the DC coefficient value. */ + temp = (*block)[0]; + emit_bits(entropy, (unsigned int) (temp >> Al), 1); + } + + cinfo->dest->next_output_byte = entropy->next_output_byte; + cinfo->dest->free_in_buffer = entropy->free_in_buffer; + + /* Update restart-interval state too */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) { + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num++; + entropy->next_restart_num &= 7; + } + entropy->restarts_to_go--; + } + + return TRUE; +} + + +/* + * MCU encoding for AC successive approximation refinement scan. + */ + +METHODDEF(boolean) +encode_mcu_AC_refine (j_compress_ptr cinfo, JBLOCKROW *MCU_data) +{ + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + phuff_entropy_ptr entropy = (phuff_entropy_ptr) lossyc->entropy_private; + register int temp; + register int r, k; + int EOB; + char *BR_buffer; + unsigned int BR; + int Se = cinfo->Se; + int Al = cinfo->Al; + JBLOCKROW block; + int absvalues[DCTSIZE2]; + + entropy->next_output_byte = cinfo->dest->next_output_byte; + entropy->free_in_buffer = cinfo->dest->free_in_buffer; + + /* Emit restart marker if needed */ + if (cinfo->restart_interval) + if (entropy->restarts_to_go == 0) + emit_restart(entropy, entropy->next_restart_num); + + /* Encode the MCU data block */ + block = MCU_data[0]; + + /* It is convenient to make a pre-pass to determine the transformed + * coefficients' absolute values and the EOB position. + */ + EOB = 0; + for (k = cinfo->Ss; k <= Se; k++) { + temp = (*block)[jpeg_natural_order[k]]; + /* We must apply the point transform by Al. For AC coefficients this + * is an integer division with rounding towards 0. To do this portably + * in C, we shift after obtaining the absolute value. + */ + if (temp < 0) + temp = -temp; /* temp is abs value of input */ + temp >>= Al; /* apply the point transform */ + absvalues[k] = temp; /* save abs value for main pass */ + if (temp == 1) + EOB = k; /* EOB = index of last newly-nonzero coef */ + } + + /* Encode the AC coefficients per section G.1.2.3, fig. G.7 */ + + r = 0; /* r = run length of zeros */ + BR = 0; /* BR = count of buffered bits added now */ + BR_buffer = entropy->bit_buffer + entropy->BE; /* Append bits to buffer */ + + for (k = cinfo->Ss; k <= Se; k++) { + if ((temp = absvalues[k]) == 0) { + r++; + continue; + } + + /* Emit any required ZRLs, but not if they can be folded into EOB */ + while (r > 15 && k <= EOB) { + /* emit any pending EOBRUN and the BE correction bits */ + emit_eobrun(entropy); + /* Emit ZRL */ + emit_symbol(entropy, entropy->ac_tbl_no, 0xF0); + r -= 16; + /* Emit buffered correction bits that must be associated with ZRL */ + emit_buffered_bits(entropy, BR_buffer, BR); + BR_buffer = entropy->bit_buffer; /* BE bits are gone now */ + BR = 0; + } + + /* If the coef was previously nonzero, it only needs a correction bit. + * NOTE: a straight translation of the spec's figure G.7 would suggest + * that we also need to test r > 15. But if r > 15, we can only get here + * if k > EOB, which implies that this coefficient is not 1. + */ + if (temp > 1) { + /* The correction bit is the next bit of the absolute value. */ + BR_buffer[BR++] = (char) (temp & 1); + continue; + } + + /* Emit any pending EOBRUN and the BE correction bits */ + emit_eobrun(entropy); + + /* Count/emit Huffman symbol for run length / number of bits */ + emit_symbol(entropy, entropy->ac_tbl_no, (r << 4) + 1); + + /* Emit output bit for newly-nonzero coef */ + temp = ((*block)[jpeg_natural_order[k]] < 0) ? 0 : 1; + emit_bits(entropy, (unsigned int) temp, 1); + + /* Emit buffered correction bits that must be associated with this code */ + emit_buffered_bits(entropy, BR_buffer, BR); + BR_buffer = entropy->bit_buffer; /* BE bits are gone now */ + BR = 0; + r = 0; /* reset zero run length */ + } + + if (r > 0 || BR > 0) { /* If there are trailing zeroes, */ + entropy->EOBRUN++; /* count an EOB */ + entropy->BE += BR; /* concat my correction bits to older ones */ + /* We force out the EOB if we risk either: + * 1. overflow of the EOB counter; + * 2. overflow of the correction bit buffer during the next MCU. + */ + if (entropy->EOBRUN == 0x7FFF || entropy->BE > (MAX_CORR_BITS-DCTSIZE2+1)) + emit_eobrun(entropy); + } + + cinfo->dest->next_output_byte = entropy->next_output_byte; + cinfo->dest->free_in_buffer = entropy->free_in_buffer; + + /* Update restart-interval state too */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) { + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num++; + entropy->next_restart_num &= 7; + } + entropy->restarts_to_go--; + } + + return TRUE; +} + + +/* + * Finish up at the end of a Huffman-compressed progressive scan. + */ + +METHODDEF(void) +finish_pass_phuff (j_compress_ptr cinfo) +{ + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + phuff_entropy_ptr entropy = (phuff_entropy_ptr) lossyc->entropy_private; + + entropy->next_output_byte = cinfo->dest->next_output_byte; + entropy->free_in_buffer = cinfo->dest->free_in_buffer; + + /* Flush out any buffered data */ + emit_eobrun(entropy); + flush_bits(entropy); + + cinfo->dest->next_output_byte = entropy->next_output_byte; + cinfo->dest->free_in_buffer = entropy->free_in_buffer; +} + + +/* + * Finish up a statistics-gathering pass and create the new Huffman tables. + */ + +METHODDEF(void) +finish_pass_gather_phuff (j_compress_ptr cinfo) +{ + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + phuff_entropy_ptr entropy = (phuff_entropy_ptr) lossyc->entropy_private; + boolean is_DC_band; + int ci, tbl; + jpeg_component_info * compptr; + JHUFF_TBL **htblptr; + boolean did[NUM_HUFF_TBLS]; + + /* Flush out buffered data (all we care about is counting the EOB symbol) */ + emit_eobrun(entropy); + + is_DC_band = (cinfo->Ss == 0); + + /* It's important not to apply jpeg_gen_optimal_table more than once + * per table, because it clobbers the input frequency counts! + */ + MEMZERO(did, SIZEOF(did)); + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + if (is_DC_band) { + if (cinfo->Ah != 0) /* DC refinement needs no table */ + continue; + tbl = compptr->dc_tbl_no; + } else { + tbl = compptr->ac_tbl_no; + } + if (! did[tbl]) { + if (is_DC_band) + htblptr = & cinfo->dc_huff_tbl_ptrs[tbl]; + else + htblptr = & cinfo->ac_huff_tbl_ptrs[tbl]; + if (*htblptr == NULL) + *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo); + jpeg_gen_optimal_table(cinfo, *htblptr, entropy->count_ptrs[tbl]); + did[tbl] = TRUE; + } + } +} + + +METHODDEF(boolean) +need_optimization_pass (j_compress_ptr cinfo) +{ + return (cinfo->Ss != 0 || cinfo->Ah == 0); +} + + +/* + * Module initialization routine for progressive Huffman entropy encoding. + */ + +GLOBAL(void) +jinit_phuff_encoder (j_compress_ptr cinfo) +{ + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + phuff_entropy_ptr entropy; + int i; + + entropy = (phuff_entropy_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(phuff_entropy_encoder)); + lossyc->entropy_private = (struct jpeg_entropy_encoder *) entropy; + lossyc->pub.entropy_start_pass = start_pass_phuff; + lossyc->pub.need_optimization_pass = need_optimization_pass; + + /* Mark tables unallocated */ + for (i = 0; i < NUM_HUFF_TBLS; i++) { + entropy->derived_tbls[i] = NULL; + entropy->count_ptrs[i] = NULL; + } + entropy->bit_buffer = NULL; /* needed only in AC refinement scan */ +} + +#endif /* C_PROGRESSIVE_SUPPORTED */ diff --git a/Utilities/ITK/Utilities/itkjpeg/jcpred.c b/Utilities/ITK/Utilities/itkjpeg/jcpred.c new file mode 100644 index 0000000000000000000000000000000000000000..293596c1b9053e9605940631f7ca24282942fcaf --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jcpred.c @@ -0,0 +1,301 @@ +/* + * jcpred.c + * + * Copyright (C) 1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains sample differencing for lossless JPEG. + * + * In order to avoid paying the performance penalty of having to check the + * predictor being used and the row being processed for each call of the + * undifferencer, and to promote optimization, we have separate differencing + * functions for each case. + * + * We are able to avoid duplicating source code by implementing the predictors + * and differencers as macros. Each of the differencing functions are + * simply wrappers around a DIFFERENCE macro with the appropriate PREDICTOR + * macro passed as an argument. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jlossls.h" /* Private declarations for lossless codec */ + + +#ifdef C_LOSSLESS_SUPPORTED + +/* Private predictor object */ + +typedef struct { + /* MCU-rows left in the restart interval for each component */ + unsigned int restart_rows_to_go[MAX_COMPONENTS]; +} c_predictor; + +typedef c_predictor * c_pred_ptr; + +/* Forward declarations */ +LOCAL(void) reset_predictor + JPP((j_compress_ptr cinfo, int ci)); +METHODDEF(void) start_pass + JPP((j_compress_ptr cinfo)); + + +/* Predictor for the first column of the first row: 2^(P-Pt-1) */ +#define INITIAL_PREDICTORx (1 << (cinfo->data_precision - cinfo->Al - 1)) + +/* Predictor for the first column of the remaining rows: Rb */ +#define INITIAL_PREDICTOR2 GETJSAMPLE(prev_row[0]) + + +/* + * 1-Dimensional differencer routine. + * + * This macro implements the 1-D horizontal predictor (1). INITIAL_PREDICTOR + * is used as the special case predictor for the first column, which must be + * either INITIAL_PREDICTOR2 or INITIAL_PREDICTORx. The remaining samples + * use PREDICTOR1. + */ + +#define DIFFERENCE_1D(INITIAL_PREDICTOR) \ + j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec; \ + c_pred_ptr pred = (c_pred_ptr) losslsc->pred_private; \ + boolean restart = FALSE; \ + unsigned int xindex; \ + int samp, Ra; \ + \ + samp = GETJSAMPLE(input_buf[0]); \ + diff_buf[0] = samp - INITIAL_PREDICTOR; \ + \ + for (xindex = 1; xindex < width; xindex++) { \ + Ra = samp; \ + samp = GETJSAMPLE(input_buf[xindex]); \ + diff_buf[xindex] = samp - PREDICTOR1; \ + } \ + \ + /* Account for restart interval (no-op if not using restarts) */ \ + if (cinfo->restart_interval) { \ + if (--(pred->restart_rows_to_go[ci]) == 0) { \ + reset_predictor(cinfo, ci); \ + restart = TRUE; \ + } \ + } + + +/* + * 2-Dimensional differencer routine. + * + * This macro implements the 2-D horizontal predictors (#2-7). PREDICTOR2 is + * used as the special case predictor for the first column. The remaining + * samples use PREDICTOR, which is a function of Ra, Rb, Rc. + * + * Because prev_row and output_buf may point to the same storage area (in an + * interleaved image with Vi=1, for example), we must take care to buffer Rb/Rc + * before writing the current reconstructed sample value into output_buf. + */ + +#define DIFFERENCE_2D(PREDICTOR) \ + j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec; \ + c_pred_ptr pred = (c_pred_ptr) losslsc->pred_private; \ + unsigned int xindex; \ + int samp, Ra, Rb, Rc; \ + \ + Rb = GETJSAMPLE(prev_row[0]); \ + samp = GETJSAMPLE(input_buf[0]); \ + diff_buf[0] = samp - PREDICTOR2; \ + \ + for (xindex = 1; xindex < width; xindex++) { \ + Rc = Rb; \ + Rb = GETJSAMPLE(prev_row[xindex]); \ + Ra = samp; \ + samp = GETJSAMPLE(input_buf[xindex]); \ + diff_buf[xindex] = samp - PREDICTOR; \ + } \ + \ + /* Account for restart interval (no-op if not using restarts) */ \ + if (cinfo->restart_interval) { \ + if (--pred->restart_rows_to_go[ci] == 0) \ + reset_predictor(cinfo, ci); \ + } + + +/* + * Differencers for the all rows but the first in a scan or restart interval. + * The first sample in the row is differenced using the vertical + * predictor (2). The rest of the samples are differenced using the + * predictor specified in the scan header. + */ + +METHODDEF(void) +jpeg_difference1(j_compress_ptr cinfo, int ci, + JSAMPROW input_buf, JSAMPROW prev_row, + JDIFFROW diff_buf, JDIMENSION width) +{ + DIFFERENCE_1D(INITIAL_PREDICTOR2); +} + +METHODDEF(void) +jpeg_difference2(j_compress_ptr cinfo, int ci, + JSAMPROW input_buf, JSAMPROW prev_row, + JDIFFROW diff_buf, JDIMENSION width) +{ + DIFFERENCE_2D(PREDICTOR2); +} + +METHODDEF(void) +jpeg_difference3(j_compress_ptr cinfo, int ci, + JSAMPROW input_buf, JSAMPROW prev_row, + JDIFFROW diff_buf, JDIMENSION width) +{ + DIFFERENCE_2D(PREDICTOR3); +} + +METHODDEF(void) +jpeg_difference4(j_compress_ptr cinfo, int ci, + JSAMPROW input_buf, JSAMPROW prev_row, + JDIFFROW diff_buf, JDIMENSION width) +{ + DIFFERENCE_2D(PREDICTOR4); +} + +METHODDEF(void) +jpeg_difference5(j_compress_ptr cinfo, int ci, + JSAMPROW input_buf, JSAMPROW prev_row, + JDIFFROW diff_buf, JDIMENSION width) +{ + SHIFT_TEMPS + DIFFERENCE_2D(PREDICTOR5); +} + +METHODDEF(void) +jpeg_difference6(j_compress_ptr cinfo, int ci, + JSAMPROW input_buf, JSAMPROW prev_row, + JDIFFROW diff_buf, JDIMENSION width) +{ + SHIFT_TEMPS + DIFFERENCE_2D(PREDICTOR6); +} + +METHODDEF(void) +jpeg_difference7(j_compress_ptr cinfo, int ci, + JSAMPROW input_buf, JSAMPROW prev_row, + JDIFFROW diff_buf, JDIMENSION width) +{ + SHIFT_TEMPS + DIFFERENCE_2D(PREDICTOR7); +} + + +/* + * Differencer for the first row in a scan or restart interval. The first + * sample in the row is differenced using the special predictor constant + * x=2^(P-Pt-1). The rest of the samples are differenced using the + * 1-D horizontal predictor (1). + */ + +METHODDEF(void) +jpeg_difference_first_row(j_compress_ptr cinfo, int ci, + JSAMPROW input_buf, JSAMPROW prev_row, + JDIFFROW diff_buf, JDIMENSION width) +{ + DIFFERENCE_1D(INITIAL_PREDICTORx); + (void)prev_row; + + /* + * Now that we have differenced the first row, we want to use the + * differencer which corresponds to the predictor specified in the + * scan header. + * + * Note that we don't to do this if we have just reset the predictor + * for a new restart interval. + */ + if (!restart) { + switch (cinfo->Ss) { + case 1: + losslsc->predict_difference[ci] = jpeg_difference1; + break; + case 2: + losslsc->predict_difference[ci] = jpeg_difference2; + break; + case 3: + losslsc->predict_difference[ci] = jpeg_difference3; + break; + case 4: + losslsc->predict_difference[ci] = jpeg_difference4; + break; + case 5: + losslsc->predict_difference[ci] = jpeg_difference5; + break; + case 6: + losslsc->predict_difference[ci] = jpeg_difference6; + break; + case 7: + losslsc->predict_difference[ci] = jpeg_difference7; + break; + } + } +} + +/* + * Reset predictor at the start of a pass or restart interval. + */ + +LOCAL(void) +reset_predictor (j_compress_ptr cinfo, int ci) +{ + j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec; + c_pred_ptr pred = (c_pred_ptr) losslsc->pred_private; + + /* Initialize restart counter */ + pred->restart_rows_to_go[ci] = + cinfo->restart_interval / cinfo->MCUs_per_row; + + /* Set difference function to first row function */ + losslsc->predict_difference[ci] = jpeg_difference_first_row; +} + + +/* + * Initialize for an input processing pass. + */ + +METHODDEF(void) +start_pass (j_compress_ptr cinfo) +{ + /* j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec; */ + /* c_pred_ptr pred = (c_pred_ptr) losslsc->pred_private; */ + int ci; + + /* Check that the restart interval is an integer multiple of the number + * of MCU in an MCU-row. + */ + if (cinfo->restart_interval % cinfo->MCUs_per_row != 0) + ERREXIT2(cinfo, JERR_BAD_RESTART, + cinfo->restart_interval, cinfo->MCUs_per_row); + + /* Set predictors for start of pass */ + for (ci = 0; ci < cinfo->num_components; ci++) + reset_predictor(cinfo, ci); +} + + +/* + * Module initialization routine for the differencer. + */ + +GLOBAL(void) +jinit_differencer (j_compress_ptr cinfo) +{ + j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec; + c_pred_ptr pred; + + pred = (c_pred_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(c_predictor)); + losslsc->pred_private = (void *) pred; + losslsc->predict_start_pass = start_pass; +} + +#endif /* C_LOSSLESS_SUPPORTED */ + diff --git a/Utilities/ITK/Utilities/itkjpeg/jcprepct.c b/Utilities/ITK/Utilities/itkjpeg/jcprepct.c new file mode 100644 index 0000000000000000000000000000000000000000..188548194a2f13949691437a81dad4d28503199e --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jcprepct.c @@ -0,0 +1,354 @@ +/* + * jcprepct.c + * + * Copyright (C) 1994-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the compression preprocessing controller. + * This controller manages the color conversion, downsampling, + * and edge expansion steps. + * + * Most of the complexity here is associated with buffering input rows + * as required by the downsampler. See the comments at the head of + * jcsample.c for the downsampler's needs. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* At present, jcsample.c can request context rows only for smoothing. + * In the future, we might also need context rows for CCIR601 sampling + * or other more-complex downsampling procedures. The code to support + * context rows should be compiled only if needed. + */ +#ifdef INPUT_SMOOTHING_SUPPORTED +#define CONTEXT_ROWS_SUPPORTED +#endif + + +/* + * For the simple (no-context-row) case, we just need to buffer one + * row group's worth of pixels for the downsampling step. At the bottom of + * the image, we pad to a full row group by replicating the last pixel row. + * The downsampler's last output row is then replicated if needed to pad + * out to a full iMCU row. + * + * When providing context rows, we must buffer three row groups' worth of + * pixels. Three row groups are physically allocated, but the row pointer + * arrays are made five row groups high, with the extra pointers above and + * below "wrapping around" to point to the last and first real row groups. + * This allows the downsampler to access the proper context rows. + * At the top and bottom of the image, we create dummy context rows by + * copying the first or last real pixel row. This copying could be avoided + * by pointer hacking as is done in jdmainct.c, but it doesn't seem worth the + * trouble on the compression side. + */ + + +/* Private buffer controller object */ + +typedef struct { + struct jpeg_c_prep_controller pub; /* public fields */ + + /* Downsampling input buffer. This buffer holds color-converted data + * until we have enough to do a downsample step. + */ + JSAMPARRAY color_buf[MAX_COMPONENTS]; + + JDIMENSION rows_to_go; /* counts rows remaining in source image */ + int next_buf_row; /* index of next row to store in color_buf */ + +#ifdef CONTEXT_ROWS_SUPPORTED /* only needed for context case */ + int this_row_group; /* starting row index of group to process */ + int next_buf_stop; /* downsample when we reach this index */ +#endif +} my_prep_controller; + +typedef my_prep_controller * my_prep_ptr; + + +/* + * Initialize for a processing pass. + */ + +METHODDEF(void) +start_pass_prep (j_compress_ptr cinfo, J_BUF_MODE pass_mode) +{ + my_prep_ptr prep = (my_prep_ptr) cinfo->prep; + + if (pass_mode != JBUF_PASS_THRU) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + + /* Initialize total-height counter for detecting bottom of image */ + prep->rows_to_go = cinfo->image_height; + /* Mark the conversion buffer empty */ + prep->next_buf_row = 0; +#ifdef CONTEXT_ROWS_SUPPORTED + /* Preset additional state variables for context mode. + * These aren't used in non-context mode, so we needn't test which mode. + */ + prep->this_row_group = 0; + /* Set next_buf_stop to stop after two row groups have been read in. */ + prep->next_buf_stop = 2 * cinfo->max_v_samp_factor; +#endif +} + + +/* + * Expand an image vertically from height input_rows to height output_rows, + * by duplicating the bottom row. + */ + +LOCAL(void) +expand_bottom_edge (JSAMPARRAY image_data, JDIMENSION num_cols, + int input_rows, int output_rows) +{ + register int row; + + for (row = input_rows; row < output_rows; row++) { + jcopy_sample_rows(image_data, input_rows-1, image_data, row, + 1, num_cols); + } +} + + +/* + * Process some data in the simple no-context case. + * + * Preprocessor output data is counted in "row groups". A row group + * is defined to be v_samp_factor sample rows of each component. + * Downsampling will produce this much data from each max_v_samp_factor + * input rows. + */ + +METHODDEF(void) +pre_process_data (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JDIMENSION *in_row_ctr, + JDIMENSION in_rows_avail, + JSAMPIMAGE output_buf, JDIMENSION *out_row_group_ctr, + JDIMENSION out_row_groups_avail) +{ + my_prep_ptr prep = (my_prep_ptr) cinfo->prep; + int numrows, ci; + JDIMENSION inrows; + jpeg_component_info * compptr; + + while (*in_row_ctr < in_rows_avail && + *out_row_group_ctr < out_row_groups_avail) { + /* Do color conversion to fill the conversion buffer. */ + inrows = in_rows_avail - *in_row_ctr; + numrows = cinfo->max_v_samp_factor - prep->next_buf_row; + numrows = (int) MIN((JDIMENSION) numrows, inrows); + (*cinfo->cconvert->color_convert) (cinfo, input_buf + *in_row_ctr, + prep->color_buf, + (JDIMENSION) prep->next_buf_row, + numrows); + *in_row_ctr += numrows; + prep->next_buf_row += numrows; + prep->rows_to_go -= numrows; + /* If at bottom of image, pad to fill the conversion buffer. */ + if (prep->rows_to_go == 0 && + prep->next_buf_row < cinfo->max_v_samp_factor) { + for (ci = 0; ci < cinfo->num_components; ci++) { + expand_bottom_edge(prep->color_buf[ci], cinfo->image_width, + prep->next_buf_row, cinfo->max_v_samp_factor); + } + prep->next_buf_row = cinfo->max_v_samp_factor; + } + /* If we've filled the conversion buffer, empty it. */ + if (prep->next_buf_row == cinfo->max_v_samp_factor) { + (*cinfo->downsample->downsample) (cinfo, + prep->color_buf, (JDIMENSION) 0, + output_buf, *out_row_group_ctr); + prep->next_buf_row = 0; + (*out_row_group_ctr)++; + } + /* If at bottom of image, pad the output to a full iMCU height. + * Note we assume the caller is providing a one-iMCU-height output buffer! + */ + if (prep->rows_to_go == 0 && + *out_row_group_ctr < out_row_groups_avail) { + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + expand_bottom_edge(output_buf[ci], + compptr->width_in_data_units * cinfo->data_unit, + (int) (*out_row_group_ctr * compptr->v_samp_factor), + (int) (out_row_groups_avail * compptr->v_samp_factor)); + } + *out_row_group_ctr = out_row_groups_avail; + break; /* can exit outer loop without test */ + } + } +} + + +#ifdef CONTEXT_ROWS_SUPPORTED + +/* + * Process some data in the context case. + */ + +METHODDEF(void) +pre_process_context (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JDIMENSION *in_row_ctr, + JDIMENSION in_rows_avail, + JSAMPIMAGE output_buf, JDIMENSION *out_row_group_ctr, + JDIMENSION out_row_groups_avail) +{ + my_prep_ptr prep = (my_prep_ptr) cinfo->prep; + int numrows, ci; + int buf_height = cinfo->max_v_samp_factor * 3; + JDIMENSION inrows; + + while (*out_row_group_ctr < out_row_groups_avail) { + if (*in_row_ctr < in_rows_avail) { + /* Do color conversion to fill the conversion buffer. */ + inrows = in_rows_avail - *in_row_ctr; + numrows = prep->next_buf_stop - prep->next_buf_row; + numrows = (int) MIN((JDIMENSION) numrows, inrows); + (*cinfo->cconvert->color_convert) (cinfo, input_buf + *in_row_ctr, + prep->color_buf, + (JDIMENSION) prep->next_buf_row, + numrows); + /* Pad at top of image, if first time through */ + if (prep->rows_to_go == cinfo->image_height) { + for (ci = 0; ci < cinfo->num_components; ci++) { + int row; + for (row = 1; row <= cinfo->max_v_samp_factor; row++) { + jcopy_sample_rows(prep->color_buf[ci], 0, + prep->color_buf[ci], -row, + 1, cinfo->image_width); + } + } + } + *in_row_ctr += numrows; + prep->next_buf_row += numrows; + prep->rows_to_go -= numrows; + } else { + /* Return for more data, unless we are at the bottom of the image. */ + if (prep->rows_to_go != 0) + break; + /* When at bottom of image, pad to fill the conversion buffer. */ + if (prep->next_buf_row < prep->next_buf_stop) { + for (ci = 0; ci < cinfo->num_components; ci++) { + expand_bottom_edge(prep->color_buf[ci], cinfo->image_width, + prep->next_buf_row, prep->next_buf_stop); + } + prep->next_buf_row = prep->next_buf_stop; + } + } + /* If we've gotten enough data, downsample a row group. */ + if (prep->next_buf_row == prep->next_buf_stop) { + (*cinfo->downsample->downsample) (cinfo, + prep->color_buf, + (JDIMENSION) prep->this_row_group, + output_buf, *out_row_group_ctr); + (*out_row_group_ctr)++; + /* Advance pointers with wraparound as necessary. */ + prep->this_row_group += cinfo->max_v_samp_factor; + if (prep->this_row_group >= buf_height) + prep->this_row_group = 0; + if (prep->next_buf_row >= buf_height) + prep->next_buf_row = 0; + prep->next_buf_stop = prep->next_buf_row + cinfo->max_v_samp_factor; + } + } +} + + +/* + * Create the wrapped-around downsampling input buffer needed for context mode. + */ + +LOCAL(void) +create_context_buffer (j_compress_ptr cinfo) +{ + my_prep_ptr prep = (my_prep_ptr) cinfo->prep; + int rgroup_height = cinfo->max_v_samp_factor; + int ci, i; + jpeg_component_info * compptr; + JSAMPARRAY true_buffer, fake_buffer; + + /* Grab enough space for fake row pointers for all the components; + * we need five row groups' worth of pointers for each component. + */ + fake_buffer = (JSAMPARRAY) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (cinfo->num_components * 5 * rgroup_height) * + SIZEOF(JSAMPROW)); + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Allocate the actual buffer space (3 row groups) for this component. + * We make the buffer wide enough to allow the downsampler to edge-expand + * horizontally within the buffer, if it so chooses. + */ + true_buffer = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (JDIMENSION) (((long) compptr->width_in_data_units * cinfo->data_unit * + cinfo->max_h_samp_factor) / compptr->h_samp_factor), + (JDIMENSION) (3 * rgroup_height)); + /* Copy true buffer row pointers into the middle of the fake row array */ + MEMCOPY(fake_buffer + rgroup_height, true_buffer, + 3 * rgroup_height * SIZEOF(JSAMPROW)); + /* Fill in the above and below wraparound pointers */ + for (i = 0; i < rgroup_height; i++) { + fake_buffer[i] = true_buffer[2 * rgroup_height + i]; + fake_buffer[4 * rgroup_height + i] = true_buffer[i]; + } + prep->color_buf[ci] = fake_buffer + rgroup_height; + fake_buffer += 5 * rgroup_height; /* point to space for next component */ + } +} + +#endif /* CONTEXT_ROWS_SUPPORTED */ + + +/* + * Initialize preprocessing controller. + */ + +GLOBAL(void) +jinit_c_prep_controller (j_compress_ptr cinfo, boolean need_full_buffer) +{ + my_prep_ptr prep; + int ci; + jpeg_component_info * compptr; + + if (need_full_buffer) /* safety check */ + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + + prep = (my_prep_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_prep_controller)); + cinfo->prep = (struct jpeg_c_prep_controller *) prep; + prep->pub.start_pass = start_pass_prep; + + /* Allocate the color conversion buffer. + * We make the buffer wide enough to allow the downsampler to edge-expand + * horizontally within the buffer, if it so chooses. + */ + if (cinfo->downsample->need_context_rows) { + /* Set up to provide context rows */ +#ifdef CONTEXT_ROWS_SUPPORTED + prep->pub.pre_process_data = pre_process_context; + create_context_buffer(cinfo); +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else { + /* No context, just make it tall enough for one row group */ + prep->pub.pre_process_data = pre_process_data; + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + prep->color_buf[ci] = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (JDIMENSION) (((long) compptr->width_in_data_units * cinfo->data_unit * + cinfo->max_h_samp_factor) / compptr->h_samp_factor), + (JDIMENSION) cinfo->max_v_samp_factor); + } + } +} diff --git a/Utilities/ITK/Utilities/itkjpeg/jcsample.c b/Utilities/ITK/Utilities/itkjpeg/jcsample.c new file mode 100644 index 0000000000000000000000000000000000000000..5b5fb79e4a086b4dc113fa0a4faea9da193a635c --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jcsample.c @@ -0,0 +1,520 @@ +/* + * jcsample.c + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains downsampling routines. + * + * Downsampling input data is counted in "row groups". A row group + * is defined to be max_v_samp_factor pixel rows of each component, + * from which the downsampler produces v_samp_factor sample rows. + * A single row group is processed in each call to the downsampler module. + * + * The downsampler is responsible for edge-expansion of its output data + * to fill an integral number of DCT blocks horizontally. The source buffer + * may be modified if it is helpful for this purpose (the source buffer is + * allocated wide enough to correspond to the desired output width). + * The caller (the prep controller) is responsible for vertical padding. + * + * The downsampler may request "context rows" by setting need_context_rows + * during startup. In this case, the input arrays will contain at least + * one row group's worth of pixels above and below the passed-in data; + * the caller will create dummy rows at image top and bottom by replicating + * the first or last real pixel row. + * + * An excellent reference for image resampling is + * Digital Image Warping, George Wolberg, 1990. + * Pub. by IEEE Computer Society Press, Los Alamitos, CA. ISBN 0-8186-8944-7. + * + * The downsampling algorithm used here is a simple average of the source + * pixels covered by the output pixel. The hi-falutin sampling literature + * refers to this as a "box filter". In general the characteristics of a box + * filter are not very good, but for the specific cases we normally use (1:1 + * and 2:1 ratios) the box is equivalent to a "triangle filter" which is not + * nearly so bad. If you intend to use other sampling ratios, you'd be well + * advised to improve this code. + * + * A simple input-smoothing capability is provided. This is mainly intended + * for cleaning up color-dithered GIF input files (if you find it inadequate, + * we suggest using an external filtering program such as pnmconvol). When + * enabled, each input pixel P is replaced by a weighted sum of itself and its + * eight neighbors. P's weight is 1-8*SF and each neighbor's weight is SF, + * where SF = (smoothing_factor / 1024). + * Currently, smoothing is only supported for 2h2v sampling factors. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Pointer to routine to downsample a single component */ +typedef JMETHOD(void, downsample1_ptr, + (j_compress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY output_data)); + +/* Private subobject */ + +typedef struct { + struct jpeg_downsampler pub; /* public fields */ + + /* Downsampling method pointers, one per component */ + downsample1_ptr methods[MAX_COMPONENTS]; +} my_downsampler; + +typedef my_downsampler * my_downsample_ptr; + + +/* + * Initialize for a downsampling pass. + */ + +METHODDEF(void) +start_pass_downsample (j_compress_ptr cinfo) +{ + (void)cinfo; + /* no work for now */ +} + + +/* + * Expand a component horizontally from width input_cols to width output_cols, + * by duplicating the rightmost samples. + */ + +LOCAL(void) +expand_right_edge (JSAMPARRAY image_data, int num_rows, + JDIMENSION input_cols, JDIMENSION output_cols) +{ + register JSAMPROW ptr; + register JSAMPLE pixval; + register int count; + int row; + int numcols = (int) (output_cols - input_cols); + + if (numcols > 0) { + for (row = 0; row < num_rows; row++) { + ptr = image_data[row] + input_cols; + pixval = ptr[-1]; /* don't need GETJSAMPLE() here */ + for (count = numcols; count > 0; count--) + *ptr++ = pixval; + } + } +} + + +/* + * Do downsampling for a whole row group (all components). + * + * In this version we simply downsample each component independently. + */ + +METHODDEF(void) +sep_downsample (j_compress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION in_row_index, + JSAMPIMAGE output_buf, JDIMENSION out_row_group_index) +{ + my_downsample_ptr downsample = (my_downsample_ptr) cinfo->downsample; + int ci; + jpeg_component_info * compptr; + JSAMPARRAY in_ptr, out_ptr; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + in_ptr = input_buf[ci] + in_row_index; + out_ptr = output_buf[ci] + (out_row_group_index * compptr->v_samp_factor); + (*downsample->methods[ci]) (cinfo, compptr, in_ptr, out_ptr); + } +} + + +/* + * Downsample pixel values of a single component. + * One row group is processed per call. + * This version handles arbitrary integral sampling ratios, without smoothing. + * Note that this version is not actually used for customary sampling ratios. + */ + +METHODDEF(void) +int_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY output_data) +{ + int inrow, outrow, h_expand, v_expand, numpix, numpix2, h, v; + JDIMENSION outcol, outcol_h; /* outcol_h == outcol*h_expand */ + JDIMENSION output_cols = compptr->width_in_data_units * cinfo->data_unit; + JSAMPROW inptr, outptr; + INT32 outvalue; + + h_expand = cinfo->max_h_samp_factor / compptr->h_samp_factor; + v_expand = cinfo->max_v_samp_factor / compptr->v_samp_factor; + numpix = h_expand * v_expand; + numpix2 = numpix/2; + + /* Expand input data enough to let all the output samples be generated + * by the standard loop. Special-casing padded output would be more + * efficient. + */ + expand_right_edge(input_data, cinfo->max_v_samp_factor, + cinfo->image_width, output_cols * h_expand); + + inrow = 0; + for (outrow = 0; outrow < compptr->v_samp_factor; outrow++) { + outptr = output_data[outrow]; + for (outcol = 0, outcol_h = 0; outcol < output_cols; + outcol++, outcol_h += h_expand) { + outvalue = 0; + for (v = 0; v < v_expand; v++) { + inptr = input_data[inrow+v] + outcol_h; + for (h = 0; h < h_expand; h++) { + outvalue += (INT32) GETJSAMPLE(*inptr++); + } + } + *outptr++ = (JSAMPLE) ((outvalue + numpix2) / numpix); + } + inrow += v_expand; + } +} + + +/* + * Downsample pixel values of a single component. + * This version handles the special case of a full-size component, + * without smoothing. + */ + +METHODDEF(void) +fullsize_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY output_data) +{ + /* Copy the data */ + jcopy_sample_rows(input_data, 0, output_data, 0, + cinfo->max_v_samp_factor, cinfo->image_width); + /* Edge-expand */ + expand_right_edge(output_data, cinfo->max_v_samp_factor, + cinfo->image_width, compptr->width_in_data_units * cinfo->data_unit); +} + + +/* + * Downsample pixel values of a single component. + * This version handles the common case of 2:1 horizontal and 1:1 vertical, + * without smoothing. + * + * A note about the "bias" calculations: when rounding fractional values to + * integer, we do not want to always round 0.5 up to the next integer. + * If we did that, we'd introduce a noticeable bias towards larger values. + * Instead, this code is arranged so that 0.5 will be rounded up or down at + * alternate pixel locations (a simple ordered dither pattern). + */ + +METHODDEF(void) +h2v1_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY output_data) +{ + int outrow; + JDIMENSION outcol; + JDIMENSION output_cols = compptr->width_in_data_units * cinfo->data_unit; + register JSAMPROW inptr, outptr; + register int bias; + + /* Expand input data enough to let all the output samples be generated + * by the standard loop. Special-casing padded output would be more + * efficient. + */ + expand_right_edge(input_data, cinfo->max_v_samp_factor, + cinfo->image_width, output_cols * 2); + + for (outrow = 0; outrow < compptr->v_samp_factor; outrow++) { + outptr = output_data[outrow]; + inptr = input_data[outrow]; + bias = 0; /* bias = 0,1,0,1,... for successive samples */ + for (outcol = 0; outcol < output_cols; outcol++) { + *outptr++ = (JSAMPLE) ((GETJSAMPLE(*inptr) + GETJSAMPLE(inptr[1]) + + bias) >> 1); + bias ^= 1; /* 0=>1, 1=>0 */ + inptr += 2; + } + } +} + + +/* + * Downsample pixel values of a single component. + * This version handles the standard case of 2:1 horizontal and 2:1 vertical, + * without smoothing. + */ + +METHODDEF(void) +h2v2_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY output_data) +{ + int inrow, outrow; + JDIMENSION outcol; + JDIMENSION output_cols = compptr->width_in_data_units * cinfo->data_unit; + register JSAMPROW inptr0, inptr1, outptr; + register int bias; + + /* Expand input data enough to let all the output samples be generated + * by the standard loop. Special-casing padded output would be more + * efficient. + */ + expand_right_edge(input_data, cinfo->max_v_samp_factor, + cinfo->image_width, output_cols * 2); + + inrow = 0; + for (outrow = 0; outrow < compptr->v_samp_factor; outrow++) { + outptr = output_data[outrow]; + inptr0 = input_data[inrow]; + inptr1 = input_data[inrow+1]; + bias = 1; /* bias = 1,2,1,2,... for successive samples */ + for (outcol = 0; outcol < output_cols; outcol++) { + *outptr++ = (JSAMPLE) ((GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) + + GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]) + + bias) >> 2); + bias ^= 3; /* 1=>2, 2=>1 */ + inptr0 += 2; inptr1 += 2; + } + inrow += 2; + } +} + + +#ifdef INPUT_SMOOTHING_SUPPORTED + +/* + * Downsample pixel values of a single component. + * This version handles the standard case of 2:1 horizontal and 2:1 vertical, + * with smoothing. One row of context is required. + */ + +METHODDEF(void) +h2v2_smooth_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY output_data) +{ + int inrow, outrow; + JDIMENSION colctr; + JDIMENSION output_cols = compptr->width_in_data_units * cinfo->data_unit; + register JSAMPROW inptr0, inptr1, above_ptr, below_ptr, outptr; + INT32 membersum, neighsum, memberscale, neighscale; + + /* Expand input data enough to let all the output samples be generated + * by the standard loop. Special-casing padded output would be more + * efficient. + */ + expand_right_edge(input_data - 1, cinfo->max_v_samp_factor + 2, + cinfo->image_width, output_cols * 2); + + /* We don't bother to form the individual "smoothed" input pixel values; + * we can directly compute the output which is the average of the four + * smoothed values. Each of the four member pixels contributes a fraction + * (1-8*SF) to its own smoothed image and a fraction SF to each of the three + * other smoothed pixels, therefore a total fraction (1-5*SF)/4 to the final + * output. The four corner-adjacent neighbor pixels contribute a fraction + * SF to just one smoothed pixel, or SF/4 to the final output; while the + * eight edge-adjacent neighbors contribute SF to each of two smoothed + * pixels, or SF/2 overall. In order to use integer arithmetic, these + * factors are scaled by 2^16 = 65536. + * Also recall that SF = smoothing_factor / 1024. + */ + + memberscale = 16384 - cinfo->smoothing_factor * 80; /* scaled (1-5*SF)/4 */ + neighscale = cinfo->smoothing_factor * 16; /* scaled SF/4 */ + + inrow = 0; + for (outrow = 0; outrow < compptr->v_samp_factor; outrow++) { + outptr = output_data[outrow]; + inptr0 = input_data[inrow]; + inptr1 = input_data[inrow+1]; + above_ptr = input_data[inrow-1]; + below_ptr = input_data[inrow+2]; + + /* Special case for first column: pretend column -1 is same as column 0 */ + membersum = GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) + + GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]); + neighsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[1]) + + GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[1]) + + GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[2]) + + GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[2]); + neighsum += neighsum; + neighsum += GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[2]) + + GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[2]); + membersum = membersum * memberscale + neighsum * neighscale; + *outptr++ = (JSAMPLE) ((membersum + 32768) >> 16); + inptr0 += 2; inptr1 += 2; above_ptr += 2; below_ptr += 2; + + for (colctr = output_cols - 2; colctr > 0; colctr--) { + /* sum of pixels directly mapped to this output element */ + membersum = GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) + + GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]); + /* sum of edge-neighbor pixels */ + neighsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[1]) + + GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[1]) + + GETJSAMPLE(inptr0[-1]) + GETJSAMPLE(inptr0[2]) + + GETJSAMPLE(inptr1[-1]) + GETJSAMPLE(inptr1[2]); + /* The edge-neighbors count twice as much as corner-neighbors */ + neighsum += neighsum; + /* Add in the corner-neighbors */ + neighsum += GETJSAMPLE(above_ptr[-1]) + GETJSAMPLE(above_ptr[2]) + + GETJSAMPLE(below_ptr[-1]) + GETJSAMPLE(below_ptr[2]); + /* form final output scaled up by 2^16 */ + membersum = membersum * memberscale + neighsum * neighscale; + /* round, descale and output it */ + *outptr++ = (JSAMPLE) ((membersum + 32768) >> 16); + inptr0 += 2; inptr1 += 2; above_ptr += 2; below_ptr += 2; + } + + /* Special case for last column */ + membersum = GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) + + GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]); + neighsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[1]) + + GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[1]) + + GETJSAMPLE(inptr0[-1]) + GETJSAMPLE(inptr0[1]) + + GETJSAMPLE(inptr1[-1]) + GETJSAMPLE(inptr1[1]); + neighsum += neighsum; + neighsum += GETJSAMPLE(above_ptr[-1]) + GETJSAMPLE(above_ptr[1]) + + GETJSAMPLE(below_ptr[-1]) + GETJSAMPLE(below_ptr[1]); + membersum = membersum * memberscale + neighsum * neighscale; + *outptr = (JSAMPLE) ((membersum + 32768) >> 16); + + inrow += 2; + } +} + + +/* + * Downsample pixel values of a single component. + * This version handles the special case of a full-size component, + * with smoothing. One row of context is required. + */ + +METHODDEF(void) +fullsize_smooth_downsample (j_compress_ptr cinfo, jpeg_component_info *compptr, + JSAMPARRAY input_data, JSAMPARRAY output_data) +{ + int outrow; + JDIMENSION colctr; + JDIMENSION output_cols = compptr->width_in_data_units * cinfo->data_unit; + register JSAMPROW inptr, above_ptr, below_ptr, outptr; + INT32 membersum, neighsum, memberscale, neighscale; + int colsum, lastcolsum, nextcolsum; + + /* Expand input data enough to let all the output samples be generated + * by the standard loop. Special-casing padded output would be more + * efficient. + */ + expand_right_edge(input_data - 1, cinfo->max_v_samp_factor + 2, + cinfo->image_width, output_cols); + + /* Each of the eight neighbor pixels contributes a fraction SF to the + * smoothed pixel, while the main pixel contributes (1-8*SF). In order + * to use integer arithmetic, these factors are multiplied by 2^16 = 65536. + * Also recall that SF = smoothing_factor / 1024. + */ + + memberscale = 65536L - cinfo->smoothing_factor * 512L; /* scaled 1-8*SF */ + neighscale = cinfo->smoothing_factor * 64; /* scaled SF */ + + for (outrow = 0; outrow < compptr->v_samp_factor; outrow++) { + outptr = output_data[outrow]; + inptr = input_data[outrow]; + above_ptr = input_data[outrow-1]; + below_ptr = input_data[outrow+1]; + + /* Special case for first column */ + colsum = GETJSAMPLE(*above_ptr++) + GETJSAMPLE(*below_ptr++) + + GETJSAMPLE(*inptr); + membersum = GETJSAMPLE(*inptr++); + nextcolsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(*below_ptr) + + GETJSAMPLE(*inptr); + neighsum = colsum + (colsum - membersum) + nextcolsum; + membersum = membersum * memberscale + neighsum * neighscale; + *outptr++ = (JSAMPLE) ((membersum + 32768) >> 16); + lastcolsum = colsum; colsum = nextcolsum; + + for (colctr = output_cols - 2; colctr > 0; colctr--) { + membersum = GETJSAMPLE(*inptr++); + above_ptr++; below_ptr++; + nextcolsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(*below_ptr) + + GETJSAMPLE(*inptr); + neighsum = lastcolsum + (colsum - membersum) + nextcolsum; + membersum = membersum * memberscale + neighsum * neighscale; + *outptr++ = (JSAMPLE) ((membersum + 32768) >> 16); + lastcolsum = colsum; colsum = nextcolsum; + } + + /* Special case for last column */ + membersum = GETJSAMPLE(*inptr); + neighsum = lastcolsum + (colsum - membersum) + colsum; + membersum = membersum * memberscale + neighsum * neighscale; + *outptr = (JSAMPLE) ((membersum + 32768) >> 16); + + } +} + +#endif /* INPUT_SMOOTHING_SUPPORTED */ + + +/* + * Module initialization routine for downsampling. + * Note that we must select a routine for each component. + */ + +GLOBAL(void) +jinit_downsampler (j_compress_ptr cinfo) +{ + my_downsample_ptr downsample; + int ci; + jpeg_component_info * compptr; + boolean smoothok = TRUE; + + downsample = (my_downsample_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_downsampler)); + cinfo->downsample = (struct jpeg_downsampler *) downsample; + downsample->pub.start_pass = start_pass_downsample; + downsample->pub.downsample = sep_downsample; + downsample->pub.need_context_rows = FALSE; + + if (cinfo->CCIR601_sampling) + ERREXIT(cinfo, JERR_CCIR601_NOTIMPL); + + /* Verify we can handle the sampling factors, and set up method pointers */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + if (compptr->h_samp_factor == cinfo->max_h_samp_factor && + compptr->v_samp_factor == cinfo->max_v_samp_factor) { +#ifdef INPUT_SMOOTHING_SUPPORTED + if (cinfo->smoothing_factor) { + downsample->methods[ci] = fullsize_smooth_downsample; + downsample->pub.need_context_rows = TRUE; + } else +#endif + downsample->methods[ci] = fullsize_downsample; + } else if (compptr->h_samp_factor * 2 == cinfo->max_h_samp_factor && + compptr->v_samp_factor == cinfo->max_v_samp_factor) { + smoothok = FALSE; + downsample->methods[ci] = h2v1_downsample; + } else if (compptr->h_samp_factor * 2 == cinfo->max_h_samp_factor && + compptr->v_samp_factor * 2 == cinfo->max_v_samp_factor) { +#ifdef INPUT_SMOOTHING_SUPPORTED + if (cinfo->smoothing_factor) { + downsample->methods[ci] = h2v2_smooth_downsample; + downsample->pub.need_context_rows = TRUE; + } else +#endif + downsample->methods[ci] = h2v2_downsample; + } else if ((cinfo->max_h_samp_factor % compptr->h_samp_factor) == 0 && + (cinfo->max_v_samp_factor % compptr->v_samp_factor) == 0) { + smoothok = FALSE; + downsample->methods[ci] = int_downsample; + } else + ERREXIT(cinfo, JERR_FRACT_SAMPLE_NOTIMPL); + } + +#ifdef INPUT_SMOOTHING_SUPPORTED + if (cinfo->smoothing_factor && !smoothok) + TRACEMS(cinfo, 0, JTRC_SMOOTH_NOTIMPL); +#endif +} diff --git a/Utilities/ITK/Utilities/itkjpeg/jcscale.c b/Utilities/ITK/Utilities/itkjpeg/jcscale.c new file mode 100644 index 0000000000000000000000000000000000000000..f0539afed68738f7f0ed35cc34b96326801a0066 --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jcscale.c @@ -0,0 +1,64 @@ +/* + * jcscale.c + * + * Copyright (C) 1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains sample downscaling by 2^Pt for lossless JPEG. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jlossls.h" /* Private declarations for lossless codec */ + + +#ifdef C_LOSSLESS_SUPPORTED + +METHODDEF(void) +simple_downscale(j_compress_ptr cinfo, + JSAMPROW input_buf, JSAMPROW output_buf, JDIMENSION width) +{ + /* j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec; */ + unsigned int xindex; + SHIFT_TEMPS + + for (xindex = 0; xindex < width; xindex++) + output_buf[xindex] = (JSAMPLE) RIGHT_SHIFT(GETJSAMPLE(input_buf[xindex]), + cinfo->Al); +} + + +METHODDEF(void) +noscale(j_compress_ptr cinfo, + JSAMPROW input_buf, JSAMPROW output_buf, JDIMENSION width) +{ + (void)cinfo; + MEMCOPY(output_buf, input_buf, width * SIZEOF(JSAMPLE)); + return; +} + + +METHODDEF(void) +scaler_start_pass (j_compress_ptr cinfo) +{ + j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec; + + /* Set scaler function based on Pt */ + if (cinfo->Al) + losslsc->scaler_scale = simple_downscale; + else + losslsc->scaler_scale = noscale; +} + + +GLOBAL(void) +jinit_c_scaler (j_compress_ptr cinfo) +{ + j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec; + + losslsc->scaler_start_pass = scaler_start_pass; +} + +#endif /* C_LOSSLESS_SUPPORTED */ diff --git a/Utilities/ITK/Utilities/itkjpeg/jcshuff.c b/Utilities/ITK/Utilities/itkjpeg/jcshuff.c new file mode 100644 index 0000000000000000000000000000000000000000..85557158b7f8aaf0c0fd47012f4fc4a8540e372d --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jcshuff.c @@ -0,0 +1,662 @@ +/* + * jcshuff.c + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains Huffman entropy encoding routines for sequential JPEG. + * + * Much of the complexity here has to do with supporting output suspension. + * If the data destination module demands suspension, we want to be able to + * back up to the start of the current MCU. To do this, we copy state + * variables into local working storage, and update them back to the + * permanent JPEG objects only upon successful completion of an MCU. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jlossy.h" /* Private declarations for lossy codec */ +#include "jchuff.h" /* Declarations shared with jc*huff.c */ + + +/* Expanded entropy encoder object for Huffman encoding. + * + * The savable_state subrecord contains fields that change within an MCU, + * but must not be updated permanently until we complete the MCU. + */ + +typedef struct { + INT32 put_buffer; /* current bit-accumulation buffer */ + int put_bits; /* # of bits now in it */ + int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */ +} savable_state; + +/* This macro is to work around compilers with missing or broken + * structure assignment. You'll need to fix this code if you have + * such a compiler and you change MAX_COMPS_IN_SCAN. + */ + +#ifndef NO_STRUCT_ASSIGN +#define ASSIGN_STATE(dest,src) ((dest) = (src)) +#else +#if MAX_COMPS_IN_SCAN == 4 +#define ASSIGN_STATE(dest,src) \ + ((dest).put_buffer = (src).put_buffer, \ + (dest).put_bits = (src).put_bits, \ + (dest).last_dc_val[0] = (src).last_dc_val[0], \ + (dest).last_dc_val[1] = (src).last_dc_val[1], \ + (dest).last_dc_val[2] = (src).last_dc_val[2], \ + (dest).last_dc_val[3] = (src).last_dc_val[3]) +#endif +#endif + + +typedef struct { + savable_state saved; /* Bit buffer & DC state at start of MCU */ + + /* These fields are NOT loaded into local working state. */ + unsigned int restarts_to_go; /* MCUs left in this restart interval */ + int next_restart_num; /* next restart number to write (0-7) */ + + /* Pointers to derived tables (these workspaces have image lifespan) */ + c_derived_tbl * dc_derived_tbls[NUM_HUFF_TBLS]; + c_derived_tbl * ac_derived_tbls[NUM_HUFF_TBLS]; + +#ifdef ENTROPY_OPT_SUPPORTED /* Statistics tables for optimization */ + long * dc_count_ptrs[NUM_HUFF_TBLS]; + long * ac_count_ptrs[NUM_HUFF_TBLS]; +#endif +} shuff_entropy_encoder; + +typedef shuff_entropy_encoder * shuff_entropy_ptr; + +/* Working state while writing an MCU. + * This struct contains all the fields that are needed by subroutines. + */ + +typedef struct { + JOCTET * next_output_byte; /* => next byte to write in buffer */ + size_t free_in_buffer; /* # of byte spaces remaining in buffer */ + savable_state cur; /* Current bit buffer & DC state */ + j_compress_ptr cinfo; /* dump_buffer needs access to this */ +} working_state; + + +/* Forward declarations */ +METHODDEF(boolean) encode_mcu_huff JPP((j_compress_ptr cinfo, + JBLOCKROW *MCU_data)); +METHODDEF(void) finish_pass_huff JPP((j_compress_ptr cinfo)); +#ifdef ENTROPY_OPT_SUPPORTED +METHODDEF(boolean) encode_mcu_gather JPP((j_compress_ptr cinfo, + JBLOCKROW *MCU_data)); +METHODDEF(void) finish_pass_gather JPP((j_compress_ptr cinfo)); +#endif + + +/* + * Initialize for a Huffman-compressed scan. + * If gather_statistics is TRUE, we do not output anything during the scan, + * just count the Huffman symbols used and generate Huffman code tables. + */ + +METHODDEF(void) +start_pass_huff (j_compress_ptr cinfo, boolean gather_statistics) +{ + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + shuff_entropy_ptr entropy = (shuff_entropy_ptr) lossyc->entropy_private; + int ci, dctbl, actbl; + jpeg_component_info * compptr; + + if (gather_statistics) { +#ifdef ENTROPY_OPT_SUPPORTED + lossyc->entropy_encode_mcu = encode_mcu_gather; + lossyc->pub.entropy_finish_pass = finish_pass_gather; +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else { + lossyc->entropy_encode_mcu = encode_mcu_huff; + lossyc->pub.entropy_finish_pass = finish_pass_huff; + } + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + dctbl = compptr->dc_tbl_no; + actbl = compptr->ac_tbl_no; + if (gather_statistics) { +#ifdef ENTROPY_OPT_SUPPORTED + /* Check for invalid table indexes */ + /* (make_c_derived_tbl does this in the other path) */ + if (dctbl < 0 || dctbl >= NUM_HUFF_TBLS) + ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, dctbl); + if (actbl < 0 || actbl >= NUM_HUFF_TBLS) + ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, actbl); + /* Allocate and zero the statistics tables */ + /* Note that jpeg_gen_optimal_table expects 257 entries in each table! */ + if (entropy->dc_count_ptrs[dctbl] == NULL) + entropy->dc_count_ptrs[dctbl] = (long *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + 257 * SIZEOF(long)); + MEMZERO(entropy->dc_count_ptrs[dctbl], 257 * SIZEOF(long)); + if (entropy->ac_count_ptrs[actbl] == NULL) + entropy->ac_count_ptrs[actbl] = (long *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + 257 * SIZEOF(long)); + MEMZERO(entropy->ac_count_ptrs[actbl], 257 * SIZEOF(long)); +#endif + } else { + /* Compute derived values for Huffman tables */ + /* We may do this more than once for a table, but it's not expensive */ + jpeg_make_c_derived_tbl(cinfo, TRUE, dctbl, + & entropy->dc_derived_tbls[dctbl]); + jpeg_make_c_derived_tbl(cinfo, FALSE, actbl, + & entropy->ac_derived_tbls[actbl]); + } + /* Initialize DC predictions to 0 */ + entropy->saved.last_dc_val[ci] = 0; + } + + /* Initialize bit buffer to empty */ + entropy->saved.put_buffer = 0; + entropy->saved.put_bits = 0; + + /* Initialize restart stuff */ + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num = 0; +} + + +/* Outputting bytes to the file */ + +/* Emit a byte, taking 'action' if must suspend. */ +#define emit_byte(state,val,action) \ + { *(state)->next_output_byte++ = (JOCTET) (val); \ + if (--(state)->free_in_buffer == 0) \ + if (! dump_buffer(state)) \ + { action; } } + + +LOCAL(boolean) +dump_buffer (working_state * state) +/* Empty the output buffer; return TRUE if successful, FALSE if must suspend */ +{ + struct jpeg_destination_mgr * dest = state->cinfo->dest; + + if (! (*dest->empty_output_buffer) (state->cinfo)) + return FALSE; + /* After a successful buffer dump, must reset buffer pointers */ + state->next_output_byte = dest->next_output_byte; + state->free_in_buffer = dest->free_in_buffer; + return TRUE; +} + + +/* Outputting bits to the file */ + +/* Only the right 24 bits of put_buffer are used; the valid bits are + * left-justified in this part. At most 16 bits can be passed to emit_bits + * in one call, and we never retain more than 7 bits in put_buffer + * between calls, so 24 bits are sufficient. + */ + +INLINE +LOCAL(boolean) +emit_bits (working_state * state, unsigned int code, int size) +/* Emit some bits; return TRUE if successful, FALSE if must suspend */ +{ + /* This routine is heavily used, so it's worth coding tightly. */ + register INT32 put_buffer = (INT32) code; + register int put_bits = state->cur.put_bits; + + /* if size is 0, caller used an invalid Huffman table entry */ + if (size == 0) + ERREXIT(state->cinfo, JERR_HUFF_MISSING_CODE); + + put_buffer &= (((INT32) 1)<<size) - 1; /* mask off any extra bits in code */ + + put_bits += size; /* new number of bits in buffer */ + + put_buffer <<= 24 - put_bits; /* align incoming bits */ + + put_buffer |= state->cur.put_buffer; /* and merge with old buffer contents */ + + while (put_bits >= 8) { + int c = (int) ((put_buffer >> 16) & 0xFF); + + emit_byte(state, c, return FALSE); + if (c == 0xFF) { /* need to stuff a zero byte? */ + emit_byte(state, 0, return FALSE); + } + put_buffer <<= 8; + put_bits -= 8; + } + + state->cur.put_buffer = put_buffer; /* update state variables */ + state->cur.put_bits = put_bits; + + return TRUE; +} + + +LOCAL(boolean) +flush_bits (working_state * state) +{ + if (! emit_bits(state, 0x7F, 7)) /* fill any partial byte with ones */ + return FALSE; + state->cur.put_buffer = 0; /* and reset bit-buffer to empty */ + state->cur.put_bits = 0; + return TRUE; +} + + +/* Encode a single block's worth of coefficients */ + +LOCAL(boolean) +encode_one_block (working_state * state, JCOEFPTR block, int last_dc_val, + c_derived_tbl *dctbl, c_derived_tbl *actbl) +{ + register int temp, temp2; + register int nbits; + register int k, r, i; + + /* Encode the DC coefficient difference per section F.1.2.1 */ + + temp = temp2 = block[0] - last_dc_val; + + if (temp < 0) { + temp = -temp; /* temp is abs value of input */ + /* For a negative input, want temp2 = bitwise complement of abs(input) */ + /* This code assumes we are on a two's complement machine */ + temp2--; + } + + /* Find the number of bits needed for the magnitude of the coefficient */ + nbits = 0; + while (temp) { + nbits++; + temp >>= 1; + } + /* Check for out-of-range coefficient values. + * Since we're encoding a difference, the range limit is twice as much. + */ + if (nbits > MAX_COEF_BITS+1) + ERREXIT(state->cinfo, JERR_BAD_DCT_COEF); + + /* Emit the Huffman-coded symbol for the number of bits */ + if (! emit_bits(state, dctbl->ehufco[nbits], dctbl->ehufsi[nbits])) + return FALSE; + + /* Emit that number of bits of the value, if positive, */ + /* or the complement of its magnitude, if negative. */ + if (nbits) /* emit_bits rejects calls with size 0 */ + if (! emit_bits(state, (unsigned int) temp2, nbits)) + return FALSE; + + /* Encode the AC coefficients per section F.1.2.2 */ + + r = 0; /* r = run length of zeros */ + + for (k = 1; k < DCTSIZE2; k++) { + if ((temp = block[jpeg_natural_order[k]]) == 0) { + r++; + } else { + /* if run length > 15, must emit special run-length-16 codes (0xF0) */ + while (r > 15) { + if (! emit_bits(state, actbl->ehufco[0xF0], actbl->ehufsi[0xF0])) + return FALSE; + r -= 16; + } + + temp2 = temp; + if (temp < 0) { + temp = -temp; /* temp is abs value of input */ + /* This code assumes we are on a two's complement machine */ + temp2--; + } + + /* Find the number of bits needed for the magnitude of the coefficient */ + nbits = 1; /* there must be at least one 1 bit */ + while ((temp >>= 1)) + nbits++; + /* Check for out-of-range coefficient values */ + if (nbits > MAX_COEF_BITS) + ERREXIT(state->cinfo, JERR_BAD_DCT_COEF); + + /* Emit Huffman symbol for run length / number of bits */ + i = (r << 4) + nbits; + if (! emit_bits(state, actbl->ehufco[i], actbl->ehufsi[i])) + return FALSE; + + /* Emit that number of bits of the value, if positive, */ + /* or the complement of its magnitude, if negative. */ + if (! emit_bits(state, (unsigned int) temp2, nbits)) + return FALSE; + + r = 0; + } + } + + /* If the last coef(s) were zero, emit an end-of-block code */ + if (r > 0) + if (! emit_bits(state, actbl->ehufco[0], actbl->ehufsi[0])) + return FALSE; + + return TRUE; +} + + +/* + * Emit a restart marker & resynchronize predictions. + */ + +LOCAL(boolean) +emit_restart (working_state * state, int restart_num) +{ + int ci; + + if (! flush_bits(state)) + return FALSE; + + emit_byte(state, 0xFF, return FALSE); + emit_byte(state, JPEG_RST0 + restart_num, return FALSE); + + /* Re-initialize DC predictions to 0 */ + for (ci = 0; ci < state->cinfo->comps_in_scan; ci++) + state->cur.last_dc_val[ci] = 0; + + /* The restart counter is not updated until we successfully write the MCU. */ + + return TRUE; +} + + +/* + * Encode and output one MCU's worth of Huffman-compressed coefficients. + */ + +METHODDEF(boolean) +encode_mcu_huff (j_compress_ptr cinfo, JBLOCKROW *MCU_data) +{ + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + shuff_entropy_ptr entropy = (shuff_entropy_ptr) lossyc->entropy_private; + working_state state; + int blkn, ci; + jpeg_component_info * compptr; + + /* Load up working state */ + state.next_output_byte = cinfo->dest->next_output_byte; + state.free_in_buffer = cinfo->dest->free_in_buffer; + ASSIGN_STATE(state.cur, entropy->saved); + state.cinfo = cinfo; + + /* Emit restart marker if needed */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) + if (! emit_restart(&state, entropy->next_restart_num)) + return FALSE; + } + + /* Encode the MCU data blocks */ + for (blkn = 0; blkn < cinfo->data_units_in_MCU; blkn++) { + ci = cinfo->MCU_membership[blkn]; + compptr = cinfo->cur_comp_info[ci]; + if (! encode_one_block(&state, + MCU_data[blkn][0], state.cur.last_dc_val[ci], + entropy->dc_derived_tbls[compptr->dc_tbl_no], + entropy->ac_derived_tbls[compptr->ac_tbl_no])) + return FALSE; + /* Update last_dc_val */ + state.cur.last_dc_val[ci] = MCU_data[blkn][0][0]; + } + + /* Completed MCU, so update state */ + cinfo->dest->next_output_byte = state.next_output_byte; + cinfo->dest->free_in_buffer = state.free_in_buffer; + ASSIGN_STATE(entropy->saved, state.cur); + + /* Update restart-interval state too */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) { + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num++; + entropy->next_restart_num &= 7; + } + entropy->restarts_to_go--; + } + + return TRUE; +} + + +/* + * Finish up at the end of a Huffman-compressed scan. + */ + +METHODDEF(void) +finish_pass_huff (j_compress_ptr cinfo) +{ + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + shuff_entropy_ptr entropy = (shuff_entropy_ptr) lossyc->entropy_private; + working_state state; + + /* Load up working state ... flush_bits needs it */ + state.next_output_byte = cinfo->dest->next_output_byte; + state.free_in_buffer = cinfo->dest->free_in_buffer; + ASSIGN_STATE(state.cur, entropy->saved); + state.cinfo = cinfo; + + /* Flush out the last data */ + if (! flush_bits(&state)) + ERREXIT(cinfo, JERR_CANT_SUSPEND); + + /* Update state */ + cinfo->dest->next_output_byte = state.next_output_byte; + cinfo->dest->free_in_buffer = state.free_in_buffer; + ASSIGN_STATE(entropy->saved, state.cur); +} + + +/* + * Huffman coding optimization. + * + * We first scan the supplied data and count the number of uses of each symbol + * that is to be Huffman-coded. (This process MUST agree with the code above.) + * Then we build a Huffman coding tree for the observed counts. + * Symbols which are not needed at all for the particular image are not + * assigned any code, which saves space in the DHT marker as well as in + * the compressed data. + */ + +#ifdef ENTROPY_OPT_SUPPORTED + + +/* Process a single block's worth of coefficients */ + +LOCAL(void) +htest_one_block (j_compress_ptr cinfo, JCOEFPTR block, int last_dc_val, + long dc_counts[], long ac_counts[]) +{ + register int temp; + register int nbits; + register int k, r; + + /* Encode the DC coefficient difference per section F.1.2.1 */ + + temp = block[0] - last_dc_val; + if (temp < 0) + temp = -temp; + + /* Find the number of bits needed for the magnitude of the coefficient */ + nbits = 0; + while (temp) { + nbits++; + temp >>= 1; + } + /* Check for out-of-range coefficient values. + * Since we're encoding a difference, the range limit is twice as much. + */ + if (nbits > MAX_COEF_BITS+1) + ERREXIT(cinfo, JERR_BAD_DCT_COEF); + + /* Count the Huffman symbol for the number of bits */ + dc_counts[nbits]++; + + /* Encode the AC coefficients per section F.1.2.2 */ + + r = 0; /* r = run length of zeros */ + + for (k = 1; k < DCTSIZE2; k++) { + if ((temp = block[jpeg_natural_order[k]]) == 0) { + r++; + } else { + /* if run length > 15, must emit special run-length-16 codes (0xF0) */ + while (r > 15) { + ac_counts[0xF0]++; + r -= 16; + } + + /* Find the number of bits needed for the magnitude of the coefficient */ + if (temp < 0) + temp = -temp; + + /* Find the number of bits needed for the magnitude of the coefficient */ + nbits = 1; /* there must be at least one 1 bit */ + while ((temp >>= 1)) + nbits++; + /* Check for out-of-range coefficient values */ + if (nbits > MAX_COEF_BITS) + ERREXIT(cinfo, JERR_BAD_DCT_COEF); + + /* Count Huffman symbol for run length / number of bits */ + ac_counts[(r << 4) + nbits]++; + + r = 0; + } + } + + /* If the last coef(s) were zero, emit an end-of-block code */ + if (r > 0) + ac_counts[0]++; +} + + +/* + * Trial-encode one MCU's worth of Huffman-compressed coefficients. + * No data is actually output, so no suspension return is possible. + */ + +METHODDEF(boolean) +encode_mcu_gather (j_compress_ptr cinfo, JBLOCKROW *MCU_data) +{ + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + shuff_entropy_ptr entropy = (shuff_entropy_ptr) lossyc->entropy_private; + int blkn, ci; + jpeg_component_info * compptr; + + /* Take care of restart intervals if needed */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) { + /* Re-initialize DC predictions to 0 */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) + entropy->saved.last_dc_val[ci] = 0; + /* Update restart state */ + entropy->restarts_to_go = cinfo->restart_interval; + } + entropy->restarts_to_go--; + } + + for (blkn = 0; blkn < cinfo->data_units_in_MCU; blkn++) { + ci = cinfo->MCU_membership[blkn]; + compptr = cinfo->cur_comp_info[ci]; + htest_one_block(cinfo, MCU_data[blkn][0], entropy->saved.last_dc_val[ci], + entropy->dc_count_ptrs[compptr->dc_tbl_no], + entropy->ac_count_ptrs[compptr->ac_tbl_no]); + entropy->saved.last_dc_val[ci] = MCU_data[blkn][0][0]; + } + + return TRUE; +} + + +/* + * Finish up a statistics-gathering pass and create the new Huffman tables. + */ + +METHODDEF(void) +finish_pass_gather (j_compress_ptr cinfo) +{ + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + shuff_entropy_ptr entropy = (shuff_entropy_ptr) lossyc->entropy_private; + int ci, dctbl, actbl; + jpeg_component_info * compptr; + JHUFF_TBL **htblptr; + boolean did_dc[NUM_HUFF_TBLS]; + boolean did_ac[NUM_HUFF_TBLS]; + + /* It's important not to apply jpeg_gen_optimal_table more than once + * per table, because it clobbers the input frequency counts! + */ + MEMZERO(did_dc, SIZEOF(did_dc)); + MEMZERO(did_ac, SIZEOF(did_ac)); + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + dctbl = compptr->dc_tbl_no; + actbl = compptr->ac_tbl_no; + if (! did_dc[dctbl]) { + htblptr = & cinfo->dc_huff_tbl_ptrs[dctbl]; + if (*htblptr == NULL) + *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo); + jpeg_gen_optimal_table(cinfo, *htblptr, entropy->dc_count_ptrs[dctbl]); + did_dc[dctbl] = TRUE; + } + if (! did_ac[actbl]) { + htblptr = & cinfo->ac_huff_tbl_ptrs[actbl]; + if (*htblptr == NULL) + *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo); + jpeg_gen_optimal_table(cinfo, *htblptr, entropy->ac_count_ptrs[actbl]); + did_ac[actbl] = TRUE; + } + } +} + + +#endif /* ENTROPY_OPT_SUPPORTED */ + + +METHODDEF(boolean) +need_optimization_pass (j_compress_ptr cinfo) +{ + (void)cinfo; + return TRUE; +} + + +/* + * Module initialization routine for Huffman entropy encoding. + */ + +GLOBAL(void) +jinit_shuff_encoder (j_compress_ptr cinfo) +{ + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + shuff_entropy_ptr entropy; + int i; + + entropy = (shuff_entropy_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(shuff_entropy_encoder)); + lossyc->entropy_private = (struct jpeg_entropy_encoder *) entropy; + lossyc->pub.entropy_start_pass = start_pass_huff; + lossyc->pub.need_optimization_pass = need_optimization_pass; + + /* Mark tables unallocated */ + for (i = 0; i < NUM_HUFF_TBLS; i++) { + entropy->dc_derived_tbls[i] = entropy->ac_derived_tbls[i] = NULL; +#ifdef ENTROPY_OPT_SUPPORTED + entropy->dc_count_ptrs[i] = entropy->ac_count_ptrs[i] = NULL; +#endif + } +} diff --git a/Utilities/ITK/Utilities/itkjpeg/jctrans.c b/Utilities/ITK/Utilities/itkjpeg/jctrans.c new file mode 100644 index 0000000000000000000000000000000000000000..0c94656a68411784d1e076f23056e28514947386 --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jctrans.c @@ -0,0 +1,421 @@ +/* + * jctrans.c + * + * Copyright (C) 1995-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains library routines for transcoding compression, + * that is, writing raw DCT coefficient arrays to an output JPEG file. + * The routines in jcapimin.c will also be needed by a transcoder. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jlossy.h" /* Private declarations for lossy codec */ + + +/* Forward declarations */ +LOCAL(void) transencode_master_selection + JPP((j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays)); +LOCAL(void) transencode_codec + JPP((j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays)); +LOCAL(void) transencode_coef_controller + JPP((j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays)); + + +/* + * Compression initialization for writing raw-coefficient data. + * Before calling this, all parameters and a data destination must be set up. + * Call jpeg_finish_compress() to actually write the data. + * + * The number of passed virtual arrays must match cinfo->num_components. + * Note that the virtual arrays need not be filled or even realized at + * the time write_coefficients is called; indeed, if the virtual arrays + * were requested from this compression object's memory manager, they + * typically will be realized during this routine and filled afterwards. + */ + +GLOBAL(void) +jpeg_write_coefficients (j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays) +{ + if (cinfo->global_state != CSTATE_START) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + /* Mark all tables to be written */ + jpeg_suppress_tables(cinfo, FALSE); + /* (Re)initialize error mgr and destination modules */ + (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo); + (*cinfo->dest->init_destination) (cinfo); + /* Perform master selection of active modules */ + transencode_master_selection(cinfo, coef_arrays); + /* Wait for jpeg_finish_compress() call */ + cinfo->next_scanline = 0; /* so jpeg_write_marker works */ + cinfo->global_state = CSTATE_WRCOEFS; +} + + +/* + * Initialize the compression object with default parameters, + * then copy from the source object all parameters needed for lossless + * transcoding. Parameters that can be varied without loss (such as + * scan script and Huffman optimization) are left in their default states. + */ + +GLOBAL(void) +jpeg_copy_critical_parameters (j_decompress_ptr srcinfo, + j_compress_ptr dstinfo) +{ + JQUANT_TBL ** qtblptr; + jpeg_component_info *incomp, *outcomp; + JQUANT_TBL *c_quant, *slot_quant; + int tblno, ci, coefi; + + /* Safety check to ensure start_compress not called yet. */ + if (dstinfo->global_state != CSTATE_START) + ERREXIT1(dstinfo, JERR_BAD_STATE, dstinfo->global_state); + /* Copy fundamental image dimensions */ + dstinfo->image_width = srcinfo->image_width; + dstinfo->image_height = srcinfo->image_height; + dstinfo->input_components = srcinfo->num_components; + dstinfo->in_color_space = srcinfo->jpeg_color_space; + /* Initialize all parameters to default values */ + jpeg_set_defaults(dstinfo); + /* jpeg_set_defaults may choose wrong colorspace, eg YCbCr if input is RGB. + * Fix it to get the right header markers for the image colorspace. + */ + jpeg_set_colorspace(dstinfo, srcinfo->jpeg_color_space); + dstinfo->data_precision = srcinfo->data_precision; + dstinfo->CCIR601_sampling = srcinfo->CCIR601_sampling; + /* Copy the source's quantization tables. */ + for (tblno = 0; tblno < NUM_QUANT_TBLS; tblno++) { + if (srcinfo->quant_tbl_ptrs[tblno] != NULL) { + qtblptr = & dstinfo->quant_tbl_ptrs[tblno]; + if (*qtblptr == NULL) + *qtblptr = jpeg_alloc_quant_table((j_common_ptr) dstinfo); + MEMCOPY((*qtblptr)->quantval, + srcinfo->quant_tbl_ptrs[tblno]->quantval, + SIZEOF((*qtblptr)->quantval)); + (*qtblptr)->sent_table = FALSE; + } + } + /* Copy the source's per-component info. + * Note we assume jpeg_set_defaults has allocated the dest comp_info array. + */ + dstinfo->num_components = srcinfo->num_components; + if (dstinfo->num_components < 1 || dstinfo->num_components > MAX_COMPONENTS) + ERREXIT2(dstinfo, JERR_COMPONENT_COUNT, dstinfo->num_components, + MAX_COMPONENTS); + for (ci = 0, incomp = srcinfo->comp_info, outcomp = dstinfo->comp_info; + ci < dstinfo->num_components; ci++, incomp++, outcomp++) { + outcomp->component_id = incomp->component_id; + outcomp->h_samp_factor = incomp->h_samp_factor; + outcomp->v_samp_factor = incomp->v_samp_factor; + outcomp->quant_tbl_no = incomp->quant_tbl_no; + /* Make sure saved quantization table for component matches the qtable + * slot. If not, the input file re-used this qtable slot. + * IJG encoder currently cannot duplicate this. + */ + tblno = outcomp->quant_tbl_no; + if (tblno < 0 || tblno >= NUM_QUANT_TBLS || + srcinfo->quant_tbl_ptrs[tblno] == NULL) + ERREXIT1(dstinfo, JERR_NO_QUANT_TABLE, tblno); + slot_quant = srcinfo->quant_tbl_ptrs[tblno]; + c_quant = incomp->quant_table; + if (c_quant != NULL) { + for (coefi = 0; coefi < DCTSIZE2; coefi++) { + if (c_quant->quantval[coefi] != slot_quant->quantval[coefi]) + ERREXIT1(dstinfo, JERR_MISMATCHED_QUANT_TABLE, tblno); + } + } + /* Note: we do not copy the source's Huffman table assignments; + * instead we rely on jpeg_set_colorspace to have made a suitable choice. + */ + } + /* Also copy JFIF version and resolution information, if available. + * Strictly speaking this isn't "critical" info, but it's nearly + * always appropriate to copy it if available. In particular, + * if the application chooses to copy JFIF 1.02 extension markers from + * the source file, we need to copy the version to make sure we don't + * emit a file that has 1.02 extensions but a claimed version of 1.01. + * We will *not*, however, copy version info from mislabeled "2.01" files. + */ + if (srcinfo->saw_JFIF_marker) { + if (srcinfo->JFIF_major_version == 1) { + dstinfo->JFIF_major_version = srcinfo->JFIF_major_version; + dstinfo->JFIF_minor_version = srcinfo->JFIF_minor_version; + } + dstinfo->density_unit = srcinfo->density_unit; + dstinfo->X_density = srcinfo->X_density; + dstinfo->Y_density = srcinfo->Y_density; + } +} + + +/* + * Master selection of compression modules for transcoding. + * This substitutes for jcinit.c's initialization of the full compressor. + */ + +LOCAL(void) +transencode_master_selection (j_compress_ptr cinfo, + jvirt_barray_ptr * coef_arrays) +{ + cinfo->data_unit = DCTSIZE; + /* Although we don't actually use input_components for transcoding, + * jcmaster.c's initial_setup will complain if input_components is 0. + */ + cinfo->input_components = 1; + /* Initialize master control (includes parameter checking/processing) */ + jinit_c_master_control(cinfo, TRUE /* transcode only */); + + /* We need a special compression codec. */ + transencode_codec(cinfo, coef_arrays); + + jinit_marker_writer(cinfo); + + /* We can now tell the memory manager to allocate virtual arrays. */ + (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo); + + /* Write the datastream header (SOI, JFIF) immediately. + * Frame and scan headers are postponed till later. + * This lets application insert special markers after the SOI. + */ + (*cinfo->marker->write_file_header) (cinfo); +} + + +/* + * The rest of this file is a special implementation of the coefficient + * buffer controller. This is similar to jccoefct.c, but it handles only + * output from presupplied virtual arrays. Furthermore, we generate any + * dummy padding blocks on-the-fly rather than expecting them to be present + * in the arrays. + */ + +/* Private buffer controller object */ + +typedef struct { + JDIMENSION iMCU_row_num; /* iMCU row # within image */ + JDIMENSION mcu_ctr; /* counts MCUs processed in current row */ + int MCU_vert_offset; /* counts MCU rows within iMCU row */ + int MCU_rows_per_iMCU_row; /* number of such rows needed */ + + /* Virtual block array for each component. */ + jvirt_barray_ptr * whole_image; + + /* Workspace for constructing dummy blocks at right/bottom edges. */ + JBLOCKROW dummy_buffer[C_MAX_DATA_UNITS_IN_MCU]; +} c_coef_controller; + +typedef c_coef_controller * c_coef_ptr; + + +LOCAL(void) +start_iMCU_row (j_compress_ptr cinfo) +/* Reset within-iMCU-row counters for a new row */ +{ + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + c_coef_ptr coef = (c_coef_ptr) lossyc->coef_private; + + /* In an interleaved scan, an MCU row is the same as an iMCU row. + * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows. + * But at the bottom of the image, process only what's left. + */ + if (cinfo->comps_in_scan > 1) { + coef->MCU_rows_per_iMCU_row = 1; + } else { + if (coef->iMCU_row_num < (cinfo->total_iMCU_rows-1)) + coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor; + else + coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height; + } + + coef->mcu_ctr = 0; + coef->MCU_vert_offset = 0; +} + + +/* + * Initialize for a processing pass. + */ + +METHODDEF(void) +start_pass_coef (j_compress_ptr cinfo, J_BUF_MODE pass_mode) +{ + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + c_coef_ptr coef = (c_coef_ptr) lossyc->coef_private; + + if (pass_mode != JBUF_CRANK_DEST) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + + coef->iMCU_row_num = 0; + start_iMCU_row(cinfo); +} + + +/* + * Process some data. + * We process the equivalent of one fully interleaved MCU row ("iMCU" row) + * per call, ie, v_samp_factor block rows for each component in the scan. + * The data is obtained from the virtual arrays and fed to the entropy coder. + * Returns TRUE if the iMCU row is completed, FALSE if suspended. + * + * NB: input_buf is ignored; it is likely to be a NULL pointer. + */ + +METHODDEF(boolean) +compress_output (j_compress_ptr cinfo, JSAMPIMAGE input_buf) +{ + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + c_coef_ptr coef = (c_coef_ptr) lossyc->coef_private; + JDIMENSION MCU_col_num; /* index of current MCU within row */ + JDIMENSION last_MCU_col = cinfo->MCUs_per_row - 1; + JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; + int blkn, ci, xindex, yindex, yoffset, blockcnt; + JDIMENSION start_col; + JBLOCKARRAY buffer[MAX_COMPS_IN_SCAN]; + JBLOCKROW MCU_buffer[C_MAX_DATA_UNITS_IN_MCU]; + JBLOCKROW buffer_ptr; + jpeg_component_info *compptr; + (void)input_buf; + + /* Align the virtual buffers for the components used in this scan. */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + buffer[ci] = (*cinfo->mem->access_virt_barray) + ((j_common_ptr) cinfo, coef->whole_image[compptr->component_index], + coef->iMCU_row_num * compptr->v_samp_factor, + (JDIMENSION) compptr->v_samp_factor, FALSE); + } + + /* Loop to process one whole iMCU row */ + for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row; + yoffset++) { + for (MCU_col_num = coef->mcu_ctr; MCU_col_num < cinfo->MCUs_per_row; + MCU_col_num++) { + /* Construct list of pointers to DCT blocks belonging to this MCU */ + blkn = 0; /* index of current DCT block within MCU */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + start_col = MCU_col_num * compptr->MCU_width; + blockcnt = (MCU_col_num < last_MCU_col) ? compptr->MCU_width + : compptr->last_col_width; + for (yindex = 0; yindex < compptr->MCU_height; yindex++) { + if (coef->iMCU_row_num < last_iMCU_row || + yindex+yoffset < compptr->last_row_height) { + /* Fill in pointers to real blocks in this row */ + buffer_ptr = buffer[ci][yindex+yoffset] + start_col; + for (xindex = 0; xindex < blockcnt; xindex++) + MCU_buffer[blkn++] = buffer_ptr++; + } else { + /* At bottom of image, need a whole row of dummy blocks */ + xindex = 0; + } + /* Fill in any dummy blocks needed in this row. + * Dummy blocks are filled in the same way as in jccoefct.c: + * all zeroes in the AC entries, DC entries equal to previous + * block's DC value. The init routine has already zeroed the + * AC entries, so we need only set the DC entries correctly. + */ + for (; xindex < compptr->MCU_width; xindex++) { + MCU_buffer[blkn] = coef->dummy_buffer[blkn]; + MCU_buffer[blkn][0][0] = MCU_buffer[blkn-1][0][0]; + blkn++; + } + } + } + /* Try to write the MCU. */ + if (! (*lossyc->entropy_encode_mcu) (cinfo, MCU_buffer)) { + /* Suspension forced; update state counters and exit */ + coef->MCU_vert_offset = yoffset; + coef->mcu_ctr = MCU_col_num; + return FALSE; + } + } + /* Completed an MCU row, but perhaps not an iMCU row */ + coef->mcu_ctr = 0; + } + /* Completed the iMCU row, advance counters for next one */ + coef->iMCU_row_num++; + start_iMCU_row(cinfo); + return TRUE; +} + + +/* + * Initialize coefficient buffer controller. + * + * Each passed coefficient array must be the right size for that + * coefficient: width_in_data_units wide and height_in_data_units high, + * with unitheight at least v_samp_factor. + */ + +LOCAL(void) +transencode_coef_controller (j_compress_ptr cinfo, + jvirt_barray_ptr * coef_arrays) +{ + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + c_coef_ptr coef; + JBLOCKROW buffer; + int i; + + coef = (c_coef_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(c_coef_controller)); + lossyc->coef_private = (struct jpeg_c_coef_controller *) coef; + + /* Save pointer to virtual arrays */ + coef->whole_image = coef_arrays; + + /* Allocate and pre-zero space for dummy DCT blocks. */ + buffer = (JBLOCKROW) + (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE, + C_MAX_DATA_UNITS_IN_MCU * SIZEOF(JBLOCK)); + jzero_far((void FAR *) buffer, C_MAX_DATA_UNITS_IN_MCU * SIZEOF(JBLOCK)); + for (i = 0; i < C_MAX_DATA_UNITS_IN_MCU; i++) { + coef->dummy_buffer[i] = buffer + i; + } +} + + +/* + * Initialize the transencoer codec. + * This is called only once, during master selection. + */ + +LOCAL(void) +transencode_codec (j_compress_ptr cinfo, + jvirt_barray_ptr * coef_arrays) +{ + j_lossy_c_ptr lossyc; + + /* Create subobject in permanent pool */ + lossyc = (j_lossy_c_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + SIZEOF(jpeg_lossy_c_codec)); + cinfo->codec = (struct jpeg_c_codec *) lossyc; + + /* Initialize sub-modules */ + + /* Entropy encoding: either Huffman or arithmetic coding. */ + if (cinfo->arith_code) { + jinit_arith_encoder(cinfo); + } else { + if (cinfo->process == JPROC_PROGRESSIVE) { +#ifdef C_PROGRESSIVE_SUPPORTED + jinit_phuff_encoder(cinfo); +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else + jinit_shuff_encoder(cinfo); + } + + /* We need a special coefficient buffer controller. */ + transencode_coef_controller(cinfo, coef_arrays); + + /* Initialize method pointers */ + lossyc->pub.start_pass = start_pass_coef; + lossyc->pub.compress_data = compress_output; +} diff --git a/Utilities/ITK/Utilities/itkjpeg/jdapimin.c b/Utilities/ITK/Utilities/itkjpeg/jdapimin.c new file mode 100644 index 0000000000000000000000000000000000000000..d13a1540ecd425871ea07a6236bc7efa5e5d63bd --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jdapimin.c @@ -0,0 +1,401 @@ +/* + * jdapimin.c + * + * Copyright (C) 1994-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains application interface code for the decompression half + * of the JPEG library. These are the "minimum" API routines that may be + * needed in either the normal full-decompression case or the + * transcoding-only case. + * + * Most of the routines intended to be called directly by an application + * are in this file or in jdapistd.c. But also see jcomapi.c for routines + * shared by compression and decompression, and jdtrans.c for the transcoding + * case. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* + * Initialization of a JPEG decompression object. + * The error manager must already be set up (in case memory manager fails). + */ + +GLOBAL(void) +jpeg_CreateDecompress (j_decompress_ptr cinfo, int version, size_t structsize) +{ + int i; + + /* Guard against version mismatches between library and caller. */ + cinfo->mem = NULL; /* so jpeg_destroy knows mem mgr not called */ + if (version != JPEG_LIB_VERSION) + ERREXIT2(cinfo, JERR_BAD_LIB_VERSION, JPEG_LIB_VERSION, version); + if (structsize != SIZEOF(struct jpeg_decompress_struct)) + ERREXIT2(cinfo, JERR_BAD_STRUCT_SIZE, + (int) SIZEOF(struct jpeg_decompress_struct), (int) structsize); + + /* For debugging purposes, we zero the whole master structure. + * But the application has already set the err pointer, and may have set + * client_data, so we have to save and restore those fields. + * Note: if application hasn't set client_data, tools like Purify may + * complain here. + */ + { + struct jpeg_error_mgr * err = cinfo->err; + void * client_data = cinfo->client_data; /* ignore Purify complaint here */ + MEMZERO(cinfo, SIZEOF(struct jpeg_decompress_struct)); + cinfo->err = err; + cinfo->client_data = client_data; + } + cinfo->is_decompressor = TRUE; + + /* Initialize a memory manager instance for this object */ + jinit_memory_mgr((j_common_ptr) cinfo); + + /* Zero out pointers to permanent structures. */ + cinfo->progress = NULL; + cinfo->src = NULL; + + for (i = 0; i < NUM_QUANT_TBLS; i++) + cinfo->quant_tbl_ptrs[i] = NULL; + + for (i = 0; i < NUM_HUFF_TBLS; i++) { + cinfo->dc_huff_tbl_ptrs[i] = NULL; + cinfo->ac_huff_tbl_ptrs[i] = NULL; + } + + /* Initialize marker processor so application can override methods + * for COM, APPn markers before calling jpeg_read_header. + */ + cinfo->marker_list = NULL; + jinit_marker_reader(cinfo); + + /* And initialize the overall input controller. */ + jinit_input_controller(cinfo); + + /* OK, I'm ready */ + cinfo->global_state = DSTATE_START; +} + + +/* + * Destruction of a JPEG decompression object + */ + +GLOBAL(void) +jpeg_destroy_decompress (j_decompress_ptr cinfo) +{ + jpeg_destroy((j_common_ptr) cinfo); /* use common routine */ +} + + +/* + * Abort processing of a JPEG decompression operation, + * but don't destroy the object itself. + */ + +GLOBAL(void) +jpeg_abort_decompress (j_decompress_ptr cinfo) +{ + jpeg_abort((j_common_ptr) cinfo); /* use common routine */ +} + + +/* + * Set default decompression parameters. + */ + +LOCAL(void) +default_decompress_parms (j_decompress_ptr cinfo) +{ + /* Guess the input colorspace, and set output colorspace accordingly. */ + /* (Wish JPEG committee had provided a real way to specify this...) */ + /* Note application may override our guesses. */ + switch (cinfo->num_components) { + case 1: + cinfo->jpeg_color_space = JCS_GRAYSCALE; + cinfo->out_color_space = JCS_GRAYSCALE; + break; + + case 3: + if (cinfo->saw_JFIF_marker) { + cinfo->jpeg_color_space = JCS_YCbCr; /* JFIF implies YCbCr */ + } else if (cinfo->saw_Adobe_marker) { + switch (cinfo->Adobe_transform) { + case 0: + cinfo->jpeg_color_space = JCS_RGB; + break; + case 1: + cinfo->jpeg_color_space = JCS_YCbCr; + break; + default: + WARNMS1(cinfo, JWRN_ADOBE_XFORM, cinfo->Adobe_transform); + cinfo->jpeg_color_space = JCS_YCbCr; /* assume it's YCbCr */ + break; + } + } else { + /* Saw no special markers, try to guess from the component IDs */ + int cid0 = cinfo->comp_info[0].component_id; + int cid1 = cinfo->comp_info[1].component_id; + int cid2 = cinfo->comp_info[2].component_id; + + if (cid0 == 1 && cid1 == 2 && cid2 == 3) + cinfo->jpeg_color_space = JCS_YCbCr; /* assume JFIF w/out marker */ + else if (cid0 == 82 && cid1 == 71 && cid2 == 66) + cinfo->jpeg_color_space = JCS_RGB; /* ASCII 'R', 'G', 'B' */ + else { + if (cinfo->process == JPROC_LOSSLESS) { + TRACEMS3(cinfo, 1, JTRC_UNKNOWN_LOSSLESS_IDS, cid0, cid1, cid2); + cinfo->jpeg_color_space = JCS_RGB; /* assume it's RGB */ + } + else { /* Lossy processes */ + TRACEMS3(cinfo, 1, JTRC_UNKNOWN_LOSSY_IDS, cid0, cid1, cid2); + cinfo->jpeg_color_space = JCS_YCbCr; /* assume it's YCbCr */ + } + } + } + /* Always guess RGB is proper output colorspace. */ + cinfo->out_color_space = JCS_RGB; + break; + + case 4: + if (cinfo->saw_Adobe_marker) { + switch (cinfo->Adobe_transform) { + case 0: + cinfo->jpeg_color_space = JCS_CMYK; + break; + case 2: + cinfo->jpeg_color_space = JCS_YCCK; + break; + default: + WARNMS1(cinfo, JWRN_ADOBE_XFORM, cinfo->Adobe_transform); + cinfo->jpeg_color_space = JCS_YCCK; /* assume it's YCCK */ + break; + } + } else { + /* No special markers, assume straight CMYK. */ + cinfo->jpeg_color_space = JCS_CMYK; + } + cinfo->out_color_space = JCS_CMYK; + break; + + default: + cinfo->jpeg_color_space = JCS_UNKNOWN; + cinfo->out_color_space = JCS_UNKNOWN; + break; + } + + /* Set defaults for other decompression parameters. */ + cinfo->scale_num = 1; /* 1:1 scaling */ + cinfo->scale_denom = 1; + cinfo->output_gamma = 1.0; + cinfo->buffered_image = FALSE; + cinfo->raw_data_out = FALSE; + cinfo->dct_method = JDCT_DEFAULT; + cinfo->do_fancy_upsampling = TRUE; + cinfo->do_block_smoothing = TRUE; + cinfo->quantize_colors = FALSE; + /* We set these in case application only sets quantize_colors. */ + cinfo->dither_mode = JDITHER_FS; +#ifdef QUANT_2PASS_SUPPORTED + cinfo->two_pass_quantize = TRUE; +#else + cinfo->two_pass_quantize = FALSE; +#endif + cinfo->desired_number_of_colors = 256; + cinfo->colormap = NULL; + /* Initialize for no mode change in buffered-image mode. */ + cinfo->enable_1pass_quant = FALSE; + cinfo->enable_external_quant = FALSE; + cinfo->enable_2pass_quant = FALSE; +} + + +/* + * Decompression startup: read start of JPEG datastream to see what's there. + * Need only initialize JPEG object and supply a data source before calling. + * + * This routine will read as far as the first SOS marker (ie, actual start of + * compressed data), and will save all tables and parameters in the JPEG + * object. It will also initialize the decompression parameters to default + * values, and finally return JPEG_HEADER_OK. On return, the application may + * adjust the decompression parameters and then call jpeg_start_decompress. + * (Or, if the application only wanted to determine the image parameters, + * the data need not be decompressed. In that case, call jpeg_abort or + * jpeg_destroy to release any temporary space.) + * If an abbreviated (tables only) datastream is presented, the routine will + * return JPEG_HEADER_TABLES_ONLY upon reaching EOI. The application may then + * re-use the JPEG object to read the abbreviated image datastream(s). + * It is unnecessary (but OK) to call jpeg_abort in this case. + * The JPEG_SUSPENDED return code only occurs if the data source module + * requests suspension of the decompressor. In this case the application + * should load more source data and then re-call jpeg_read_header to resume + * processing. + * If a non-suspending data source is used and require_image is TRUE, then the + * return code need not be inspected since only JPEG_HEADER_OK is possible. + * + * This routine is now just a front end to jpeg_consume_input, with some + * extra error checking. + */ + +GLOBAL(int) +jpeg_read_header (j_decompress_ptr cinfo, boolean require_image) +{ + int retcode; + + if (cinfo->global_state != DSTATE_START && + cinfo->global_state != DSTATE_INHEADER) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + retcode = jpeg_consume_input(cinfo); + + switch (retcode) { + case JPEG_REACHED_SOS: + retcode = JPEG_HEADER_OK; + break; + case JPEG_REACHED_EOI: + if (require_image) /* Complain if application wanted an image */ + ERREXIT(cinfo, JERR_NO_IMAGE); + /* Reset to start state; it would be safer to require the application to + * call jpeg_abort, but we can't change it now for compatibility reasons. + * A side effect is to free any temporary memory (there shouldn't be any). + */ + jpeg_abort((j_common_ptr) cinfo); /* sets state = DSTATE_START */ + retcode = JPEG_HEADER_TABLES_ONLY; + break; + case JPEG_SUSPENDED: + /* no work */ + break; + } + + return retcode; +} + + +/* + * Consume data in advance of what the decompressor requires. + * This can be called at any time once the decompressor object has + * been created and a data source has been set up. + * + * This routine is essentially a state machine that handles a couple + * of critical state-transition actions, namely initial setup and + * transition from header scanning to ready-for-start_decompress. + * All the actual input is done via the input controller's consume_input + * method. + */ + +GLOBAL(int) +jpeg_consume_input (j_decompress_ptr cinfo) +{ + int retcode = JPEG_SUSPENDED; + + /* NB: every possible DSTATE value should be listed in this switch */ + switch (cinfo->global_state) { + case DSTATE_START: + /* Start-of-datastream actions: reset appropriate modules */ + (*cinfo->inputctl->reset_input_controller) (cinfo); + /* Initialize application's data source module */ + (*cinfo->src->init_source) (cinfo); + cinfo->global_state = DSTATE_INHEADER; + /*FALLTHROUGH*/ + case DSTATE_INHEADER: + retcode = (*cinfo->inputctl->consume_input) (cinfo); + if (retcode == JPEG_REACHED_SOS) { /* Found SOS, prepare to decompress */ + /* Set up default parameters based on header data */ + default_decompress_parms(cinfo); + /* Set global state: ready for start_decompress */ + cinfo->global_state = DSTATE_READY; + } + break; + case DSTATE_READY: + /* Can't advance past first SOS until start_decompress is called */ + retcode = JPEG_REACHED_SOS; + break; + case DSTATE_PRELOAD: + case DSTATE_PRESCAN: + case DSTATE_SCANNING: + case DSTATE_RAW_OK: + case DSTATE_BUFIMAGE: + case DSTATE_BUFPOST: + case DSTATE_STOPPING: + retcode = (*cinfo->inputctl->consume_input) (cinfo); + break; + default: + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + } + return retcode; +} + + +/* + * Have we finished reading the input file? + */ + +GLOBAL(boolean) +jpeg_input_complete (j_decompress_ptr cinfo) +{ + /* Check for valid jpeg object */ + if (cinfo->global_state < DSTATE_START || + cinfo->global_state > DSTATE_STOPPING) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + return cinfo->inputctl->eoi_reached; +} + + +/* + * Is there more than one scan? + */ + +GLOBAL(boolean) +jpeg_has_multiple_scans (j_decompress_ptr cinfo) +{ + /* Only valid after jpeg_read_header completes */ + if (cinfo->global_state < DSTATE_READY || + cinfo->global_state > DSTATE_STOPPING) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + return cinfo->inputctl->has_multiple_scans; +} + + +/* + * Finish JPEG decompression. + * + * This will normally just verify the file trailer and release temp storage. + * + * Returns FALSE if suspended. The return value need be inspected only if + * a suspending data source is used. + */ + +GLOBAL(boolean) +jpeg_finish_decompress (j_decompress_ptr cinfo) +{ + if ((cinfo->global_state == DSTATE_SCANNING || + cinfo->global_state == DSTATE_RAW_OK) && ! cinfo->buffered_image) { + /* Terminate final pass of non-buffered mode */ + if (cinfo->output_scanline < cinfo->output_height) + ERREXIT(cinfo, JERR_TOO_LITTLE_DATA); + (*cinfo->master->finish_output_pass) (cinfo); + cinfo->global_state = DSTATE_STOPPING; + } else if (cinfo->global_state == DSTATE_BUFIMAGE) { + /* Finishing after a buffered-image operation */ + cinfo->global_state = DSTATE_STOPPING; + } else if (cinfo->global_state != DSTATE_STOPPING) { + /* STOPPING = repeat call after a suspension, anything else is error */ + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + } + /* Read until EOI */ + while (! cinfo->inputctl->eoi_reached) { + if ((*cinfo->inputctl->consume_input) (cinfo) == JPEG_SUSPENDED) + return FALSE; /* Suspend, come back later */ + } + /* Do final cleanup */ + (*cinfo->src->term_source) (cinfo); + /* We can use jpeg_abort to release memory and reset global_state */ + jpeg_abort((j_common_ptr) cinfo); + return TRUE; +} diff --git a/Utilities/ITK/Utilities/itkjpeg/jdapistd.c b/Utilities/ITK/Utilities/itkjpeg/jdapistd.c new file mode 100644 index 0000000000000000000000000000000000000000..4cc36d719cc18cf9eb85b5d354cfd0d81207c400 --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jdapistd.c @@ -0,0 +1,275 @@ +/* + * jdapistd.c + * + * Copyright (C) 1994-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains application interface code for the decompression half + * of the JPEG library. These are the "standard" API routines that are + * used in the normal full-decompression case. They are not used by a + * transcoding-only application. Note that if an application links in + * jpeg_start_decompress, it will end up linking in the entire decompressor. + * We thus must separate this file from jdapimin.c to avoid linking the + * whole decompression library into a transcoder. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Forward declarations */ +LOCAL(boolean) output_pass_setup JPP((j_decompress_ptr cinfo)); + + +/* + * Decompression initialization. + * jpeg_read_header must be completed before calling this. + * + * If a multipass operating mode was selected, this will do all but the + * last pass, and thus may take a great deal of time. + * + * Returns FALSE if suspended. The return value need be inspected only if + * a suspending data source is used. + */ + +GLOBAL(boolean) +jpeg_start_decompress (j_decompress_ptr cinfo) +{ + if (cinfo->global_state == DSTATE_READY) { + /* First call: initialize master control, select active modules */ + jinit_master_decompress(cinfo); + if (cinfo->buffered_image) { + /* No more work here; expecting jpeg_start_output next */ + cinfo->global_state = DSTATE_BUFIMAGE; + return TRUE; + } + cinfo->global_state = DSTATE_PRELOAD; + } + if (cinfo->global_state == DSTATE_PRELOAD) { + /* If file has multiple scans, absorb them all into the coef buffer */ + if (cinfo->inputctl->has_multiple_scans) { +#ifdef D_MULTISCAN_FILES_SUPPORTED + for (;;) { + int retcode; + /* Call progress monitor hook if present */ + if (cinfo->progress != NULL) + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + /* Absorb some more input */ + retcode = (*cinfo->inputctl->consume_input) (cinfo); + if (retcode == JPEG_SUSPENDED) + return FALSE; + if (retcode == JPEG_REACHED_EOI) + break; + /* Advance progress counter if appropriate */ + if (cinfo->progress != NULL && + (retcode == JPEG_ROW_COMPLETED || retcode == JPEG_REACHED_SOS)) { + if (++cinfo->progress->pass_counter >= cinfo->progress->pass_limit) { + /* jdmaster underestimated number of scans; ratchet up one scan */ + cinfo->progress->pass_limit += (long) cinfo->total_iMCU_rows; + } + } + } +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif /* D_MULTISCAN_FILES_SUPPORTED */ + } + cinfo->output_scan_number = cinfo->input_scan_number; + } else if (cinfo->global_state != DSTATE_PRESCAN) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + /* Perform any dummy output passes, and set up for the final pass */ + return output_pass_setup(cinfo); +} + + +/* + * Set up for an output pass, and perform any dummy pass(es) needed. + * Common subroutine for jpeg_start_decompress and jpeg_start_output. + * Entry: global_state = DSTATE_PRESCAN only if previously suspended. + * Exit: If done, returns TRUE and sets global_state for proper output mode. + * If suspended, returns FALSE and sets global_state = DSTATE_PRESCAN. + */ + +LOCAL(boolean) +output_pass_setup (j_decompress_ptr cinfo) +{ + if (cinfo->global_state != DSTATE_PRESCAN) { + /* First call: do pass setup */ + (*cinfo->master->prepare_for_output_pass) (cinfo); + cinfo->output_scanline = 0; + cinfo->global_state = DSTATE_PRESCAN; + } + /* Loop over any required dummy passes */ + while (cinfo->master->is_dummy_pass) { +#ifdef QUANT_2PASS_SUPPORTED + /* Crank through the dummy pass */ + while (cinfo->output_scanline < cinfo->output_height) { + JDIMENSION last_scanline; + /* Call progress monitor hook if present */ + if (cinfo->progress != NULL) { + cinfo->progress->pass_counter = (long) cinfo->output_scanline; + cinfo->progress->pass_limit = (long) cinfo->output_height; + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + } + /* Process some data */ + last_scanline = cinfo->output_scanline; + (*cinfo->main->process_data) (cinfo, (JSAMPARRAY) NULL, + &cinfo->output_scanline, (JDIMENSION) 0); + if (cinfo->output_scanline == last_scanline) + return FALSE; /* No progress made, must suspend */ + } + /* Finish up dummy pass, and set up for another one */ + (*cinfo->master->finish_output_pass) (cinfo); + (*cinfo->master->prepare_for_output_pass) (cinfo); + cinfo->output_scanline = 0; +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif /* QUANT_2PASS_SUPPORTED */ + } + /* Ready for application to drive output pass through + * jpeg_read_scanlines or jpeg_read_raw_data. + */ + cinfo->global_state = cinfo->raw_data_out ? DSTATE_RAW_OK : DSTATE_SCANNING; + return TRUE; +} + + +/* + * Read some scanlines of data from the JPEG decompressor. + * + * The return value will be the number of lines actually read. + * This may be less than the number requested in several cases, + * including bottom of image, data source suspension, and operating + * modes that emit multiple scanlines at a time. + * + * Note: we warn about excess calls to jpeg_read_scanlines() since + * this likely signals an application programmer error. However, + * an oversize buffer (max_lines > scanlines remaining) is not an error. + */ + +GLOBAL(JDIMENSION) +jpeg_read_scanlines (j_decompress_ptr cinfo, JSAMPARRAY scanlines, + JDIMENSION max_lines) +{ + JDIMENSION row_ctr; + + if (cinfo->global_state != DSTATE_SCANNING) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + if (cinfo->output_scanline >= cinfo->output_height) { + WARNMS(cinfo, JWRN_TOO_MUCH_DATA); + return 0; + } + + /* Call progress monitor hook if present */ + if (cinfo->progress != NULL) { + cinfo->progress->pass_counter = (long) cinfo->output_scanline; + cinfo->progress->pass_limit = (long) cinfo->output_height; + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + } + + /* Process some data */ + row_ctr = 0; + (*cinfo->main->process_data) (cinfo, scanlines, &row_ctr, max_lines); + cinfo->output_scanline += row_ctr; + return row_ctr; +} + + +/* + * Alternate entry point to read raw data. + * Processes exactly one iMCU row per call, unless suspended. + */ + +GLOBAL(JDIMENSION) +jpeg_read_raw_data (j_decompress_ptr cinfo, JSAMPIMAGE data, + JDIMENSION max_lines) +{ + JDIMENSION lines_per_iMCU_row; + + if (cinfo->global_state != DSTATE_RAW_OK) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + if (cinfo->output_scanline >= cinfo->output_height) { + WARNMS(cinfo, JWRN_TOO_MUCH_DATA); + return 0; + } + + /* Call progress monitor hook if present */ + if (cinfo->progress != NULL) { + cinfo->progress->pass_counter = (long) cinfo->output_scanline; + cinfo->progress->pass_limit = (long) cinfo->output_height; + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + } + + /* Verify that at least one iMCU row can be returned. */ + lines_per_iMCU_row = cinfo->max_v_samp_factor * cinfo->min_codec_data_unit; + if (max_lines < lines_per_iMCU_row) + ERREXIT(cinfo, JERR_BUFFER_SIZE); + + /* Decompress directly into user's buffer. */ + if (! (*cinfo->codec->decompress_data) (cinfo, data)) + return 0; /* suspension forced, can do nothing more */ + + /* OK, we processed one iMCU row. */ + cinfo->output_scanline += lines_per_iMCU_row; + return lines_per_iMCU_row; +} + + +/* Additional entry points for buffered-image mode. */ + +#ifdef D_MULTISCAN_FILES_SUPPORTED + +/* + * Initialize for an output pass in buffered-image mode. + */ + +GLOBAL(boolean) +jpeg_start_output (j_decompress_ptr cinfo, int scan_number) +{ + if (cinfo->global_state != DSTATE_BUFIMAGE && + cinfo->global_state != DSTATE_PRESCAN) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + /* Limit scan number to valid range */ + if (scan_number <= 0) + scan_number = 1; + if (cinfo->inputctl->eoi_reached && + scan_number > cinfo->input_scan_number) + scan_number = cinfo->input_scan_number; + cinfo->output_scan_number = scan_number; + /* Perform any dummy output passes, and set up for the real pass */ + return output_pass_setup(cinfo); +} + + +/* + * Finish up after an output pass in buffered-image mode. + * + * Returns FALSE if suspended. The return value need be inspected only if + * a suspending data source is used. + */ + +GLOBAL(boolean) +jpeg_finish_output (j_decompress_ptr cinfo) +{ + if ((cinfo->global_state == DSTATE_SCANNING || + cinfo->global_state == DSTATE_RAW_OK) && cinfo->buffered_image) { + /* Terminate this pass. */ + /* We do not require the whole pass to have been completed. */ + (*cinfo->master->finish_output_pass) (cinfo); + cinfo->global_state = DSTATE_BUFPOST; + } else if (cinfo->global_state != DSTATE_BUFPOST) { + /* BUFPOST = repeat call after a suspension, anything else is error */ + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + } + /* Read markers looking for SOS or EOI */ + while (cinfo->input_scan_number <= cinfo->output_scan_number && + ! cinfo->inputctl->eoi_reached) { + if ((*cinfo->inputctl->consume_input) (cinfo) == JPEG_SUSPENDED) + return FALSE; /* Suspend, come back later */ + } + cinfo->global_state = DSTATE_BUFIMAGE; + return TRUE; +} + +#endif /* D_MULTISCAN_FILES_SUPPORTED */ diff --git a/Utilities/ITK/Utilities/itkjpeg/jdarith.c b/Utilities/ITK/Utilities/itkjpeg/jdarith.c new file mode 100644 index 0000000000000000000000000000000000000000..52eb79d7af0b32eb23e7f9fb56cffe644bd082ed --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jdarith.c @@ -0,0 +1,24 @@ +/* + * jdarith.c + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file holds place for arithmetic entropy decoding routines. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* + * Module initialization routine for arithmetic entropy decoding. + */ + +GLOBAL(void) +jinit_arith_decoder (j_decompress_ptr cinfo) +{ + ERREXIT(cinfo, JERR_ARITH_NOTIMPL); +} diff --git a/Utilities/ITK/Utilities/itkjpeg/jdatadst.c b/Utilities/ITK/Utilities/itkjpeg/jdatadst.c new file mode 100644 index 0000000000000000000000000000000000000000..88d859d210238daa04e630429f2c918513743854 --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jdatadst.c @@ -0,0 +1,151 @@ +/* + * jdatadst.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains compression data destination routines for the case of + * emitting JPEG data to a file (or any stdio stream). While these routines + * are sufficient for most applications, some will want to use a different + * destination manager. + * IMPORTANT: we assume that fwrite() will correctly transcribe an array of + * JOCTETs into 8-bit-wide elements on external storage. If char is wider + * than 8 bits on your machine, you may need to do some tweaking. + */ + +/* this is not a core library module, so it doesn't define JPEG_INTERNALS */ +#include "jinclude.h" +#include "jpeglib.h" +#include "jerror.h" + + +/* Expanded data destination object for stdio output */ + +typedef struct { + struct jpeg_destination_mgr pub; /* public fields */ + + FILE * outfile; /* target stream */ + JOCTET * buffer; /* start of buffer */ +} my_destination_mgr; + +typedef my_destination_mgr * my_dest_ptr; + +#define OUTPUT_BUF_SIZE 4096 /* choose an efficiently fwrite'able size */ + + +/* + * Initialize destination --- called by jpeg_start_compress + * before any data is actually written. + */ + +METHODDEF(void) +init_destination (j_compress_ptr cinfo) +{ + my_dest_ptr dest = (my_dest_ptr) cinfo->dest; + + /* Allocate the output buffer --- it will be released when done with image */ + dest->buffer = (JOCTET *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + OUTPUT_BUF_SIZE * SIZEOF(JOCTET)); + + dest->pub.next_output_byte = dest->buffer; + dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; +} + + +/* + * Empty the output buffer --- called whenever buffer fills up. + * + * In typical applications, this should write the entire output buffer + * (ignoring the current state of next_output_byte & free_in_buffer), + * reset the pointer & count to the start of the buffer, and return TRUE + * indicating that the buffer has been dumped. + * + * In applications that need to be able to suspend compression due to output + * overrun, a FALSE return indicates that the buffer cannot be emptied now. + * In this situation, the compressor will return to its caller (possibly with + * an indication that it has not accepted all the supplied scanlines). The + * application should resume compression after it has made more room in the + * output buffer. Note that there are substantial restrictions on the use of + * suspension --- see the documentation. + * + * When suspending, the compressor will back up to a convenient restart point + * (typically the start of the current MCU). next_output_byte & free_in_buffer + * indicate where the restart point will be if the current call returns FALSE. + * Data beyond this point will be regenerated after resumption, so do not + * write it out when emptying the buffer externally. + */ + +METHODDEF(boolean) +empty_output_buffer (j_compress_ptr cinfo) +{ + my_dest_ptr dest = (my_dest_ptr) cinfo->dest; + + if (JFWRITE(dest->outfile, dest->buffer, OUTPUT_BUF_SIZE) != + (size_t) OUTPUT_BUF_SIZE) + ERREXIT(cinfo, JERR_FILE_WRITE); + + dest->pub.next_output_byte = dest->buffer; + dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; + + return TRUE; +} + + +/* + * Terminate destination --- called by jpeg_finish_compress + * after all data has been written. Usually needs to flush buffer. + * + * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding + * application must deal with any cleanup that should happen even + * for error exit. + */ + +METHODDEF(void) +term_destination (j_compress_ptr cinfo) +{ + my_dest_ptr dest = (my_dest_ptr) cinfo->dest; + size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer; + + /* Write any data remaining in the buffer */ + if (datacount > 0) { + if (JFWRITE(dest->outfile, dest->buffer, datacount) != datacount) + ERREXIT(cinfo, JERR_FILE_WRITE); + } + fflush(dest->outfile); + /* Make sure we wrote the output file OK */ + if (ferror(dest->outfile)) + ERREXIT(cinfo, JERR_FILE_WRITE); +} + + +/* + * Prepare for output to a stdio stream. + * The caller must have already opened the stream, and is responsible + * for closing it after finishing compression. + */ + +GLOBAL(void) +jpeg_stdio_dest (j_compress_ptr cinfo, FILE * outfile) +{ + my_dest_ptr dest; + + /* The destination object is made permanent so that multiple JPEG images + * can be written to the same file without re-executing jpeg_stdio_dest. + * This makes it dangerous to use this manager and a different destination + * manager serially with the same JPEG object, because their private object + * sizes may be different. Caveat programmer. + */ + if (cinfo->dest == NULL) { /* first time for this JPEG object? */ + cinfo->dest = (struct jpeg_destination_mgr *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + SIZEOF(my_destination_mgr)); + } + + dest = (my_dest_ptr) cinfo->dest; + dest->pub.init_destination = init_destination; + dest->pub.empty_output_buffer = empty_output_buffer; + dest->pub.term_destination = term_destination; + dest->outfile = outfile; +} diff --git a/Utilities/ITK/Utilities/itkjpeg/jdatasrc.c b/Utilities/ITK/Utilities/itkjpeg/jdatasrc.c new file mode 100644 index 0000000000000000000000000000000000000000..531c90b34ee996f63fee1ab817efdbf47b4d45d5 --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jdatasrc.c @@ -0,0 +1,213 @@ +/* + * jdatasrc.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains decompression data source routines for the case of + * reading JPEG data from a file (or any stdio stream). While these routines + * are sufficient for most applications, some will want to use a different + * source manager. + * IMPORTANT: we assume that fread() will correctly transcribe an array of + * JOCTETs from 8-bit-wide elements on external storage. If char is wider + * than 8 bits on your machine, you may need to do some tweaking. + */ + +/* this is not a core library module, so it doesn't define JPEG_INTERNALS */ +#include "jinclude.h" +#include "jpeglib.h" +#include "jerror.h" + + +/* Expanded data source object for stdio input */ + +typedef struct { + struct jpeg_source_mgr pub; /* public fields */ + + FILE * infile; /* source stream */ + JOCTET * buffer; /* start of buffer */ + boolean start_of_file; /* have we gotten any data yet? */ +} my_source_mgr; + +typedef my_source_mgr * my_src_ptr; + +#define INPUT_BUF_SIZE 4096 /* choose an efficiently fread'able size */ + + +/* + * Initialize source --- called by jpeg_read_header + * before any data is actually read. + */ + +METHODDEF(void) +init_source (j_decompress_ptr cinfo) +{ + my_src_ptr src = (my_src_ptr) cinfo->src; + + /* We reset the empty-input-file flag for each image, + * but we don't clear the input buffer. + * This is correct behavior for reading a series of images from one source. + */ + src->start_of_file = TRUE; +} + + +/* + * Fill the input buffer --- called whenever buffer is emptied. + * + * In typical applications, this should read fresh data into the buffer + * (ignoring the current state of next_input_byte & bytes_in_buffer), + * reset the pointer & count to the start of the buffer, and return TRUE + * indicating that the buffer has been reloaded. It is not necessary to + * fill the buffer entirely, only to obtain at least one more byte. + * + * There is no such thing as an EOF return. If the end of the file has been + * reached, the routine has a choice of ERREXIT() or inserting fake data into + * the buffer. In most cases, generating a warning message and inserting a + * fake EOI marker is the best course of action --- this will allow the + * decompressor to output however much of the image is there. However, + * the resulting error message is misleading if the real problem is an empty + * input file, so we handle that case specially. + * + * In applications that need to be able to suspend compression due to input + * not being available yet, a FALSE return indicates that no more data can be + * obtained right now, but more may be forthcoming later. In this situation, + * the decompressor will return to its caller (with an indication of the + * number of scanlines it has read, if any). The application should resume + * decompression after it has loaded more data into the input buffer. Note + * that there are substantial restrictions on the use of suspension --- see + * the documentation. + * + * When suspending, the decompressor will back up to a convenient restart point + * (typically the start of the current MCU). next_input_byte & bytes_in_buffer + * indicate where the restart point will be if the current call returns FALSE. + * Data beyond this point must be rescanned after resumption, so move it to + * the front of the buffer rather than discarding it. + */ + +METHODDEF(boolean) +fill_input_buffer (j_decompress_ptr cinfo) +{ + my_src_ptr src = (my_src_ptr) cinfo->src; + size_t nbytes; + + nbytes = JFREAD(src->infile, src->buffer, INPUT_BUF_SIZE); + + if (nbytes <= 0) { + if (src->start_of_file) /* Treat empty input file as fatal error */ + ERREXIT(cinfo, JERR_INPUT_EMPTY); + WARNMS(cinfo, JWRN_JPEG_EOF); + /* Insert a fake EOI marker */ + src->buffer[0] = (JOCTET) 0xFF; + src->buffer[1] = (JOCTET) JPEG_EOI; + nbytes = 2; + } + + src->pub.next_input_byte = src->buffer; + src->pub.bytes_in_buffer = nbytes; + src->start_of_file = FALSE; + + return TRUE; +} + + +/* + * Skip data --- used to skip over a potentially large amount of + * uninteresting data (such as an APPn marker). + * + * Writers of suspendable-input applications must note that skip_input_data + * is not granted the right to give a suspension return. If the skip extends + * beyond the data currently in the buffer, the buffer can be marked empty so + * that the next read will cause a fill_input_buffer call that can suspend. + * Arranging for additional bytes to be discarded before reloading the input + * buffer is the application writer's problem. + */ + +METHODDEF(void) +skip_input_data (j_decompress_ptr cinfo, long num_bytes) +{ + my_src_ptr src = (my_src_ptr) cinfo->src; + + /* Just a dumb implementation for now. Could use fseek() except + * it doesn't work on pipes. Not clear that being smart is worth + * any trouble anyway --- large skips are infrequent. + */ + if (num_bytes > 0) { + while (num_bytes > (long) src->pub.bytes_in_buffer) { + num_bytes -= (long) src->pub.bytes_in_buffer; + (void) fill_input_buffer(cinfo); + /* note we assume that fill_input_buffer will never return FALSE, + * so suspension need not be handled. + */ + } + src->pub.next_input_byte += (size_t) num_bytes; + src->pub.bytes_in_buffer -= (size_t) num_bytes; + } +} + + +/* + * An additional method that can be provided by data source modules is the + * resync_to_restart method for error recovery in the presence of RST markers. + * For the moment, this source module just uses the default resync method + * provided by the JPEG library. That method assumes that no backtracking + * is possible. + */ + + +/* + * Terminate source --- called by jpeg_finish_decompress + * after all data has been read. Often a no-op. + * + * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding + * application must deal with any cleanup that should happen even + * for error exit. + */ + +METHODDEF(void) +term_source (j_decompress_ptr cinfo) +{ + (void)cinfo; + /* no work necessary here */ +} + + +/* + * Prepare for input from a stdio stream. + * The caller must have already opened the stream, and is responsible + * for closing it after finishing decompression. + */ + +GLOBAL(void) +jpeg_stdio_src (j_decompress_ptr cinfo, FILE * infile) +{ + my_src_ptr src; + + /* The source object and input buffer are made permanent so that a series + * of JPEG images can be read from the same file by calling jpeg_stdio_src + * only before the first one. (If we discarded the buffer at the end of + * one image, we'd likely lose the start of the next one.) + * This makes it unsafe to use this manager and a different source + * manager serially with the same JPEG object. Caveat programmer. + */ + if (cinfo->src == NULL) { /* first time for this JPEG object? */ + cinfo->src = (struct jpeg_source_mgr *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + SIZEOF(my_source_mgr)); + src = (my_src_ptr) cinfo->src; + src->buffer = (JOCTET *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + INPUT_BUF_SIZE * SIZEOF(JOCTET)); + } + + src = (my_src_ptr) cinfo->src; + src->pub.init_source = init_source; + src->pub.fill_input_buffer = fill_input_buffer; + src->pub.skip_input_data = skip_input_data; + src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */ + src->pub.term_source = term_source; + src->infile = infile; + src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */ + src->pub.next_input_byte = NULL; /* until buffer loaded */ +} diff --git a/Utilities/ITK/Utilities/itkjpeg/jdcoefct.c b/Utilities/ITK/Utilities/itkjpeg/jdcoefct.c new file mode 100644 index 0000000000000000000000000000000000000000..2e5ec1100c0d3a3fa8a9b6aa927078a20fbd5671 --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jdcoefct.c @@ -0,0 +1,744 @@ +/* + * jdcoefct.c + * + * Copyright (C) 1994-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the coefficient buffer controller for decompression. + * This controller is the top level of the lossy JPEG decompressor proper. + * The coefficient buffer lies between entropy decoding and inverse-DCT steps. + * + * In buffered-image mode, this controller is the interface between + * input-oriented processing and output-oriented processing. + * Also, the input side (only) is used when reading a file for transcoding. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jlossy.h" + +/* Block smoothing is only applicable for progressive JPEG, so: */ +#ifndef D_PROGRESSIVE_SUPPORTED +#undef BLOCK_SMOOTHING_SUPPORTED +#endif + +/* Private buffer controller object */ + +typedef struct { + /* These variables keep track of the current location of the input side. */ + /* cinfo->input_iMCU_row is also used for this. */ + JDIMENSION MCU_ctr; /* counts MCUs processed in current row */ + int MCU_vert_offset; /* counts MCU rows within iMCU row */ + int MCU_rows_per_iMCU_row; /* number of such rows needed */ + + /* The output side's location is represented by cinfo->output_iMCU_row. */ + + /* In single-pass modes, it's sufficient to buffer just one MCU. + * We allocate a workspace of D_MAX_DATA_UNITS_IN_MCU coefficient blocks, + * and let the entropy decoder write into that workspace each time. + * (On 80x86, the workspace is FAR even though it's not really very big; + * this is to keep the module interfaces unchanged when a large coefficient + * buffer is necessary.) + * In multi-pass modes, this array points to the current MCU's blocks + * within the virtual arrays; it is used only by the input side. + */ + JBLOCKROW MCU_buffer[D_MAX_DATA_UNITS_IN_MCU]; + +#ifdef D_MULTISCAN_FILES_SUPPORTED + /* In multi-pass modes, we need a virtual block array for each component. */ + jvirt_barray_ptr whole_image[MAX_COMPONENTS]; +#endif + +#ifdef BLOCK_SMOOTHING_SUPPORTED + /* When doing block smoothing, we latch coefficient Al values here */ + int * coef_bits_latch; +#define SAVED_COEFS 6 /* we save coef_bits[0..5] */ +#endif +} d_coef_controller; + +typedef d_coef_controller * d_coef_ptr; + +/* Forward declarations */ +METHODDEF(int) decompress_onepass + JPP((j_decompress_ptr cinfo, JSAMPIMAGE output_buf)); +#ifdef D_MULTISCAN_FILES_SUPPORTED +METHODDEF(int) decompress_data + JPP((j_decompress_ptr cinfo, JSAMPIMAGE output_buf)); +#endif +#ifdef BLOCK_SMOOTHING_SUPPORTED +LOCAL(boolean) smoothing_ok JPP((j_decompress_ptr cinfo)); +METHODDEF(int) decompress_smooth_data + JPP((j_decompress_ptr cinfo, JSAMPIMAGE output_buf)); +#endif + + +LOCAL(void) +start_iMCU_row (j_decompress_ptr cinfo) +/* Reset within-iMCU-row counters for a new row (input side) */ +{ + j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; + d_coef_ptr coef = (d_coef_ptr) lossyd->coef_private; + + /* In an interleaved scan, an MCU row is the same as an iMCU row. + * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows. + * But at the bottom of the image, process only what's left. + */ + if (cinfo->comps_in_scan > 1) { + coef->MCU_rows_per_iMCU_row = 1; + } else { + if (cinfo->input_iMCU_row < (cinfo->total_iMCU_rows-1)) + coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor; + else + coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height; + } + + coef->MCU_ctr = 0; + coef->MCU_vert_offset = 0; +} + + +/* + * Initialize for an input processing pass. + */ + +METHODDEF(void) +start_input_pass (j_decompress_ptr cinfo) +{ + cinfo->input_iMCU_row = 0; + start_iMCU_row(cinfo); +} + + +/* + * Initialize for an output processing pass. + */ + +METHODDEF(void) +start_output_pass (j_decompress_ptr cinfo) +{ +#ifdef BLOCK_SMOOTHING_SUPPORTED + j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; + /* d_coef_ptr coef = (d_coef_ptr) lossyd->coef_private; */ + + /* If multipass, check to see whether to use block smoothing on this pass */ + if (lossyd->coef_arrays != NULL) { + if (cinfo->do_block_smoothing && smoothing_ok(cinfo)) + lossyd->pub.decompress_data = decompress_smooth_data; + else + lossyd->pub.decompress_data = decompress_data; + } +#endif + cinfo->output_iMCU_row = 0; +} + + +/* + * Decompress and return some data in the single-pass case. + * Always attempts to emit one fully interleaved MCU row ("iMCU" row). + * Input and output must run in lockstep since we have only a one-MCU buffer. + * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED. + * + * NB: output_buf contains a plane for each component in image, + * which we index according to the component's SOF position. + */ + +METHODDEF(int) +decompress_onepass (j_decompress_ptr cinfo, JSAMPIMAGE output_buf) +{ + j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; + d_coef_ptr coef = (d_coef_ptr) lossyd->coef_private; + JDIMENSION MCU_col_num; /* index of current MCU within row */ + JDIMENSION last_MCU_col = cinfo->MCUs_per_row - 1; + JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; + int blkn, ci, xindex, yindex, yoffset, useful_width; + JSAMPARRAY output_ptr; + JDIMENSION start_col, output_col; + jpeg_component_info *compptr; + inverse_DCT_method_ptr inverse_DCT; + + /* Loop to process as much as one whole iMCU row */ + for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row; + yoffset++) { + for (MCU_col_num = coef->MCU_ctr; MCU_col_num <= last_MCU_col; + MCU_col_num++) { + /* Try to fetch an MCU. Entropy decoder expects buffer to be zeroed. */ + jzero_far((void FAR *) coef->MCU_buffer[0], + (size_t) (cinfo->data_units_in_MCU * SIZEOF(JBLOCK))); + if (! (*lossyd->entropy_decode_mcu) (cinfo, coef->MCU_buffer)) { + /* Suspension forced; update state counters and exit */ + coef->MCU_vert_offset = yoffset; + coef->MCU_ctr = MCU_col_num; + return JPEG_SUSPENDED; + } + /* Determine where data should go in output_buf and do the IDCT thing. + * We skip dummy blocks at the right and bottom edges (but blkn gets + * incremented past them!). Note the inner loop relies on having + * allocated the MCU_buffer[] blocks sequentially. + */ + blkn = 0; /* index of current DCT block within MCU */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + /* Don't bother to IDCT an uninteresting component. */ + if (! compptr->component_needed) { + blkn += compptr->MCU_data_units; + continue; + } + inverse_DCT = lossyd->inverse_DCT[compptr->component_index]; + useful_width = (MCU_col_num < last_MCU_col) ? compptr->MCU_width + : compptr->last_col_width; + output_ptr = output_buf[compptr->component_index] + + yoffset * compptr->codec_data_unit; + start_col = MCU_col_num * compptr->MCU_sample_width; + for (yindex = 0; yindex < compptr->MCU_height; yindex++) { + if (cinfo->input_iMCU_row < last_iMCU_row || + yoffset+yindex < compptr->last_row_height) { + output_col = start_col; + for (xindex = 0; xindex < useful_width; xindex++) { + (*inverse_DCT) (cinfo, compptr, + (JCOEFPTR) coef->MCU_buffer[blkn+xindex], + output_ptr, output_col); + output_col += compptr->codec_data_unit; + } + } + blkn += compptr->MCU_width; + output_ptr += compptr->codec_data_unit; + } + } + } + /* Completed an MCU row, but perhaps not an iMCU row */ + coef->MCU_ctr = 0; + } + /* Completed the iMCU row, advance counters for next one */ + cinfo->output_iMCU_row++; + if (++(cinfo->input_iMCU_row) < cinfo->total_iMCU_rows) { + start_iMCU_row(cinfo); + return JPEG_ROW_COMPLETED; + } + /* Completed the scan */ + (*cinfo->inputctl->finish_input_pass) (cinfo); + return JPEG_SCAN_COMPLETED; +} + + +/* + * Dummy consume-input routine for single-pass operation. + */ + +METHODDEF(int) +dummy_consume_data (j_decompress_ptr cinfo) +{ + (void)cinfo; + return JPEG_SUSPENDED; /* Always indicate nothing was done */ +} + + +#ifdef D_MULTISCAN_FILES_SUPPORTED + +/* + * Consume input data and store it in the full-image coefficient buffer. + * We read as much as one fully interleaved MCU row ("iMCU" row) per call, + * ie, v_samp_factor block rows for each component in the scan. + * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED. + */ + +METHODDEF(int) +consume_data (j_decompress_ptr cinfo) +{ + j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; + d_coef_ptr coef = (d_coef_ptr) lossyd->coef_private; + JDIMENSION MCU_col_num; /* index of current MCU within row */ + int blkn, ci, xindex, yindex, yoffset; + JDIMENSION start_col; + JBLOCKARRAY buffer[MAX_COMPS_IN_SCAN]; + JBLOCKROW buffer_ptr; + jpeg_component_info *compptr; + + /* Align the virtual buffers for the components used in this scan. */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + buffer[ci] = (*cinfo->mem->access_virt_barray) + ((j_common_ptr) cinfo, coef->whole_image[compptr->component_index], + cinfo->input_iMCU_row * compptr->v_samp_factor, + (JDIMENSION) compptr->v_samp_factor, TRUE); + /* Note: entropy decoder expects buffer to be zeroed, + * but this is handled automatically by the memory manager + * because we requested a pre-zeroed array. + */ + } + + /* Loop to process one whole iMCU row */ + for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row; + yoffset++) { + for (MCU_col_num = coef->MCU_ctr; MCU_col_num < cinfo->MCUs_per_row; + MCU_col_num++) { + /* Construct list of pointers to DCT blocks belonging to this MCU */ + blkn = 0; /* index of current DCT block within MCU */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + start_col = MCU_col_num * compptr->MCU_width; + for (yindex = 0; yindex < compptr->MCU_height; yindex++) { + buffer_ptr = buffer[ci][yindex+yoffset] + start_col; + for (xindex = 0; xindex < compptr->MCU_width; xindex++) { + coef->MCU_buffer[blkn++] = buffer_ptr++; + } + } + } + /* Try to fetch the MCU. */ + if (! (*lossyd->entropy_decode_mcu) (cinfo, coef->MCU_buffer)) { + /* Suspension forced; update state counters and exit */ + coef->MCU_vert_offset = yoffset; + coef->MCU_ctr = MCU_col_num; + return JPEG_SUSPENDED; + } + } + /* Completed an MCU row, but perhaps not an iMCU row */ + coef->MCU_ctr = 0; + } + /* Completed the iMCU row, advance counters for next one */ + if (++(cinfo->input_iMCU_row) < cinfo->total_iMCU_rows) { + start_iMCU_row(cinfo); + return JPEG_ROW_COMPLETED; + } + /* Completed the scan */ + (*cinfo->inputctl->finish_input_pass) (cinfo); + return JPEG_SCAN_COMPLETED; +} + + +/* + * Decompress and return some data in the multi-pass case. + * Always attempts to emit one fully interleaved MCU row ("iMCU" row). + * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED. + * + * NB: output_buf contains a plane for each component in image. + */ + +METHODDEF(int) +decompress_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf) +{ + j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; + d_coef_ptr coef = (d_coef_ptr) lossyd->coef_private; + JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; + JDIMENSION block_num; + int ci, block_row, block_rows; + JBLOCKARRAY buffer; + JBLOCKROW buffer_ptr; + JSAMPARRAY output_ptr; + JDIMENSION output_col; + jpeg_component_info *compptr; + inverse_DCT_method_ptr inverse_DCT; + + /* Force some input to be done if we are getting ahead of the input. */ + while (cinfo->input_scan_number < cinfo->output_scan_number || + (cinfo->input_scan_number == cinfo->output_scan_number && + cinfo->input_iMCU_row <= cinfo->output_iMCU_row)) { + if ((*cinfo->inputctl->consume_input)(cinfo) == JPEG_SUSPENDED) + return JPEG_SUSPENDED; + } + + /* OK, output from the virtual arrays. */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Don't bother to IDCT an uninteresting component. */ + if (! compptr->component_needed) + continue; + /* Align the virtual buffer for this component. */ + buffer = (*cinfo->mem->access_virt_barray) + ((j_common_ptr) cinfo, coef->whole_image[ci], + cinfo->output_iMCU_row * compptr->v_samp_factor, + (JDIMENSION) compptr->v_samp_factor, FALSE); + /* Count non-dummy DCT block rows in this iMCU row. */ + if (cinfo->output_iMCU_row < last_iMCU_row) + block_rows = compptr->v_samp_factor; + else { + /* NB: can't use last_row_height here; it is input-side-dependent! */ + block_rows = (int) (compptr->height_in_data_units % compptr->v_samp_factor); + if (block_rows == 0) block_rows = compptr->v_samp_factor; + } + inverse_DCT = lossyd->inverse_DCT[ci]; + output_ptr = output_buf[ci]; + /* Loop over all DCT blocks to be processed. */ + for (block_row = 0; block_row < block_rows; block_row++) { + buffer_ptr = buffer[block_row]; + output_col = 0; + for (block_num = 0; block_num < compptr->width_in_data_units; block_num++) { + (*inverse_DCT) (cinfo, compptr, (JCOEFPTR) buffer_ptr, + output_ptr, output_col); + buffer_ptr++; + output_col += compptr->codec_data_unit; + } + output_ptr += compptr->codec_data_unit; + } + } + + if (++(cinfo->output_iMCU_row) < cinfo->total_iMCU_rows) + return JPEG_ROW_COMPLETED; + return JPEG_SCAN_COMPLETED; +} + +#endif /* D_MULTISCAN_FILES_SUPPORTED */ + + +#ifdef BLOCK_SMOOTHING_SUPPORTED + +/* + * This code applies interblock smoothing as described by section K.8 + * of the JPEG standard: the first 5 AC coefficients are estimated from + * the DC values of a DCT block and its 8 neighboring blocks. + * We apply smoothing only for progressive JPEG decoding, and only if + * the coefficients it can estimate are not yet known to full precision. + */ + +/* Natural-order array positions of the first 5 zigzag-order coefficients */ +#define Q01_POS 1 +#define Q10_POS 8 +#define Q20_POS 16 +#define Q11_POS 9 +#define Q02_POS 2 + +/* + * Determine whether block smoothing is applicable and safe. + * We also latch the current states of the coef_bits[] entries for the + * AC coefficients; otherwise, if the input side of the decompressor + * advances into a new scan, we might think the coefficients are known + * more accurately than they really are. + */ + +LOCAL(boolean) +smoothing_ok (j_decompress_ptr cinfo) +{ + j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; + d_coef_ptr coef = (d_coef_ptr) lossyd->coef_private; + boolean smoothing_useful = FALSE; + int ci, coefi; + jpeg_component_info *compptr; + JQUANT_TBL * qtable; + int * coef_bits; + int * coef_bits_latch; + + if (! cinfo->process == JPROC_PROGRESSIVE || cinfo->coef_bits == NULL) + return FALSE; + + /* Allocate latch area if not already done */ + if (coef->coef_bits_latch == NULL) + coef->coef_bits_latch = (int *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + cinfo->num_components * + (SAVED_COEFS * SIZEOF(int))); + coef_bits_latch = coef->coef_bits_latch; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* All components' quantization values must already be latched. */ + if ((qtable = compptr->quant_table) == NULL) + return FALSE; + /* Verify DC & first 5 AC quantizers are nonzero to avoid zero-divide. */ + if (qtable->quantval[0] == 0 || + qtable->quantval[Q01_POS] == 0 || + qtable->quantval[Q10_POS] == 0 || + qtable->quantval[Q20_POS] == 0 || + qtable->quantval[Q11_POS] == 0 || + qtable->quantval[Q02_POS] == 0) + return FALSE; + /* DC values must be at least partly known for all components. */ + coef_bits = cinfo->coef_bits[ci]; + if (coef_bits[0] < 0) + return FALSE; + /* Block smoothing is helpful if some AC coefficients remain inaccurate. */ + for (coefi = 1; coefi <= 5; coefi++) { + coef_bits_latch[coefi] = coef_bits[coefi]; + if (coef_bits[coefi] != 0) + smoothing_useful = TRUE; + } + coef_bits_latch += SAVED_COEFS; + } + + return smoothing_useful; +} + + +/* + * Variant of decompress_data for use when doing block smoothing. + */ + +METHODDEF(int) +decompress_smooth_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf) +{ + j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; + d_coef_ptr coef = (d_coef_ptr) lossyd->coef_private; + JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; + JDIMENSION block_num, last_block_column; + int ci, block_row, block_rows, access_rows; + JBLOCKARRAY buffer; + JBLOCKROW buffer_ptr, prev_block_row, next_block_row; + JSAMPARRAY output_ptr; + JDIMENSION output_col; + jpeg_component_info *compptr; + inverse_DCT_method_ptr inverse_DCT; + boolean first_row, last_row; + JBLOCK workspace; + int *coef_bits; + JQUANT_TBL *quanttbl; + INT32 Q00,Q01,Q02,Q10,Q11,Q20, num; + int DC1,DC2,DC3,DC4,DC5,DC6,DC7,DC8,DC9; + int Al, pred; + + /* Force some input to be done if we are getting ahead of the input. */ + while (cinfo->input_scan_number <= cinfo->output_scan_number && + ! cinfo->inputctl->eoi_reached) { + if (cinfo->input_scan_number == cinfo->output_scan_number) { + /* If input is working on current scan, we ordinarily want it to + * have completed the current row. But if input scan is DC, + * we want it to keep one row ahead so that next block row's DC + * values are up to date. + */ + JDIMENSION delta = (cinfo->Ss == 0) ? 1 : 0; + if (cinfo->input_iMCU_row > cinfo->output_iMCU_row+delta) + break; + } + if ((*cinfo->inputctl->consume_input)(cinfo) == JPEG_SUSPENDED) + return JPEG_SUSPENDED; + } + + /* OK, output from the virtual arrays. */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Don't bother to IDCT an uninteresting component. */ + if (! compptr->component_needed) + continue; + /* Count non-dummy DCT block rows in this iMCU row. */ + if (cinfo->output_iMCU_row < last_iMCU_row) { + block_rows = compptr->v_samp_factor; + access_rows = block_rows * 2; /* this and next iMCU row */ + last_row = FALSE; + } else { + /* NB: can't use last_row_height here; it is input-side-dependent! */ + block_rows = (int) (compptr->height_in_data_units % compptr->v_samp_factor); + if (block_rows == 0) block_rows = compptr->v_samp_factor; + access_rows = block_rows; /* this iMCU row only */ + last_row = TRUE; + } + /* Align the virtual buffer for this component. */ + if (cinfo->output_iMCU_row > 0) { + access_rows += compptr->v_samp_factor; /* prior iMCU row too */ + buffer = (*cinfo->mem->access_virt_barray) + ((j_common_ptr) cinfo, coef->whole_image[ci], + (cinfo->output_iMCU_row - 1) * compptr->v_samp_factor, + (JDIMENSION) access_rows, FALSE); + buffer += compptr->v_samp_factor; /* point to current iMCU row */ + first_row = FALSE; + } else { + buffer = (*cinfo->mem->access_virt_barray) + ((j_common_ptr) cinfo, coef->whole_image[ci], + (JDIMENSION) 0, (JDIMENSION) access_rows, FALSE); + first_row = TRUE; + } + /* Fetch component-dependent info */ + coef_bits = coef->coef_bits_latch + (ci * SAVED_COEFS); + quanttbl = compptr->quant_table; + Q00 = quanttbl->quantval[0]; + Q01 = quanttbl->quantval[Q01_POS]; + Q10 = quanttbl->quantval[Q10_POS]; + Q20 = quanttbl->quantval[Q20_POS]; + Q11 = quanttbl->quantval[Q11_POS]; + Q02 = quanttbl->quantval[Q02_POS]; + inverse_DCT = lossyd->inverse_DCT[ci]; + output_ptr = output_buf[ci]; + /* Loop over all DCT blocks to be processed. */ + for (block_row = 0; block_row < block_rows; block_row++) { + buffer_ptr = buffer[block_row]; + if (first_row && block_row == 0) + prev_block_row = buffer_ptr; + else + prev_block_row = buffer[block_row-1]; + if (last_row && block_row == block_rows-1) + next_block_row = buffer_ptr; + else + next_block_row = buffer[block_row+1]; + /* We fetch the surrounding DC values using a sliding-register approach. + * Initialize all nine here so as to do the right thing on narrow pics. + */ + DC1 = DC2 = DC3 = (int) prev_block_row[0][0]; + DC4 = DC5 = DC6 = (int) buffer_ptr[0][0]; + DC7 = DC8 = DC9 = (int) next_block_row[0][0]; + output_col = 0; + last_block_column = compptr->width_in_data_units - 1; + for (block_num = 0; block_num <= last_block_column; block_num++) { + /* Fetch current DCT block into workspace so we can modify it. */ + jcopy_block_row(buffer_ptr, (JBLOCKROW) workspace, (JDIMENSION) 1); + /* Update DC values */ + if (block_num < last_block_column) { + DC3 = (int) prev_block_row[1][0]; + DC6 = (int) buffer_ptr[1][0]; + DC9 = (int) next_block_row[1][0]; + } + /* Compute coefficient estimates per K.8. + * An estimate is applied only if coefficient is still zero, + * and is not known to be fully accurate. + */ + /* AC01 */ + if ((Al=coef_bits[1]) != 0 && workspace[1] == 0) { + num = 36 * Q00 * (DC4 - DC6); + if (num >= 0) { + pred = (int) (((Q01<<7) + num) / (Q01<<8)); + if (Al > 0 && pred >= (1<<Al)) + pred = (1<<Al)-1; + } else { + pred = (int) (((Q01<<7) - num) / (Q01<<8)); + if (Al > 0 && pred >= (1<<Al)) + pred = (1<<Al)-1; + pred = -pred; + } + workspace[1] = (JCOEF) pred; + } + /* AC10 */ + if ((Al=coef_bits[2]) != 0 && workspace[8] == 0) { + num = 36 * Q00 * (DC2 - DC8); + if (num >= 0) { + pred = (int) (((Q10<<7) + num) / (Q10<<8)); + if (Al > 0 && pred >= (1<<Al)) + pred = (1<<Al)-1; + } else { + pred = (int) (((Q10<<7) - num) / (Q10<<8)); + if (Al > 0 && pred >= (1<<Al)) + pred = (1<<Al)-1; + pred = -pred; + } + workspace[8] = (JCOEF) pred; + } + /* AC20 */ + if ((Al=coef_bits[3]) != 0 && workspace[16] == 0) { + num = 9 * Q00 * (DC2 + DC8 - 2*DC5); + if (num >= 0) { + pred = (int) (((Q20<<7) + num) / (Q20<<8)); + if (Al > 0 && pred >= (1<<Al)) + pred = (1<<Al)-1; + } else { + pred = (int) (((Q20<<7) - num) / (Q20<<8)); + if (Al > 0 && pred >= (1<<Al)) + pred = (1<<Al)-1; + pred = -pred; + } + workspace[16] = (JCOEF) pred; + } + /* AC11 */ + if ((Al=coef_bits[4]) != 0 && workspace[9] == 0) { + num = 5 * Q00 * (DC1 - DC3 - DC7 + DC9); + if (num >= 0) { + pred = (int) (((Q11<<7) + num) / (Q11<<8)); + if (Al > 0 && pred >= (1<<Al)) + pred = (1<<Al)-1; + } else { + pred = (int) (((Q11<<7) - num) / (Q11<<8)); + if (Al > 0 && pred >= (1<<Al)) + pred = (1<<Al)-1; + pred = -pred; + } + workspace[9] = (JCOEF) pred; + } + /* AC02 */ + if ((Al=coef_bits[5]) != 0 && workspace[2] == 0) { + num = 9 * Q00 * (DC4 + DC6 - 2*DC5); + if (num >= 0) { + pred = (int) (((Q02<<7) + num) / (Q02<<8)); + if (Al > 0 && pred >= (1<<Al)) + pred = (1<<Al)-1; + } else { + pred = (int) (((Q02<<7) - num) / (Q02<<8)); + if (Al > 0 && pred >= (1<<Al)) + pred = (1<<Al)-1; + pred = -pred; + } + workspace[2] = (JCOEF) pred; + } + /* OK, do the IDCT */ + (*inverse_DCT) (cinfo, compptr, (JCOEFPTR) workspace, + output_ptr, output_col); + /* Advance for next column */ + DC1 = DC2; DC2 = DC3; + DC4 = DC5; DC5 = DC6; + DC7 = DC8; DC8 = DC9; + buffer_ptr++, prev_block_row++, next_block_row++; + output_col += compptr->codec_data_unit; + } + output_ptr += compptr->codec_data_unit; + } + } + + if (++(cinfo->output_iMCU_row) < cinfo->total_iMCU_rows) + return JPEG_ROW_COMPLETED; + return JPEG_SCAN_COMPLETED; +} + +#endif /* BLOCK_SMOOTHING_SUPPORTED */ + + +/* + * Initialize coefficient buffer controller. + */ + +GLOBAL(void) +jinit_d_coef_controller (j_decompress_ptr cinfo, boolean need_full_buffer) +{ + j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; + d_coef_ptr coef; + + coef = (d_coef_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(d_coef_controller)); + lossyd->coef_private = (void *) coef; + lossyd->coef_start_input_pass = start_input_pass; + lossyd->coef_start_output_pass = start_output_pass; +#ifdef BLOCK_SMOOTHING_SUPPORTED + coef->coef_bits_latch = NULL; +#endif + + /* Create the coefficient buffer. */ + if (need_full_buffer) { +#ifdef D_MULTISCAN_FILES_SUPPORTED + /* Allocate a full-image virtual array for each component, */ + /* padded to a multiple of samp_factor DCT blocks in each direction. */ + /* Note we ask for a pre-zeroed array. */ + int ci, access_rows; + jpeg_component_info *compptr; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + access_rows = compptr->v_samp_factor; +#ifdef BLOCK_SMOOTHING_SUPPORTED + /* If block smoothing could be used, need a bigger window */ + if (cinfo->process == JPROC_PROGRESSIVE) + access_rows *= 3; +#endif + coef->whole_image[ci] = (*cinfo->mem->request_virt_barray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, TRUE, + (JDIMENSION) jround_up((long) compptr->width_in_data_units, + (long) compptr->h_samp_factor), + (JDIMENSION) jround_up((long) compptr->height_in_data_units, + (long) compptr->v_samp_factor), + (JDIMENSION) access_rows); + } + lossyd->pub.consume_data = consume_data; + lossyd->pub.decompress_data = decompress_data; + lossyd->coef_arrays = coef->whole_image; /* link to virtual arrays */ +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else { + /* We only need a single-MCU buffer. */ + JBLOCKROW buffer; + int i; + + buffer = (JBLOCKROW) + (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE, + D_MAX_DATA_UNITS_IN_MCU * SIZEOF(JBLOCK)); + for (i = 0; i < D_MAX_DATA_UNITS_IN_MCU; i++) { + coef->MCU_buffer[i] = buffer + i; + } + lossyd->pub.consume_data = dummy_consume_data; + lossyd->pub.decompress_data = decompress_onepass; + lossyd->coef_arrays = NULL; /* flag for no virtual arrays */ + } +} diff --git a/Utilities/ITK/Utilities/itkjpeg/jdcolor.c b/Utilities/ITK/Utilities/itkjpeg/jdcolor.c new file mode 100644 index 0000000000000000000000000000000000000000..7b0aa3d7bda56d78eddb5fb70f6c8021e4e85217 --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jdcolor.c @@ -0,0 +1,414 @@ +/* + * jdcolor.c + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains output colorspace conversion routines. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Private subobject */ + +typedef struct { + struct jpeg_color_deconverter pub; /* public fields */ + + /* Private state for YCC->RGB conversion */ + int * Cr_r_tab; /* => table for Cr to R conversion */ + int * Cb_b_tab; /* => table for Cb to B conversion */ + INT32 * Cr_g_tab; /* => table for Cr to G conversion */ + INT32 * Cb_g_tab; /* => table for Cb to G conversion */ +} my_color_deconverter; + +typedef my_color_deconverter * my_cconvert_ptr; + + +/**************** YCbCr -> RGB conversion: most common case **************/ + +/* + * YCbCr is defined per CCIR 601-1, except that Cb and Cr are + * normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5. + * The conversion equations to be implemented are therefore + * R = Y + 1.40200 * Cr + * G = Y - 0.34414 * Cb - 0.71414 * Cr + * B = Y + 1.77200 * Cb + * where Cb and Cr represent the incoming values less CENTERJSAMPLE. + * (These numbers are derived from TIFF 6.0 section 21, dated 3-June-92.) + * + * To avoid floating-point arithmetic, we represent the fractional constants + * as integers scaled up by 2^16 (about 4 digits precision); we have to divide + * the products by 2^16, with appropriate rounding, to get the correct answer. + * Notice that Y, being an integral input, does not contribute any fraction + * so it need not participate in the rounding. + * + * For even more speed, we avoid doing any multiplications in the inner loop + * by precalculating the constants times Cb and Cr for all possible values. + * For 8-bit JSAMPLEs this is very reasonable (only 256 entries per table); + * for 12-bit samples it is still acceptable. It's not very reasonable for + * 16-bit samples, but if you want lossless storage you shouldn't be changing + * colorspace anyway. + * The Cr=>R and Cb=>B values can be rounded to integers in advance; the + * values for the G calculation are left scaled up, since we must add them + * together before rounding. + */ + +#define SCALEBITS 16 /* speediest right-shift on some machines */ +#define ONE_HALF ((INT32) 1 << (SCALEBITS-1)) +#define FIX(x) ((INT32) ((x) * (1L<<SCALEBITS) + 0.5)) + + +/* + * Initialize tables for YCC->RGB colorspace conversion. + */ + +LOCAL(void) +build_ycc_rgb_table (j_decompress_ptr cinfo) +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + int i; + INT32 x; +#if BITS_IN_JSAMPLE == 16 + /* no need for temporaries */ +#else + SHIFT_TEMPS +#endif + + cconvert->Cr_r_tab = (int *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (MAXJSAMPLE+1) * SIZEOF(int)); + cconvert->Cb_b_tab = (int *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (MAXJSAMPLE+1) * SIZEOF(int)); + cconvert->Cr_g_tab = (INT32 *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (MAXJSAMPLE+1) * SIZEOF(INT32)); + cconvert->Cb_g_tab = (INT32 *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (MAXJSAMPLE+1) * SIZEOF(INT32)); + + for (i = 0, x = -CENTERJSAMPLE; i <= MAXJSAMPLE; i++, x++) { + /* i is the actual input pixel value, in the range 0..MAXJSAMPLE */ + /* The Cb or Cr value we are thinking of is x = i - CENTERJSAMPLE */ + +#if BITS_IN_JSAMPLE == 16 + /* Bug fix 2001-11-06 by Eichelberg: The integer routines below + produce an overflow when used with MAXJSAMPLE == 65535. + Use floating point calculation instead. */ + + /* Cr=>R value is nearest int to 1.40200 * x */ + cconvert->Cr_r_tab[i] = (int)(1.40200 * (double)x + 0.5); + /* Cb=>B value is nearest int to 1.77200 * x */ + cconvert->Cb_b_tab[i] = (int)(1.77200 * (double)x + 0.5); +#else + /* Cr=>R value is nearest int to 1.40200 * x */ + cconvert->Cr_r_tab[i] = (int) + RIGHT_SHIFT(FIX(1.40200) * x + ONE_HALF, SCALEBITS); + /* Cb=>B value is nearest int to 1.77200 * x */ + cconvert->Cb_b_tab[i] = (int) + RIGHT_SHIFT(FIX(1.77200) * x + ONE_HALF, SCALEBITS); +#endif + + /* Cr=>G value is scaled-up -0.71414 * x */ + cconvert->Cr_g_tab[i] = (- FIX(0.71414)) * x; + /* Cb=>G value is scaled-up -0.34414 * x */ + /* We also add in ONE_HALF so that need not do it in inner loop */ + cconvert->Cb_g_tab[i] = (- FIX(0.34414)) * x + ONE_HALF; + } +} + + +/* + * Convert some rows of samples to the output colorspace. + * + * Note that we change from noninterleaved, one-plane-per-component format + * to interleaved-pixel format. The output buffer is therefore three times + * as wide as the input buffer. + * A starting row offset is provided only for the input buffer. The caller + * can easily adjust the passed output_buf value to accommodate any row + * offset required on that side. + */ + +METHODDEF(void) +ycc_rgb_convert (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows) +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + register int y, cb, cr; + register JSAMPROW outptr; + register JSAMPROW inptr0, inptr1, inptr2; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->output_width; + /* copy these pointers into registers if possible */ + register JSAMPLE * range_limit = cinfo->sample_range_limit; + register int * Crrtab = cconvert->Cr_r_tab; + register int * Cbbtab = cconvert->Cb_b_tab; + register INT32 * Crgtab = cconvert->Cr_g_tab; + register INT32 * Cbgtab = cconvert->Cb_g_tab; + SHIFT_TEMPS + + while (--num_rows >= 0) { + inptr0 = input_buf[0][input_row]; + inptr1 = input_buf[1][input_row]; + inptr2 = input_buf[2][input_row]; + input_row++; + outptr = *output_buf++; + for (col = 0; col < num_cols; col++) { + y = GETJSAMPLE(inptr0[col]); + cb = GETJSAMPLE(inptr1[col]); + cr = GETJSAMPLE(inptr2[col]); + /* Range-limiting is essential due to noise introduced by DCT losses. */ + outptr[RGB_RED] = range_limit[y + Crrtab[cr]]; + outptr[RGB_GREEN] = range_limit[y + + ((int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], + SCALEBITS))]; + outptr[RGB_BLUE] = range_limit[y + Cbbtab[cb]]; + outptr += RGB_PIXELSIZE; + } + } +} + + +/**************** Cases other than YCbCr -> RGB **************/ + + +/* + * Color conversion for no colorspace change: just copy the data, + * converting from separate-planes to interleaved representation. + */ + +METHODDEF(void) +null_convert (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows) +{ + register JSAMPROW inptr, outptr; + register JDIMENSION count; + register int num_components = cinfo->num_components; + JDIMENSION num_cols = cinfo->output_width; + int ci; + + while (--num_rows >= 0) { + for (ci = 0; ci < num_components; ci++) { + inptr = input_buf[ci][input_row]; + outptr = output_buf[0] + ci; + for (count = num_cols; count > 0; count--) { + *outptr = *inptr++; /* needn't bother with GETJSAMPLE() here */ + outptr += num_components; + } + } + input_row++; + output_buf++; + } +} + + +/* + * Color conversion for grayscale: just copy the data. + * This also works for YCbCr -> grayscale conversion, in which + * we just copy the Y (luminance) component and ignore chrominance. + */ + +METHODDEF(void) +grayscale_convert (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows) +{ + jcopy_sample_rows(input_buf[0], (int) input_row, output_buf, 0, + num_rows, cinfo->output_width); +} + + +/* + * Convert grayscale to RGB: just duplicate the graylevel three times. + * This is provided to support applications that don't want to cope + * with grayscale as a separate case. + */ + +METHODDEF(void) +gray_rgb_convert (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows) +{ + register JSAMPROW inptr, outptr; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->output_width; + + while (--num_rows >= 0) { + inptr = input_buf[0][input_row++]; + outptr = *output_buf++; + for (col = 0; col < num_cols; col++) { + /* We can dispense with GETJSAMPLE() here */ + outptr[RGB_RED] = outptr[RGB_GREEN] = outptr[RGB_BLUE] = inptr[col]; + outptr += RGB_PIXELSIZE; + } + } +} + + +/* + * Adobe-style YCCK->CMYK conversion. + * We convert YCbCr to R=1-C, G=1-M, and B=1-Y using the same + * conversion as above, while passing K (black) unchanged. + * We assume build_ycc_rgb_table has been called. + */ + +METHODDEF(void) +ycck_cmyk_convert (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows) +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + register int y, cb, cr; + register JSAMPROW outptr; + register JSAMPROW inptr0, inptr1, inptr2, inptr3; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->output_width; + /* copy these pointers into registers if possible */ + register JSAMPLE * range_limit = cinfo->sample_range_limit; + register int * Crrtab = cconvert->Cr_r_tab; + register int * Cbbtab = cconvert->Cb_b_tab; + register INT32 * Crgtab = cconvert->Cr_g_tab; + register INT32 * Cbgtab = cconvert->Cb_g_tab; + SHIFT_TEMPS + + while (--num_rows >= 0) { + inptr0 = input_buf[0][input_row]; + inptr1 = input_buf[1][input_row]; + inptr2 = input_buf[2][input_row]; + inptr3 = input_buf[3][input_row]; + input_row++; + outptr = *output_buf++; + for (col = 0; col < num_cols; col++) { + y = GETJSAMPLE(inptr0[col]); + cb = GETJSAMPLE(inptr1[col]); + cr = GETJSAMPLE(inptr2[col]); + /* Range-limiting is essential due to noise introduced by DCT losses. */ + outptr[0] = range_limit[MAXJSAMPLE - (y + Crrtab[cr])]; /* red */ + outptr[1] = range_limit[MAXJSAMPLE - (y + /* green */ + ((int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], + SCALEBITS)))]; + outptr[2] = range_limit[MAXJSAMPLE - (y + Cbbtab[cb])]; /* blue */ + /* K passes through unchanged */ + outptr[3] = inptr3[col]; /* don't need GETJSAMPLE here */ + outptr += 4; + } + } +} + + +/* + * Empty method for start_pass. + */ + +METHODDEF(void) +start_pass_dcolor (j_decompress_ptr cinfo) +{ + (void)cinfo; + /* no work needed */ +} + + +/* + * Module initialization routine for output colorspace conversion. + */ + +GLOBAL(void) +jinit_color_deconverter (j_decompress_ptr cinfo) +{ + my_cconvert_ptr cconvert; + int ci; + + cconvert = (my_cconvert_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_color_deconverter)); + cinfo->cconvert = (struct jpeg_color_deconverter *) cconvert; + cconvert->pub.start_pass = start_pass_dcolor; + + /* Make sure num_components agrees with jpeg_color_space */ + switch (cinfo->jpeg_color_space) { + case JCS_GRAYSCALE: + if (cinfo->num_components != 1) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + break; + + case JCS_RGB: + case JCS_YCbCr: + if (cinfo->num_components != 3) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + break; + + case JCS_CMYK: + case JCS_YCCK: + if (cinfo->num_components != 4) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + break; + + default: /* JCS_UNKNOWN can be anything */ + if (cinfo->num_components < 1) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + break; + } + + /* Set out_color_components and conversion method based on requested space. + * Also clear the component_needed flags for any unused components, + * so that earlier pipeline stages can avoid useless computation. + */ + + switch (cinfo->out_color_space) { + case JCS_GRAYSCALE: + cinfo->out_color_components = 1; + if (cinfo->jpeg_color_space == JCS_GRAYSCALE || + cinfo->jpeg_color_space == JCS_YCbCr) { + cconvert->pub.color_convert = grayscale_convert; + /* For color->grayscale conversion, only the Y (0) component is needed */ + for (ci = 1; ci < cinfo->num_components; ci++) + cinfo->comp_info[ci].component_needed = FALSE; + } else + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + break; + + case JCS_RGB: + cinfo->out_color_components = RGB_PIXELSIZE; + if (cinfo->jpeg_color_space == JCS_YCbCr) { + cconvert->pub.color_convert = ycc_rgb_convert; + build_ycc_rgb_table(cinfo); + } else if (cinfo->jpeg_color_space == JCS_GRAYSCALE) { + cconvert->pub.color_convert = gray_rgb_convert; + } else if (cinfo->jpeg_color_space == JCS_RGB && RGB_PIXELSIZE == 3) { + cconvert->pub.color_convert = null_convert; + } else + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + break; + + case JCS_CMYK: + cinfo->out_color_components = 4; + if (cinfo->jpeg_color_space == JCS_YCCK) { + cconvert->pub.color_convert = ycck_cmyk_convert; + build_ycc_rgb_table(cinfo); + } else if (cinfo->jpeg_color_space == JCS_CMYK) { + cconvert->pub.color_convert = null_convert; + } else + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + break; + + default: + /* Permit null conversion to same output space */ + if (cinfo->out_color_space == cinfo->jpeg_color_space) { + cinfo->out_color_components = cinfo->num_components; + cconvert->pub.color_convert = null_convert; + } else /* unsupported non-null conversion */ + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + break; + } + + if (cinfo->quantize_colors) + cinfo->output_components = 1; /* single colormapped output component */ + else + cinfo->output_components = cinfo->out_color_components; +} diff --git a/Utilities/ITK/Utilities/itkjpeg/jdct.h b/Utilities/ITK/Utilities/itkjpeg/jdct.h new file mode 100644 index 0000000000000000000000000000000000000000..ffdd5e50bed24bdb5bd19eabc229e829e8f0e1de --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jdct.h @@ -0,0 +1,176 @@ +/* + * jdct.h + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This include file contains common declarations for the forward and + * inverse DCT modules. These declarations are private to the DCT managers + * (jcdctmgr.c, jddctmgr.c) and the individual DCT algorithms. + * The individual DCT algorithms are kept in separate files to ease + * machine-dependent tuning (e.g., assembly coding). + */ + + +/* + * A forward DCT routine is given a pointer to a work area of type DCTELEM[]; + * the DCT is to be performed in-place in that buffer. Type DCTELEM is int + * for 8-bit samples, INT32 for 12-bit samples. (NOTE: Floating-point DCT + * implementations use an array of type FAST_FLOAT, instead.) + * The DCT inputs are expected to be signed (range +-CENTERJSAMPLE). + * The DCT outputs are returned scaled up by a factor of 8; they therefore + * have a range of +-8K for 8-bit data, +-128K for 12-bit data. This + * convention improves accuracy in integer implementations and saves some + * work in floating-point ones. + * Quantization of the output coefficients is done by jcdctmgr.c. + */ + +#if BITS_IN_JSAMPLE == 8 +typedef int DCTELEM; /* 16 or 32 bits is fine */ +#else +typedef INT32 DCTELEM; /* must have 32 bits */ +#endif + +typedef JMETHOD(void, forward_DCT_method_ptr, (DCTELEM * data)); +typedef JMETHOD(void, float_DCT_method_ptr, (FAST_FLOAT * data)); + + +/* + * An inverse DCT routine is given a pointer to the input JBLOCK and a pointer + * to an output sample array. The routine must dequantize the input data as + * well as perform the IDCT; for dequantization, it uses the multiplier table + * pointed to by compptr->dct_table. The output data is to be placed into the + * sample array starting at a specified column. (Any row offset needed will + * be applied to the array pointer before it is passed to the IDCT code.) + * Note that the number of samples emitted by the IDCT routine is + * DCT_scaled_size * DCT_scaled_size. + */ + +/* typedef inverse_DCT_method_ptr is declared in jpegint.h */ + +/* + * Each IDCT routine has its own ideas about the best dct_table element type. + */ + +typedef MULTIPLIER ISLOW_MULT_TYPE; /* short or int, whichever is faster */ +#if BITS_IN_JSAMPLE == 8 +typedef MULTIPLIER IFAST_MULT_TYPE; /* 16 bits is OK, use short if faster */ +#define IFAST_SCALE_BITS 2 /* fractional bits in scale factors */ +#else +typedef INT32 IFAST_MULT_TYPE; /* need 32 bits for scaled quantizers */ +#define IFAST_SCALE_BITS 13 /* fractional bits in scale factors */ +#endif +typedef FAST_FLOAT FLOAT_MULT_TYPE; /* preferred floating type */ + + +/* + * Each IDCT routine is responsible for range-limiting its results and + * converting them to unsigned form (0..MAXJSAMPLE). The raw outputs could + * be quite far out of range if the input data is corrupt, so a bulletproof + * range-limiting step is required. We use a mask-and-table-lookup method + * to do the combined operations quickly. See the comments with + * prepare_range_limit_table (in jdmaster.c) for more info. + */ + +#define IDCT_range_limit(cinfo) ((cinfo)->sample_range_limit + CENTERJSAMPLE) + +#define RANGE_MASK (MAXJSAMPLE * 4 + 3) /* 2 bits wider than legal samples */ + + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_fdct_islow jFDislow +#define jpeg_fdct_ifast jFDifast +#define jpeg_fdct_float jFDfloat +#define jpeg_idct_islow jRDislow +#define jpeg_idct_ifast jRDifast +#define jpeg_idct_float jRDfloat +#define jpeg_idct_4x4 jRD4x4 +#define jpeg_idct_2x2 jRD2x2 +#define jpeg_idct_1x1 jRD1x1 +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + +/* Extern declarations for the forward and inverse DCT routines. */ + +EXTERN(void) jpeg_fdct_islow JPP((DCTELEM * data)); +EXTERN(void) jpeg_fdct_ifast JPP((DCTELEM * data)); +EXTERN(void) jpeg_fdct_float JPP((FAST_FLOAT * data)); + +EXTERN(void) jpeg_idct_islow + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_ifast + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_float + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_4x4 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_2x2 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_1x1 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); + + +/* + * Macros for handling fixed-point arithmetic; these are used by many + * but not all of the DCT/IDCT modules. + * + * All values are expected to be of type INT32. + * Fractional constants are scaled left by CONST_BITS bits. + * CONST_BITS is defined within each module using these macros, + * and may differ from one module to the next. + */ + +#define ONE ((INT32) 1) +#define CONST_SCALE (ONE << CONST_BITS) + +/* Convert a positive real constant to an integer scaled by CONST_SCALE. + * Caution: some C compilers fail to reduce "FIX(constant)" at compile time, + * thus causing a lot of useless floating-point operations at run time. + */ + +#define FIX(x) ((INT32) ((x) * CONST_SCALE + 0.5)) + +/* Descale and correctly round an INT32 value that's scaled by N bits. + * We assume RIGHT_SHIFT rounds towards minus infinity, so adding + * the fudge factor is correct for either sign of X. + */ + +#define DESCALE(x,n) RIGHT_SHIFT((x) + (ONE << ((n)-1)), n) + +/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result. + * This macro is used only when the two inputs will actually be no more than + * 16 bits wide, so that a 16x16->32 bit multiply can be used instead of a + * full 32x32 multiply. This provides a useful speedup on many machines. + * Unfortunately there is no way to specify a 16x16->32 multiply portably + * in C, but some C compilers will do the right thing if you provide the + * correct combination of casts. + */ + +#ifdef SHORTxSHORT_32 /* may work if 'int' is 32 bits */ +#define MULTIPLY16C16(var,const) (((INT16) (var)) * ((INT16) (const))) +#endif +#ifdef SHORTxLCONST_32 /* known to work with Microsoft C 6.0 */ +#define MULTIPLY16C16(var,const) (((INT16) (var)) * ((INT32) (const))) +#endif + +#ifndef MULTIPLY16C16 /* default definition */ +#define MULTIPLY16C16(var,const) ((var) * (const)) +#endif + +/* Same except both inputs are variables. */ + +#ifdef SHORTxSHORT_32 /* may work if 'int' is 32 bits */ +#define MULTIPLY16V16(var1,var2) (((INT16) (var1)) * ((INT16) (var2))) +#endif + +#ifndef MULTIPLY16V16 /* default definition */ +#define MULTIPLY16V16(var1,var2) ((var1) * (var2)) +#endif diff --git a/Utilities/ITK/Utilities/itkjpeg/jddctmgr.c b/Utilities/ITK/Utilities/itkjpeg/jddctmgr.c new file mode 100644 index 0000000000000000000000000000000000000000..6f6c4442bd9f19fd6f9516a99dd929c573c424d8 --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jddctmgr.c @@ -0,0 +1,270 @@ +/* + * jddctmgr.c + * + * Copyright (C) 1994-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the inverse-DCT management logic. + * This code selects a particular IDCT implementation to be used, + * and it performs related housekeeping chores. No code in this file + * is executed per IDCT step, only during output pass setup. + * + * Note that the IDCT routines are responsible for performing coefficient + * dequantization as well as the IDCT proper. This module sets up the + * dequantization multiplier table needed by the IDCT routine. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jlossy.h" /* Private declarations for lossy subsystem */ +#include "jdct.h" /* Private declarations for DCT subsystem */ + + +/* + * The decompressor input side (jdinput.c) saves away the appropriate + * quantization table for each component at the start of the first scan + * involving that component. (This is necessary in order to correctly + * decode files that reuse Q-table slots.) + * When we are ready to make an output pass, the saved Q-table is converted + * to a multiplier table that will actually be used by the IDCT routine. + * The multiplier table contents are IDCT-method-dependent. To support + * application changes in IDCT method between scans, we can remake the + * multiplier tables if necessary. + * In buffered-image mode, the first output pass may occur before any data + * has been seen for some components, and thus before their Q-tables have + * been saved away. To handle this case, multiplier tables are preset + * to zeroes; the result of the IDCT will be a neutral gray level. + */ + + +/* Private subobject for this module */ + +typedef struct { + /* This array contains the IDCT method code that each multiplier table + * is currently set up for, or -1 if it's not yet set up. + * The actual multiplier tables are pointed to by dct_table in the + * per-component comp_info structures. + */ + int cur_method[MAX_COMPONENTS]; +} idct_controller; + +typedef idct_controller * idct_ptr; + + +/* Allocated multiplier tables: big enough for any supported variant */ + +typedef union { + ISLOW_MULT_TYPE islow_array[DCTSIZE2]; +#ifdef DCT_IFAST_SUPPORTED + IFAST_MULT_TYPE ifast_array[DCTSIZE2]; +#endif +#ifdef DCT_FLOAT_SUPPORTED + FLOAT_MULT_TYPE float_array[DCTSIZE2]; +#endif +} multiplier_table; + + +/* The current scaled-IDCT routines require ISLOW-style multiplier tables, + * so be sure to compile that code if either ISLOW or SCALING is requested. + */ +#ifdef DCT_ISLOW_SUPPORTED +#define PROVIDE_ISLOW_TABLES +#else +#ifdef IDCT_SCALING_SUPPORTED +#define PROVIDE_ISLOW_TABLES +#endif +#endif + + +/* + * Prepare for an output pass. + * Here we select the proper IDCT routine for each component and build + * a matching multiplier table. + */ + +METHODDEF(void) +start_pass (j_decompress_ptr cinfo) +{ + j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; + idct_ptr idct = (idct_ptr) lossyd->idct_private; + int ci, i; + jpeg_component_info *compptr; + int method = 0; + inverse_DCT_method_ptr method_ptr = NULL; + JQUANT_TBL * qtbl; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Select the proper IDCT routine for this component's scaling */ + switch (compptr->codec_data_unit) { +#ifdef IDCT_SCALING_SUPPORTED + case 1: + method_ptr = jpeg_idct_1x1; + method = JDCT_ISLOW; /* jidctred uses islow-style table */ + break; + case 2: + method_ptr = jpeg_idct_2x2; + method = JDCT_ISLOW; /* jidctred uses islow-style table */ + break; + case 4: + method_ptr = jpeg_idct_4x4; + method = JDCT_ISLOW; /* jidctred uses islow-style table */ + break; +#endif + case DCTSIZE: + switch (cinfo->dct_method) { +#ifdef DCT_ISLOW_SUPPORTED + case JDCT_ISLOW: + method_ptr = jpeg_idct_islow; + method = JDCT_ISLOW; + break; +#endif +#ifdef DCT_IFAST_SUPPORTED + case JDCT_IFAST: + method_ptr = jpeg_idct_ifast; + method = JDCT_IFAST; + break; +#endif +#ifdef DCT_FLOAT_SUPPORTED + case JDCT_FLOAT: + method_ptr = jpeg_idct_float; + method = JDCT_FLOAT; + break; +#endif + default: + ERREXIT(cinfo, JERR_NOT_COMPILED); + break; + } + break; + default: + ERREXIT1(cinfo, JERR_BAD_DCTSIZE, compptr->codec_data_unit); + break; + } + lossyd->inverse_DCT[ci] = method_ptr; + /* Create multiplier table from quant table. + * However, we can skip this if the component is uninteresting + * or if we already built the table. Also, if no quant table + * has yet been saved for the component, we leave the + * multiplier table all-zero; we'll be reading zeroes from the + * coefficient controller's buffer anyway. + */ + if (! compptr->component_needed || idct->cur_method[ci] == method) + continue; + qtbl = compptr->quant_table; + if (qtbl == NULL) /* happens if no data yet for component */ + continue; + idct->cur_method[ci] = method; + switch (method) { +#ifdef PROVIDE_ISLOW_TABLES + case JDCT_ISLOW: + { + /* For LL&M IDCT method, multipliers are equal to raw quantization + * coefficients, but are stored as ints to ensure access efficiency. + */ + ISLOW_MULT_TYPE * ismtbl = (ISLOW_MULT_TYPE *) compptr->dct_table; + for (i = 0; i < DCTSIZE2; i++) { + ismtbl[i] = (ISLOW_MULT_TYPE) qtbl->quantval[i]; + } + } + break; +#endif +#ifdef DCT_IFAST_SUPPORTED + case JDCT_IFAST: + { + /* For AA&N IDCT method, multipliers are equal to quantization + * coefficients scaled by scalefactor[row]*scalefactor[col], where + * scalefactor[0] = 1 + * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7 + * For integer operation, the multiplier table is to be scaled by + * IFAST_SCALE_BITS. + */ + IFAST_MULT_TYPE * ifmtbl = (IFAST_MULT_TYPE *) compptr->dct_table; +#define CONST_BITS 14 + static const INT16 aanscales[DCTSIZE2] = { + /* precomputed values scaled up by 14 bits */ + 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, + 22725, 31521, 29692, 26722, 22725, 17855, 12299, 6270, + 21407, 29692, 27969, 25172, 21407, 16819, 11585, 5906, + 19266, 26722, 25172, 22654, 19266, 15137, 10426, 5315, + 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, + 12873, 17855, 16819, 15137, 12873, 10114, 6967, 3552, + 8867, 12299, 11585, 10426, 8867, 6967, 4799, 2446, + 4520, 6270, 5906, 5315, 4520, 3552, 2446, 1247 + }; + SHIFT_TEMPS + + for (i = 0; i < DCTSIZE2; i++) { + ifmtbl[i] = (IFAST_MULT_TYPE) + DESCALE(MULTIPLY16V16((INT32) qtbl->quantval[i], + (INT32) aanscales[i]), + CONST_BITS-IFAST_SCALE_BITS); + } + } + break; +#endif +#ifdef DCT_FLOAT_SUPPORTED + case JDCT_FLOAT: + { + /* For float AA&N IDCT method, multipliers are equal to quantization + * coefficients scaled by scalefactor[row]*scalefactor[col], where + * scalefactor[0] = 1 + * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7 + */ + FLOAT_MULT_TYPE * fmtbl = (FLOAT_MULT_TYPE *) compptr->dct_table; + int row, col; + static const double aanscalefactor[DCTSIZE] = { + 1.0, 1.387039845, 1.306562965, 1.175875602, + 1.0, 0.785694958, 0.541196100, 0.275899379 + }; + + i = 0; + for (row = 0; row < DCTSIZE; row++) { + for (col = 0; col < DCTSIZE; col++) { + fmtbl[i] = (FLOAT_MULT_TYPE) + ((double) qtbl->quantval[i] * + aanscalefactor[row] * aanscalefactor[col]); + i++; + } + } + } + break; +#endif + default: + ERREXIT(cinfo, JERR_NOT_COMPILED); + break; + } + } +} + + +/* + * Initialize IDCT manager. + */ + +GLOBAL(void) +jinit_inverse_dct (j_decompress_ptr cinfo) +{ + j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; + idct_ptr idct; + int ci; + jpeg_component_info *compptr; + + idct = (idct_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(idct_controller)); + lossyd->idct_private = (void *) idct; + lossyd->idct_start_pass = start_pass; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Allocate and pre-zero a multiplier table for each component */ + compptr->dct_table = + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(multiplier_table)); + MEMZERO(compptr->dct_table, SIZEOF(multiplier_table)); + /* Mark multiplier table not yet set up for any method */ + idct->cur_method[ci] = -1; + } +} diff --git a/Utilities/ITK/Utilities/itkjpeg/jddiffct.c b/Utilities/ITK/Utilities/itkjpeg/jddiffct.c new file mode 100644 index 0000000000000000000000000000000000000000..6dc61e44569788272aeed1e7f109171656c1c375 --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jddiffct.c @@ -0,0 +1,400 @@ +/* + * jddiffct.c + * + * Copyright (C) 1994-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the [un]difference buffer controller for decompression. + * This controller is the top level of the lossless JPEG decompressor proper. + * The difference buffer lies between the entropy decoding and + * prediction/undifferencing steps. The undifference buffer lies between the + * prediction/undifferencing and scaling steps. + * + * In buffered-image mode, this controller is the interface between + * input-oriented processing and output-oriented processing. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jlossls.h" + + +#ifdef D_LOSSLESS_SUPPORTED + +/* Private buffer controller object */ + +typedef struct { + /* These variables keep track of the current location of the input side. */ + /* cinfo->input_iMCU_row is also used for this. */ + JDIMENSION MCU_ctr; /* counts MCUs processed in current row */ + unsigned int restart_rows_to_go; /* MCU-rows left in this restart interval */ + unsigned int MCU_vert_offset; /* counts MCU rows within iMCU row */ + unsigned int MCU_rows_per_iMCU_row; /* number of such rows needed */ + + /* The output side's location is represented by cinfo->output_iMCU_row. */ + + JDIFFARRAY diff_buf[MAX_COMPONENTS]; /* iMCU row of differences */ + JDIFFARRAY undiff_buf[MAX_COMPONENTS]; /* iMCU row of undiff'd samples */ + +#ifdef D_MULTISCAN_FILES_SUPPORTED + /* In multi-pass modes, we need a virtual sample array for each component. */ + jvirt_sarray_ptr whole_image[MAX_COMPONENTS]; +#endif +} d_diff_controller; + +typedef d_diff_controller * d_diff_ptr; + +/* Forward declarations */ +METHODDEF(int) decompress_data + JPP((j_decompress_ptr cinfo, JSAMPIMAGE output_buf)); +#ifdef D_MULTISCAN_FILES_SUPPORTED +METHODDEF(int) output_data + JPP((j_decompress_ptr cinfo, JSAMPIMAGE output_buf)); +#endif + + +LOCAL(void) +start_iMCU_row (j_decompress_ptr cinfo) +/* Reset within-iMCU-row counters for a new row (input side) */ +{ + j_lossless_d_ptr losslsd = (j_lossless_d_ptr) cinfo->codec; + d_diff_ptr diff = (d_diff_ptr) losslsd->diff_private; + + /* In an interleaved scan, an MCU row is the same as an iMCU row. + * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows. + * But at the bottom of the image, process only what's left. + */ + if (cinfo->comps_in_scan > 1) { + diff->MCU_rows_per_iMCU_row = 1; + } else { + if (cinfo->input_iMCU_row < (cinfo->total_iMCU_rows-1)) + diff->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor; + else + diff->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height; + } + + diff->MCU_ctr = 0; + diff->MCU_vert_offset = 0; +} + + +/* + * Initialize for an input processing pass. + */ + +METHODDEF(void) +start_input_pass (j_decompress_ptr cinfo) +{ + j_lossless_d_ptr losslsd = (j_lossless_d_ptr) cinfo->codec; + d_diff_ptr diff = (d_diff_ptr) losslsd->diff_private; + + /* Check that the restart interval is an integer multiple of the number + * of MCU in an MCU-row. + */ + if (cinfo->restart_interval % cinfo->MCUs_per_row != 0) + ERREXIT2(cinfo, JERR_BAD_RESTART, + cinfo->restart_interval, cinfo->MCUs_per_row); + + /* Initialize restart counter */ + diff->restart_rows_to_go = cinfo->restart_interval / cinfo->MCUs_per_row; + + cinfo->input_iMCU_row = 0; + start_iMCU_row(cinfo); +} + + +/* + * Check for a restart marker & resynchronize decoder, undifferencer. + * Returns FALSE if must suspend. + */ + +METHODDEF(boolean) +process_restart (j_decompress_ptr cinfo) +{ + j_lossless_d_ptr losslsd = (j_lossless_d_ptr) cinfo->codec; + d_diff_ptr diff = (d_diff_ptr) losslsd->diff_private; + + if (! (*losslsd->entropy_process_restart) (cinfo)) + return FALSE; + + (*losslsd->predict_process_restart) (cinfo); + + /* Reset restart counter */ + diff->restart_rows_to_go = cinfo->restart_interval / cinfo->MCUs_per_row; + + return TRUE; +} + + +/* + * Initialize for an output processing pass. + */ + +METHODDEF(void) +start_output_pass (j_decompress_ptr cinfo) +{ + cinfo->output_iMCU_row = 0; +} + + +/* + * Decompress and return some data in the supplied buffer. + * Always attempts to emit one fully interleaved MCU row ("iMCU" row). + * Input and output must run in lockstep since we have only a one-MCU buffer. + * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED. + * + * NB: output_buf contains a plane for each component in image, + * which we index according to the component's SOF position. + */ + +METHODDEF(int) +decompress_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf) +{ + j_lossless_d_ptr losslsd = (j_lossless_d_ptr) cinfo->codec; + d_diff_ptr diff = (d_diff_ptr) losslsd->diff_private; + JDIMENSION MCU_col_num; /* index of current MCU within row */ + JDIMENSION MCU_count; /* number of MCUs decoded */ + JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; + int comp, ci, row, prev_row; + unsigned int yoffset; + jpeg_component_info *compptr; + + /* Loop to process as much as one whole iMCU row */ + for (yoffset = diff->MCU_vert_offset; yoffset < diff->MCU_rows_per_iMCU_row; + yoffset++) { + + /* Process restart marker if needed; may have to suspend */ + if (cinfo->restart_interval) { + if (diff->restart_rows_to_go == 0) + if (! process_restart(cinfo)) + return JPEG_SUSPENDED; + } + + MCU_col_num = diff->MCU_ctr; + /* Try to fetch an MCU-row (or remaining portion of suspended MCU-row). */ + MCU_count = + (*losslsd->entropy_decode_mcus) (cinfo, + diff->diff_buf, yoffset, MCU_col_num, + cinfo->MCUs_per_row - MCU_col_num); + if (MCU_count != cinfo->MCUs_per_row - MCU_col_num) { + /* Suspension forced; update state counters and exit */ + diff->MCU_vert_offset = yoffset; + diff->MCU_ctr += MCU_count; + return JPEG_SUSPENDED; + } + + /* Account for restart interval (no-op if not using restarts) */ + diff->restart_rows_to_go--; + + /* Completed an MCU row, but perhaps not an iMCU row */ + diff->MCU_ctr = 0; + } + + /* + * Undifference and scale each scanline of the disassembled MCU-row + * separately. We do not process dummy samples at the end of a scanline + * or dummy rows at the end of the image. + */ + for (comp = 0; comp < cinfo->comps_in_scan; comp++) { + compptr = cinfo->cur_comp_info[comp]; + ci = compptr->component_index; + for (row = 0, prev_row = compptr->v_samp_factor - 1; + row < (cinfo->input_iMCU_row == last_iMCU_row ? + compptr->last_row_height : compptr->v_samp_factor); + prev_row = row, row++) { + (*losslsd->predict_undifference[ci]) (cinfo, ci, + diff->diff_buf[ci][row], + diff->undiff_buf[ci][prev_row], + diff->undiff_buf[ci][row], + compptr->width_in_data_units); + (*losslsd->scaler_scale) (cinfo, diff->undiff_buf[ci][row], + output_buf[ci][row], + compptr->width_in_data_units); + } + } + + /* Completed the iMCU row, advance counters for next one. + * + * NB: output_data will increment output_iMCU_row. + * This counter is not needed for the single-pass case + * or the input side of the multi-pass case. + */ + if (++(cinfo->input_iMCU_row) < cinfo->total_iMCU_rows) { + start_iMCU_row(cinfo); + return JPEG_ROW_COMPLETED; + } + /* Completed the scan */ + (*cinfo->inputctl->finish_input_pass) (cinfo); + return JPEG_SCAN_COMPLETED; +} + + +/* + * Dummy consume-input routine for single-pass operation. + */ + +METHODDEF(int) +dummy_consume_data (j_decompress_ptr cinfo) +{ + (void)cinfo; + return JPEG_SUSPENDED; /* Always indicate nothing was done */ +} + + +#ifdef D_MULTISCAN_FILES_SUPPORTED + +/* + * Consume input data and store it in the full-image sample buffer. + * We read as much as one fully interleaved MCU row ("iMCU" row) per call, + * ie, v_samp_factor rows for each component in the scan. + * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED. + */ + +METHODDEF(int) +consume_data (j_decompress_ptr cinfo) +{ + j_lossless_d_ptr losslsd = (j_lossless_d_ptr) cinfo->codec; + d_diff_ptr diff = (d_diff_ptr) losslsd->diff_private; + /* JDIMENSION MCU_col_num; */ /* index of current MCU within row */ + /* JDIMENSION MCU_count; */ /* number of MCUs decoded */ + /* JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; */ + int comp, ci /* , yoffset, row, prev_row */; + JSAMPARRAY buffer[MAX_COMPS_IN_SCAN]; + jpeg_component_info *compptr; + + /* Align the virtual buffers for the components used in this scan. */ + for (comp = 0; comp < cinfo->comps_in_scan; comp++) { + compptr = cinfo->cur_comp_info[comp]; + ci = compptr->component_index; + buffer[ci] = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, diff->whole_image[ci], + cinfo->input_iMCU_row * compptr->v_samp_factor, + (JDIMENSION) compptr->v_samp_factor, TRUE); + } + + return decompress_data(cinfo, buffer); +} + + +/* + * Output some data from the full-image buffer sample in the multi-pass case. + * Always attempts to emit one fully interleaved MCU row ("iMCU" row). + * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED. + * + * NB: output_buf contains a plane for each component in image. + */ + +METHODDEF(int) +output_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf) +{ + j_lossless_d_ptr losslsd = (j_lossless_d_ptr) cinfo->codec; + d_diff_ptr diff = (d_diff_ptr) losslsd->diff_private; + JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; + int ci, samp_rows, row; + JSAMPARRAY buffer; + jpeg_component_info *compptr; + + /* Force some input to be done if we are getting ahead of the input. */ + while (cinfo->input_scan_number < cinfo->output_scan_number || + (cinfo->input_scan_number == cinfo->output_scan_number && + cinfo->input_iMCU_row <= cinfo->output_iMCU_row)) { + if ((*cinfo->inputctl->consume_input)(cinfo) == JPEG_SUSPENDED) + return JPEG_SUSPENDED; + } + + /* OK, output from the virtual arrays. */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Align the virtual buffer for this component. */ + buffer = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, diff->whole_image[ci], + cinfo->output_iMCU_row * compptr->v_samp_factor, + (JDIMENSION) compptr->v_samp_factor, FALSE); + + if (cinfo->output_iMCU_row < last_iMCU_row) + samp_rows = compptr->v_samp_factor; + else { + /* NB: can't use last_row_height here; it is input-side-dependent! */ + samp_rows = (int) (compptr->height_in_data_units % compptr->v_samp_factor); + if (samp_rows == 0) samp_rows = compptr->v_samp_factor; + } + + for (row = 0; row < samp_rows; row++) { + MEMCOPY(output_buf[ci][row], buffer[row], + compptr->width_in_data_units * SIZEOF(JSAMPLE)); + } + } + + if (++(cinfo->output_iMCU_row) < cinfo->total_iMCU_rows) + return JPEG_ROW_COMPLETED; + return JPEG_SCAN_COMPLETED; +} + +#endif /* D_MULTISCAN_FILES_SUPPORTED */ + + +/* + * Initialize difference buffer controller. + */ + +GLOBAL(void) +jinit_d_diff_controller (j_decompress_ptr cinfo, boolean need_full_buffer) +{ + j_lossless_d_ptr losslsd = (j_lossless_d_ptr) cinfo->codec; + d_diff_ptr diff; + int ci; + jpeg_component_info *compptr; + + diff = (d_diff_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(d_diff_controller)); + losslsd->diff_private = (void *) diff; + losslsd->diff_start_input_pass = start_input_pass; + losslsd->pub.start_output_pass = start_output_pass; + + /* Create the [un]difference buffers. */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + diff->diff_buf[ci] = (*cinfo->mem->alloc_darray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (JDIMENSION) jround_up((long) compptr->width_in_data_units, + (long) compptr->h_samp_factor), + (JDIMENSION) compptr->v_samp_factor); + diff->undiff_buf[ci] = (*cinfo->mem->alloc_darray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (JDIMENSION) jround_up((long) compptr->width_in_data_units, + (long) compptr->h_samp_factor), + (JDIMENSION) compptr->v_samp_factor); + } + + if (need_full_buffer) { +#ifdef D_MULTISCAN_FILES_SUPPORTED + /* Allocate a full-image virtual array for each component. */ + int access_rows; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + access_rows = compptr->v_samp_factor; + diff->whole_image[ci] = (*cinfo->mem->request_virt_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE, + (JDIMENSION) jround_up((long) compptr->width_in_data_units, + (long) compptr->h_samp_factor), + (JDIMENSION) jround_up((long) compptr->height_in_data_units, + (long) compptr->v_samp_factor), + (JDIMENSION) access_rows); + } + losslsd->pub.consume_data = consume_data; + losslsd->pub.decompress_data = output_data; +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else { + losslsd->pub.consume_data = dummy_consume_data; + losslsd->pub.decompress_data = decompress_data; + diff->whole_image[0] = NULL; /* flag for no virtual arrays */ + } +} + +#endif /* D_LOSSLESS_SUPPORTED */ diff --git a/Utilities/ITK/Utilities/itkjpeg/jdhuff.c b/Utilities/ITK/Utilities/itkjpeg/jdhuff.c new file mode 100644 index 0000000000000000000000000000000000000000..54a827241c740c36fa3de1bf2eedded042d05747 --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jdhuff.c @@ -0,0 +1,321 @@ +/* + * jdhuff.c + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains Huffman entropy decoding routines which are shared + * by the sequential, progressive and lossless decoders. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jlossy.h" /* Private declarations for lossy codec */ +#include "jlossls.h" /* Private declarations for lossless codec */ +#include "jdhuff.h" /* Declarations shared with jd*huff.c */ + + +/* + * Compute the derived values for a Huffman table. + * This routine also performs some validation checks on the table. + */ + +GLOBAL(void) +jpeg_make_d_derived_tbl (j_decompress_ptr cinfo, boolean isDC, int tblno, + d_derived_tbl ** pdtbl) +{ + JHUFF_TBL *htbl; + d_derived_tbl *dtbl; + int p, i, l, si, numsymbols; + int lookbits, ctr; + char huffsize[257]; + unsigned int huffcode[257]; + unsigned int code; + + /* Note that huffsize[] and huffcode[] are filled in code-length order, + * paralleling the order of the symbols themselves in htbl->huffval[]. + */ + + /* Find the input Huffman table */ + if (tblno < 0 || tblno >= NUM_HUFF_TBLS) + ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tblno); + htbl = + isDC ? cinfo->dc_huff_tbl_ptrs[tblno] : cinfo->ac_huff_tbl_ptrs[tblno]; + if (htbl == NULL) + ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tblno); + + /* Allocate a workspace if we haven't already done so. */ + if (*pdtbl == NULL) + *pdtbl = (d_derived_tbl *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(d_derived_tbl)); + dtbl = *pdtbl; + dtbl->pub = htbl; /* fill in back link */ + + /* Figure C.1: make table of Huffman code length for each symbol */ + + p = 0; + for (l = 1; l <= 16; l++) { + i = (int) htbl->bits[l]; + if (i < 0 || p + i > 256) /* protect against table overrun */ + ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); + while (i--) + huffsize[p++] = (char) l; + } + huffsize[p] = 0; + numsymbols = p; + + /* Figure C.2: generate the codes themselves */ + /* We also validate that the counts represent a legal Huffman code tree. */ + + code = 0; + si = huffsize[0]; + p = 0; + while (huffsize[p]) { + while (((int) huffsize[p]) == si) { + huffcode[p++] = code; + code++; + } + /* code is now 1 more than the last code used for codelength si; but + * it must still fit in si bits, since no code is allowed to be all ones. + * BUG FIX 2001-09-03: Comparison must be >, not >= + */ + if (((INT32) code) > (((INT32) 1) << si)) + ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); + code <<= 1; + si++; + } + + /* Figure F.15: generate decoding tables for bit-sequential decoding */ + + p = 0; + for (l = 1; l <= 16; l++) { + if (htbl->bits[l]) { + /* valoffset[l] = huffval[] index of 1st symbol of code length l, + * minus the minimum code of length l + */ + dtbl->valoffset[l] = (INT32) p - (INT32) huffcode[p]; + p += htbl->bits[l]; + dtbl->maxcode[l] = huffcode[p-1]; /* maximum code of length l */ + } else { + dtbl->maxcode[l] = -1; /* -1 if no codes of this length */ + } + } + dtbl->maxcode[17] = 0xFFFFFL; /* ensures jpeg_huff_decode terminates */ + + /* Compute lookahead tables to speed up decoding. + * First we set all the table entries to 0, indicating "too long"; + * then we iterate through the Huffman codes that are short enough and + * fill in all the entries that correspond to bit sequences starting + * with that code. + */ + + MEMZERO(dtbl->look_nbits, SIZEOF(dtbl->look_nbits)); + + p = 0; + for (l = 1; l <= HUFF_LOOKAHEAD; l++) { + for (i = 1; i <= (int) htbl->bits[l]; i++, p++) { + /* l = current code's length, p = its index in huffcode[] & huffval[]. */ + /* Generate left-justified code followed by all possible bit sequences */ + lookbits = huffcode[p] << (HUFF_LOOKAHEAD-l); + for (ctr = 1 << (HUFF_LOOKAHEAD-l); ctr > 0; ctr--) { + dtbl->look_nbits[lookbits] = l; + dtbl->look_sym[lookbits] = htbl->huffval[p]; + lookbits++; + } + } + } + + /* Validate symbols as being reasonable. + * For AC tables, we make no check, but accept all byte values 0..255. + * For DC tables, we require the symbols to be in range 0..16. + * (Tighter bounds could be applied depending on the data depth and mode, + * but this is sufficient to ensure safe decoding.) + */ + if (isDC) { + for (i = 0; i < numsymbols; i++) { + int sym = htbl->huffval[i]; + if (sym < 0 || sym > 16) +/* The following is needed to be able to read certain Philips DICOM MRI images */ +#if BITS_IN_JSAMPLE == 12 + htbl->huffval[i]=15; +#else + ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); +#endif /* BITS_IN_JSAMPLE == 12 */ + } + } +} + + +/* + * Out-of-line code for bit fetching. + * See jdhuff.h for info about usage. + * Note: current values of get_buffer and bits_left are passed as parameters, + * but are returned in the corresponding fields of the state struct. + * + * On most machines MIN_GET_BITS should be 25 to allow the full 32-bit width + * of get_buffer to be used. (On machines with wider words, an even larger + * buffer could be used.) However, on some machines 32-bit shifts are + * quite slow and take time proportional to the number of places shifted. + * (This is true with most PC compilers, for instance.) In this case it may + * be a win to set MIN_GET_BITS to the minimum value of 15. This reduces the + * average shift distance at the cost of more calls to jpeg_fill_bit_buffer. + */ + +#ifdef SLOW_SHIFT_32 +#define MIN_GET_BITS 15 /* minimum allowable value */ +#else +#define MIN_GET_BITS (BIT_BUF_SIZE-7) +#endif + + +GLOBAL(boolean) +jpeg_fill_bit_buffer (bitread_working_state * state, + register bit_buf_type get_buffer, register int bits_left, + int nbits) +/* Load up the bit buffer to a depth of at least nbits */ +{ + /* Copy heavily used state fields into locals (hopefully registers) */ + register const JOCTET * next_input_byte = state->next_input_byte; + register size_t bytes_in_buffer = state->bytes_in_buffer; + j_decompress_ptr cinfo = state->cinfo; + + /* Attempt to load at least MIN_GET_BITS bits into get_buffer. */ + /* (It is assumed that no request will be for more than that many bits.) */ + /* We fail to do so only if we hit a marker or are forced to suspend. */ + + if (cinfo->unread_marker == 0) { /* cannot advance past a marker */ + while (bits_left < MIN_GET_BITS) { + register int c; + + /* Attempt to read a byte */ + if (bytes_in_buffer == 0) { + if (! (*cinfo->src->fill_input_buffer) (cinfo)) + return FALSE; + next_input_byte = cinfo->src->next_input_byte; + bytes_in_buffer = cinfo->src->bytes_in_buffer; + } + bytes_in_buffer--; + c = GETJOCTET(*next_input_byte++); + + /* If it's 0xFF, check and discard stuffed zero byte */ + if (c == 0xFF) { + /* Loop here to discard any padding FF's on terminating marker, + * so that we can save a valid unread_marker value. NOTE: we will + * accept multiple FF's followed by a 0 as meaning a single FF data + * byte. This data pattern is not valid according to the standard. + */ + do { + if (bytes_in_buffer == 0) { + if (! (*cinfo->src->fill_input_buffer) (cinfo)) + return FALSE; + next_input_byte = cinfo->src->next_input_byte; + bytes_in_buffer = cinfo->src->bytes_in_buffer; + } + bytes_in_buffer--; + c = GETJOCTET(*next_input_byte++); + } while (c == 0xFF); + + if (c == 0) { + /* Found FF/00, which represents an FF data byte */ + c = 0xFF; + } else { + /* Oops, it's actually a marker indicating end of compressed data. + * Save the marker code for later use. + * Fine point: it might appear that we should save the marker into + * bitread working state, not straight into permanent state. But + * once we have hit a marker, we cannot need to suspend within the + * current MCU, because we will read no more bytes from the data + * source. So it is OK to update permanent state right away. + */ + cinfo->unread_marker = c; + /* See if we need to insert some fake zero bits. */ + goto no_more_bytes; + } + } + + /* OK, load c into get_buffer */ + get_buffer = (get_buffer << 8) | c; + bits_left += 8; + } /* end while */ + } else { + no_more_bytes: + /* We get here if we've read the marker that terminates the compressed + * data segment. There should be enough bits in the buffer register + * to satisfy the request; if so, no problem. + */ + if (nbits > bits_left) { + /* Uh-oh. Report corrupted data to user and stuff zeroes into + * the data stream, so that we can produce some kind of image. + * We use a nonvolatile flag to ensure that only one warning message + * appears per data segment. + */ + huffd_common_ptr huffd; + if (cinfo->process == JPROC_LOSSLESS) + huffd = (huffd_common_ptr) ((j_lossless_d_ptr) cinfo->codec)->entropy_private; + else + huffd = (huffd_common_ptr) ((j_lossy_d_ptr) cinfo->codec)->entropy_private; + if (! huffd->insufficient_data) { + WARNMS(cinfo, JWRN_HIT_MARKER); + huffd->insufficient_data = TRUE; + } + /* Fill the buffer with zero bits */ + get_buffer <<= MIN_GET_BITS - bits_left; + bits_left = MIN_GET_BITS; + } + } + + /* Unload the local registers */ + state->next_input_byte = next_input_byte; + state->bytes_in_buffer = bytes_in_buffer; + state->get_buffer = get_buffer; + state->bits_left = bits_left; + + return TRUE; +} + + +/* + * Out-of-line code for Huffman code decoding. + * See jdhuff.h for info about usage. + */ + +GLOBAL(int) +jpeg_huff_decode (bitread_working_state * state, + register bit_buf_type get_buffer, register int bits_left, + d_derived_tbl * htbl, int min_bits) +{ + register int l = min_bits; + register INT32 code; + + /* HUFF_DECODE has determined that the code is at least min_bits */ + /* bits long, so fetch that many bits in one swoop. */ + + CHECK_BIT_BUFFER(*state, l, return -1); + code = GET_BITS(l); + + /* Collect the rest of the Huffman code one bit at a time. */ + /* This is per Figure F.16 in the JPEG spec. */ + + while (code > htbl->maxcode[l]) { + code <<= 1; + CHECK_BIT_BUFFER(*state, 1, return -1); + code |= GET_BITS(1); + l++; + } + + /* Unload the local registers */ + state->get_buffer = get_buffer; + state->bits_left = bits_left; + + /* With garbage input we may reach the sentinel value l = 17. */ + + if (l > 16) { + WARNMS(state->cinfo, JWRN_HUFF_BAD_CODE); + return 0; /* fake a zero as the safest result */ + } + + return htbl->pub->huffval[ (int) (code + htbl->valoffset[l]) ]; +} diff --git a/Utilities/ITK/Utilities/itkjpeg/jdhuff.h b/Utilities/ITK/Utilities/itkjpeg/jdhuff.h new file mode 100644 index 0000000000000000000000000000000000000000..907465628a0fc9f20b6a00c44702016d4101e4d7 --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jdhuff.h @@ -0,0 +1,229 @@ +/* + * jdhuff.h + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains declarations for Huffman entropy decoding routines + * that are shared between the sequential decoder (jdhuff.c), the + * progressive decoder (jdphuff.c) and the lossless decoder (jdlhuff.c). + * No other modules need to see these. + */ + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_make_d_derived_tbl jMkDDerived +#define jpeg_fill_bit_buffer jFilBitBuf +#define jpeg_huff_decode jHufDecode +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + +/* Derived data constructed for each Huffman table */ + +#define HUFF_LOOKAHEAD 8 /* # of bits of lookahead */ + +typedef struct { + /* Basic tables: (element [0] of each array is unused) */ + INT32 maxcode[18]; /* largest code of length k (-1 if none) */ + /* (maxcode[17] is a sentinel to ensure jpeg_huff_decode terminates) */ + INT32 valoffset[17]; /* huffval[] offset for codes of length k */ + /* valoffset[k] = huffval[] index of 1st symbol of code length k, less + * the smallest code of length k; so given a code of length k, the + * corresponding symbol is huffval[code + valoffset[k]] + */ + + /* Link to public Huffman table (needed only in jpeg_huff_decode) */ + JHUFF_TBL *pub; + + /* Lookahead tables: indexed by the next HUFF_LOOKAHEAD bits of + * the input data stream. If the next Huffman code is no more + * than HUFF_LOOKAHEAD bits long, we can obtain its length and + * the corresponding symbol directly from these tables. + */ + int look_nbits[1<<HUFF_LOOKAHEAD]; /* # bits, or 0 if too long */ + UINT8 look_sym[1<<HUFF_LOOKAHEAD]; /* symbol, or unused */ +} d_derived_tbl; + +/* Expand a Huffman table definition into the derived format */ +EXTERN(void) jpeg_make_d_derived_tbl + JPP((j_decompress_ptr cinfo, boolean isDC, int tblno, + d_derived_tbl ** pdtbl)); + + +/* + * Fetching the next N bits from the input stream is a time-critical operation + * for the Huffman decoders. We implement it with a combination of inline + * macros and out-of-line subroutines. Note that N (the number of bits + * demanded at one time) never exceeds 15 for JPEG use. + * + * We read source bytes into get_buffer and dole out bits as needed. + * If get_buffer already contains enough bits, they are fetched in-line + * by the macros CHECK_BIT_BUFFER and GET_BITS. When there aren't enough + * bits, jpeg_fill_bit_buffer is called; it will attempt to fill get_buffer + * as full as possible (not just to the number of bits needed; this + * prefetching reduces the overhead cost of calling jpeg_fill_bit_buffer). + * Note that jpeg_fill_bit_buffer may return FALSE to indicate suspension. + * On TRUE return, jpeg_fill_bit_buffer guarantees that get_buffer contains + * at least the requested number of bits --- dummy zeroes are inserted if + * necessary. + */ + +typedef INT32 bit_buf_type; /* type of bit-extraction buffer */ +#define BIT_BUF_SIZE 32 /* size of buffer in bits */ + +/* If long is > 32 bits on your machine, and shifting/masking longs is + * reasonably fast, making bit_buf_type be long and setting BIT_BUF_SIZE + * appropriately should be a win. Unfortunately we can't define the size + * with something like #define BIT_BUF_SIZE (sizeof(bit_buf_type)*8) + * because not all machines measure sizeof in 8-bit bytes. + */ + +typedef struct { /* Bitreading state saved across MCUs */ + bit_buf_type get_buffer; /* current bit-extraction buffer */ + int bits_left; /* # of unused bits in it */ +} bitread_perm_state; + +typedef struct { /* Bitreading working state within an MCU */ + /* Current data source location */ + /* We need a copy, rather than munging the original, in case of suspension */ + const JOCTET * next_input_byte; /* => next byte to read from source */ + size_t bytes_in_buffer; /* # of bytes remaining in source buffer */ + /* Bit input buffer --- note these values are kept in register variables, + * not in this struct, inside the inner loops. + */ + bit_buf_type get_buffer; /* current bit-extraction buffer */ + int bits_left; /* # of unused bits in it */ + /* Pointer needed by jpeg_fill_bit_buffer. */ + j_decompress_ptr cinfo; /* back link to decompress master record */ +} bitread_working_state; + +/* Macros to declare and load/save bitread local variables. */ +#define BITREAD_STATE_VARS \ + register bit_buf_type get_buffer; \ + register int bits_left; \ + bitread_working_state br_state + +#define BITREAD_LOAD_STATE(cinfop,permstate) \ + br_state.cinfo = cinfop; \ + br_state.next_input_byte = cinfop->src->next_input_byte; \ + br_state.bytes_in_buffer = cinfop->src->bytes_in_buffer; \ + get_buffer = permstate.get_buffer; \ + bits_left = permstate.bits_left; + +#define BITREAD_SAVE_STATE(cinfop,permstate) \ + cinfop->src->next_input_byte = br_state.next_input_byte; \ + cinfop->src->bytes_in_buffer = br_state.bytes_in_buffer; \ + permstate.get_buffer = get_buffer; \ + permstate.bits_left = bits_left + +/* + * These macros provide the in-line portion of bit fetching. + * Use CHECK_BIT_BUFFER to ensure there are N bits in get_buffer + * before using GET_BITS, PEEK_BITS, or DROP_BITS. + * The variables get_buffer and bits_left are assumed to be locals, + * but the state struct might not be (jpeg_huff_decode needs this). + * CHECK_BIT_BUFFER(state,n,action); + * Ensure there are N bits in get_buffer; if suspend, take action. + * val = GET_BITS(n); + * Fetch next N bits. + * val = PEEK_BITS(n); + * Fetch next N bits without removing them from the buffer. + * DROP_BITS(n); + * Discard next N bits. + * The value N should be a simple variable, not an expression, because it + * is evaluated multiple times. + */ + +#define CHECK_BIT_BUFFER(state,nbits,action) \ + { if (bits_left < (nbits)) { \ + if (! jpeg_fill_bit_buffer(&(state),get_buffer,bits_left,nbits)) \ + { action; } \ + get_buffer = (state).get_buffer; bits_left = (state).bits_left; } } + +#define GET_BITS(nbits) \ + (((int) (get_buffer >> (bits_left -= (nbits)))) & ((1<<(nbits))-1)) + +#define PEEK_BITS(nbits) \ + (((int) (get_buffer >> (bits_left - (nbits)))) & ((1<<(nbits))-1)) + +#define DROP_BITS(nbits) \ + (bits_left -= (nbits)) + +/* Load up the bit buffer to a depth of at least nbits */ +EXTERN(boolean) jpeg_fill_bit_buffer + JPP((bitread_working_state * state, register bit_buf_type get_buffer, + register int bits_left, int nbits)); + + +/* + * Code for extracting next Huffman-coded symbol from input bit stream. + * Again, this is time-critical and we make the main paths be macros. + * + * We use a lookahead table to process codes of up to HUFF_LOOKAHEAD bits + * without looping. Usually, more than 95% of the Huffman codes will be 8 + * or fewer bits long. The few overlength codes are handled with a loop, + * which need not be inline code. + * + * Notes about the HUFF_DECODE macro: + * 1. Near the end of the data segment, we may fail to get enough bits + * for a lookahead. In that case, we do it the hard way. + * 2. If the lookahead table contains no entry, the next code must be + * more than HUFF_LOOKAHEAD bits long. + * 3. jpeg_huff_decode returns -1 if forced to suspend. + */ + +#define HUFF_DECODE(result,state,htbl,failaction,slowlabel) \ +{ register int nb, look; \ + if (bits_left < HUFF_LOOKAHEAD) { \ + if (! jpeg_fill_bit_buffer(&state,get_buffer,bits_left, 0)) {failaction;} \ + get_buffer = state.get_buffer; bits_left = state.bits_left; \ + if (bits_left < HUFF_LOOKAHEAD) { \ + nb = 1; goto slowlabel; \ + } \ + } \ + look = PEEK_BITS(HUFF_LOOKAHEAD); \ + if ((nb = htbl->look_nbits[look]) != 0) { \ + DROP_BITS(nb); \ + result = htbl->look_sym[look]; \ + } else { \ + nb = HUFF_LOOKAHEAD+1; \ +slowlabel: \ + if ((result=jpeg_huff_decode(&state,get_buffer,bits_left,htbl,nb)) < 0) \ + { failaction; } \ + get_buffer = state.get_buffer; bits_left = state.bits_left; \ + } \ +} + +/* Out-of-line case for Huffman code fetching */ +EXTERN(int) jpeg_huff_decode + JPP((bitread_working_state * state, register bit_buf_type get_buffer, + register int bits_left, d_derived_tbl * htbl, int min_bits)); + + +/* Common fields between sequential, progressive and lossless Huffman entropy + * decoder master structs. + */ + +#define huffd_common_fields \ + boolean insufficient_data; /* set TRUE after emmitting warning */ \ + /* These fields are loaded into local variables at start of each MCU. \ + * In case of suspension, we exit WITHOUT updating them. \ + */ \ + bitread_perm_state bitstate /* Bit buffer at start of MCU */ + +/* Routines that are to be used by any or all of the entropy decoders are + * declared to receive a pointer to this structure. There are no actual + * instances of huffd_common_struct, only of shuff_entropy_decoder, + * phuff_entropy_decoder and lhuff_entropy_decoder. + */ +struct huffd_common_struct { + huffd_common_fields; /* Fields common to all decoder struct types */ + /* Additional fields follow in an actual shuff_entropy_decoder, + * phuff_entropy_decoder or lhuff_entropy_decoder struct. All four structs + * must agree on these initial fields! (This would be a lot cleaner in C++.) + */ +}; + +typedef struct huffd_common_struct * huffd_common_ptr; diff --git a/Utilities/ITK/Utilities/itkjpeg/jdinput.c b/Utilities/ITK/Utilities/itkjpeg/jdinput.c new file mode 100644 index 0000000000000000000000000000000000000000..8cb0f22d81d0aa205451b74bfbc2679fed9b3fee --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jdinput.c @@ -0,0 +1,347 @@ +/* + * jdinput.c + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains input control logic for the JPEG decompressor. + * These routines are concerned with controlling the decompressor's input + * processing (marker reading and coefficient/difference decoding). + * The actual input reading is done in jdmarker.c, jdhuff.c, jdphuff.c, + * and jdlhuff.c. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Private state */ + +typedef struct { + struct jpeg_input_controller pub; /* public fields */ + + boolean inheaders; /* TRUE until first SOS is reached */ +} my_input_controller; + +typedef my_input_controller * my_inputctl_ptr; + + +/* Forward declarations */ +METHODDEF(int) consume_markers JPP((j_decompress_ptr cinfo)); + + +/* + * Routines to calculate various quantities related to the size of the image. + */ + +LOCAL(void) +initial_setup (j_decompress_ptr cinfo) +/* Called once, when first SOS marker is reached */ +{ + int ci; + jpeg_component_info *compptr; + + /* Make sure image isn't bigger than I can handle */ + if ((long) cinfo->image_height > (long) JPEG_MAX_DIMENSION || + (long) cinfo->image_width > (long) JPEG_MAX_DIMENSION) + ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) JPEG_MAX_DIMENSION); + + if (cinfo->process == JPROC_LOSSLESS) { + /* If precision > compiled-in value, we must downscale */ + if (cinfo->data_precision > BITS_IN_JSAMPLE) + WARNMS2(cinfo, JWRN_MUST_DOWNSCALE, + cinfo->data_precision, BITS_IN_JSAMPLE); + } + else { /* Lossy processes */ + /* For now, precision must match compiled-in value... */ + if (cinfo->data_precision != BITS_IN_JSAMPLE) + ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision); + } + + /* Check that number of components won't exceed internal array sizes */ + if (cinfo->num_components > MAX_COMPONENTS) + ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components, + MAX_COMPONENTS); + + /* Compute maximum sampling factors; check factor validity */ + cinfo->max_h_samp_factor = 1; + cinfo->max_v_samp_factor = 1; + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + if (compptr->h_samp_factor<=0 || compptr->h_samp_factor>MAX_SAMP_FACTOR || + compptr->v_samp_factor<=0 || compptr->v_samp_factor>MAX_SAMP_FACTOR) + ERREXIT(cinfo, JERR_BAD_SAMPLING); + cinfo->max_h_samp_factor = MAX(cinfo->max_h_samp_factor, + compptr->h_samp_factor); + cinfo->max_v_samp_factor = MAX(cinfo->max_v_samp_factor, + compptr->v_samp_factor); + } + + /* We initialize codec_data_unit and min_codec_data_unit to data_unit. + * In the full decompressor, this will be overridden by jdmaster.c; + * but in the transcoder, jdmaster.c is not used, so we must do it here. + */ + cinfo->min_codec_data_unit = cinfo->data_unit; + + /* Compute dimensions of components */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + compptr->codec_data_unit = cinfo->data_unit; + /* Size in data units */ + compptr->width_in_data_units = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor, + (long) (cinfo->max_h_samp_factor * cinfo->data_unit)); + compptr->height_in_data_units = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor, + (long) (cinfo->max_v_samp_factor * cinfo->data_unit)); + /* downsampled_width and downsampled_height will also be overridden by + * jdmaster.c if we are doing full decompression. The transcoder library + * doesn't use these values, but the calling application might. + */ + /* Size in samples */ + compptr->downsampled_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor, + (long) cinfo->max_h_samp_factor); + compptr->downsampled_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor, + (long) cinfo->max_v_samp_factor); + /* Mark component needed, until color conversion says otherwise */ + compptr->component_needed = TRUE; + /* Mark no quantization table yet saved for component */ + compptr->quant_table = NULL; + } + + /* Compute number of fully interleaved MCU rows. */ + cinfo->total_iMCU_rows = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height, + (long) (cinfo->max_v_samp_factor*cinfo->data_unit)); + + /* Decide whether file contains multiple scans */ + if (cinfo->comps_in_scan < cinfo->num_components || + cinfo->process == JPROC_PROGRESSIVE) + cinfo->inputctl->has_multiple_scans = TRUE; + else + cinfo->inputctl->has_multiple_scans = FALSE; +} + + +LOCAL(void) +per_scan_setup (j_decompress_ptr cinfo) +/* Do computations that are needed before processing a JPEG scan */ +/* cinfo->comps_in_scan and cinfo->cur_comp_info[] were set from SOS marker */ +{ + int ci, mcublks, tmp; + jpeg_component_info *compptr; + + if (cinfo->comps_in_scan == 1) { + + /* Noninterleaved (single-component) scan */ + compptr = cinfo->cur_comp_info[0]; + + /* Overall image size in MCUs */ + cinfo->MCUs_per_row = compptr->width_in_data_units; + cinfo->MCU_rows_in_scan = compptr->height_in_data_units; + + /* For noninterleaved scan, always one data unit per MCU */ + compptr->MCU_width = 1; + compptr->MCU_height = 1; + compptr->MCU_data_units = 1; + compptr->MCU_sample_width = compptr->codec_data_unit; + compptr->last_col_width = 1; + /* For noninterleaved scans, it is convenient to define last_row_height + * as the number of data unit rows present in the last iMCU row. + */ + tmp = (int) (compptr->height_in_data_units % compptr->v_samp_factor); + if (tmp == 0) tmp = compptr->v_samp_factor; + compptr->last_row_height = tmp; + + /* Prepare array describing MCU composition */ + cinfo->data_units_in_MCU = 1; + cinfo->MCU_membership[0] = 0; + + } else { + + /* Interleaved (multi-component) scan */ + if (cinfo->comps_in_scan <= 0 || cinfo->comps_in_scan > MAX_COMPS_IN_SCAN) + ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->comps_in_scan, + MAX_COMPS_IN_SCAN); + + /* Overall image size in MCUs */ + cinfo->MCUs_per_row = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width, + (long) (cinfo->max_h_samp_factor*cinfo->data_unit)); + cinfo->MCU_rows_in_scan = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height, + (long) (cinfo->max_v_samp_factor*cinfo->data_unit)); + + cinfo->data_units_in_MCU = 0; + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + /* Sampling factors give # of data units of component in each MCU */ + compptr->MCU_width = compptr->h_samp_factor; + compptr->MCU_height = compptr->v_samp_factor; + compptr->MCU_data_units = compptr->MCU_width * compptr->MCU_height; + compptr->MCU_sample_width = compptr->MCU_width * compptr->codec_data_unit; + /* Figure number of non-dummy data units in last MCU column & row */ + tmp = (int) (compptr->width_in_data_units % compptr->MCU_width); + if (tmp == 0) tmp = compptr->MCU_width; + compptr->last_col_width = tmp; + tmp = (int) (compptr->height_in_data_units % compptr->MCU_height); + if (tmp == 0) tmp = compptr->MCU_height; + compptr->last_row_height = tmp; + /* Prepare array describing MCU composition */ + mcublks = compptr->MCU_data_units; + if (cinfo->data_units_in_MCU + mcublks > D_MAX_DATA_UNITS_IN_MCU) + ERREXIT(cinfo, JERR_BAD_MCU_SIZE); + while (mcublks-- > 0) { + cinfo->MCU_membership[cinfo->data_units_in_MCU++] = ci; + } + } + + } +} + + +/* + * Initialize the input modules to read a scan of compressed data. + * The first call to this is done by jdmaster.c after initializing + * the entire decompressor (during jpeg_start_decompress). + * Subsequent calls come from consume_markers, below. + */ + +METHODDEF(void) +start_input_pass (j_decompress_ptr cinfo) +{ + per_scan_setup(cinfo); + (*cinfo->codec->start_input_pass) (cinfo); + cinfo->inputctl->consume_input = cinfo->codec->consume_data; +} + + +/* + * Finish up after inputting a compressed-data scan. + * This is called by the coefficient controller after it's read all + * the expected data of the scan. + */ + +METHODDEF(void) +finish_input_pass (j_decompress_ptr cinfo) +{ + cinfo->inputctl->consume_input = consume_markers; +} + + +/* + * Read JPEG markers before, between, or after compressed-data scans. + * Change state as necessary when a new scan is reached. + * Return value is JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI. + * + * The consume_input method pointer points either here or to the + * coefficient controller's consume_data routine, depending on whether + * we are reading a compressed data segment or inter-segment markers. + */ + +METHODDEF(int) +consume_markers (j_decompress_ptr cinfo) +{ + my_inputctl_ptr inputctl = (my_inputctl_ptr) cinfo->inputctl; + int val; + + if (inputctl->pub.eoi_reached) /* After hitting EOI, read no further */ + return JPEG_REACHED_EOI; + + val = (*cinfo->marker->read_markers) (cinfo); + + switch (val) { + case JPEG_REACHED_SOS: /* Found SOS */ + if (inputctl->inheaders) { /* 1st SOS */ + initial_setup(cinfo); + /* + * Initialize the decompression codec. We need to do this here so that + * any codec-specific fields and function pointers are available to + * the rest of the library. + */ + jinit_d_codec(cinfo); + inputctl->inheaders = FALSE; + /* Note: start_input_pass must be called by jdmaster.c + * before any more input can be consumed. jdapimin.c is + * responsible for enforcing this sequencing. + */ + } else { /* 2nd or later SOS marker */ + if (! inputctl->pub.has_multiple_scans) + ERREXIT(cinfo, JERR_EOI_EXPECTED); /* Oops, I wasn't expecting this! */ + start_input_pass(cinfo); + } + break; + case JPEG_REACHED_EOI: /* Found EOI */ + inputctl->pub.eoi_reached = TRUE; + if (inputctl->inheaders) { /* Tables-only datastream, apparently */ + if (cinfo->marker->saw_SOF) + ERREXIT(cinfo, JERR_SOF_NO_SOS); + } else { + /* Prevent infinite loop in coef ctlr's decompress_data routine + * if user set output_scan_number larger than number of scans. + */ + if (cinfo->output_scan_number > cinfo->input_scan_number) + cinfo->output_scan_number = cinfo->input_scan_number; + } + break; + case JPEG_SUSPENDED: + break; + } + + return val; +} + + +/* + * Reset state to begin a fresh datastream. + */ + +METHODDEF(void) +reset_input_controller (j_decompress_ptr cinfo) +{ + my_inputctl_ptr inputctl = (my_inputctl_ptr) cinfo->inputctl; + + inputctl->pub.consume_input = consume_markers; + inputctl->pub.has_multiple_scans = FALSE; /* "unknown" would be better */ + inputctl->pub.eoi_reached = FALSE; + inputctl->inheaders = TRUE; + /* Reset other modules */ + (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo); + (*cinfo->marker->reset_marker_reader) (cinfo); + /* Reset progression state -- would be cleaner if entropy decoder did this */ + cinfo->coef_bits = NULL; +} + + +/* + * Initialize the input controller module. + * This is called only once, when the decompression object is created. + */ + +GLOBAL(void) +jinit_input_controller (j_decompress_ptr cinfo) +{ + my_inputctl_ptr inputctl; + + /* Create subobject in permanent pool */ + inputctl = (my_inputctl_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + SIZEOF(my_input_controller)); + cinfo->inputctl = (struct jpeg_input_controller *) inputctl; + /* Initialize method pointers */ + inputctl->pub.consume_input = consume_markers; + inputctl->pub.reset_input_controller = reset_input_controller; + inputctl->pub.start_input_pass = start_input_pass; + inputctl->pub.finish_input_pass = finish_input_pass; + /* Initialize state: can't use reset_input_controller since we don't + * want to try to reset other modules yet. + */ + inputctl->pub.has_multiple_scans = FALSE; /* "unknown" would be better */ + inputctl->pub.eoi_reached = FALSE; + inputctl->inheaders = TRUE; +} diff --git a/Utilities/ITK/Utilities/itkjpeg/jdlhuff.c b/Utilities/ITK/Utilities/itkjpeg/jdlhuff.c new file mode 100644 index 0000000000000000000000000000000000000000..2ee9f28a6108b5ee344bb50b6d1ffd333ba33013 --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jdlhuff.c @@ -0,0 +1,291 @@ +/* + * jdlhuff.c + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains Huffman entropy decoding routines for lossless JPEG. + * + * Much of the complexity here has to do with supporting input suspension. + * If the data source module demands suspension, we want to be able to back + * up to the start of the current MCU. To do this, we copy state variables + * into local working storage, and update them back to the permanent + * storage only upon successful completion of an MCU. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jlossls.h" /* Private declarations for lossless codec */ +#include "jdhuff.h" /* Declarations shared with jd*huff.c */ + + +#ifdef D_LOSSLESS_SUPPORTED + +typedef struct { + int ci, yoffset, MCU_width; +} lhd_output_ptr_info; + +/* + * Private entropy decoder object for lossless Huffman decoding. + */ + +typedef struct { + huffd_common_fields; /* Fields shared with other entropy decoders */ + + /* Pointers to derived tables (these workspaces have image lifespan) */ + d_derived_tbl * derived_tbls[NUM_HUFF_TBLS]; + + /* Precalculated info set up by start_pass for use in decode_mcus: */ + + /* Pointers to derived tables to be used for each data unit within an MCU */ + d_derived_tbl * cur_tbls[D_MAX_DATA_UNITS_IN_MCU]; + + /* Pointers to the proper output difference row for each group of data units + * within an MCU. For each component, there are Vi groups of Hi data units. + */ + JDIFFROW output_ptr[D_MAX_DATA_UNITS_IN_MCU]; + + /* Number of output pointers in use for the current MCU. This is the sum + * of all Vi in the MCU. + */ + int num_output_ptrs; + + /* Information used for positioning the output pointers within the output + * difference rows. + */ + lhd_output_ptr_info output_ptr_info[D_MAX_DATA_UNITS_IN_MCU]; + + /* Index of the proper output pointer for each data unit within an MCU */ + int output_ptr_index[D_MAX_DATA_UNITS_IN_MCU]; + +} lhuff_entropy_decoder; + +typedef lhuff_entropy_decoder * lhuff_entropy_ptr; + + +/* + * Initialize for a Huffman-compressed scan. + */ + +METHODDEF(void) +start_pass_lhuff_decoder (j_decompress_ptr cinfo) +{ + j_lossless_d_ptr losslsd = (j_lossless_d_ptr) cinfo->codec; + lhuff_entropy_ptr entropy = (lhuff_entropy_ptr) losslsd->entropy_private; + int ci, dctbl, sampn, ptrn, yoffset, xoffset; + jpeg_component_info * compptr; + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + dctbl = compptr->dc_tbl_no; + /* Make sure requested tables are present */ + if (dctbl < 0 || dctbl >= NUM_HUFF_TBLS || + cinfo->dc_huff_tbl_ptrs[dctbl] == NULL) + ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, dctbl); + /* Compute derived values for Huffman tables */ + /* We may do this more than once for a table, but it's not expensive */ + jpeg_make_d_derived_tbl(cinfo, TRUE, dctbl, + & entropy->derived_tbls[dctbl]); + } + + /* Precalculate decoding info for each sample in an MCU of this scan */ + for (sampn = 0, ptrn = 0; sampn < cinfo->data_units_in_MCU;) { + compptr = cinfo->cur_comp_info[cinfo->MCU_membership[sampn]]; + ci = compptr->component_index; + for (yoffset = 0; yoffset < compptr->MCU_height; yoffset++, ptrn++) { + /* Precalculate the setup info for each output pointer */ + entropy->output_ptr_info[ptrn].ci = ci; + entropy->output_ptr_info[ptrn].yoffset = yoffset; + entropy->output_ptr_info[ptrn].MCU_width = compptr->MCU_width; + for (xoffset = 0; xoffset < compptr->MCU_width; xoffset++, sampn++) { + /* Precalculate the output pointer index for each sample */ + entropy->output_ptr_index[sampn] = ptrn; + /* Precalculate which table to use for each sample */ + entropy->cur_tbls[sampn] = entropy->derived_tbls[compptr->dc_tbl_no]; + } + } + } + entropy->num_output_ptrs = ptrn; + + /* Initialize bitread state variables */ + entropy->bitstate.bits_left = 0; + entropy->bitstate.get_buffer = 0; /* unnecessary, but keeps Purify quiet */ + entropy->insufficient_data = FALSE; +} + + +/* + * Figure F.12: extend sign bit. + * On some machines, a shift and add will be faster than a table lookup. + */ + +#ifdef AVOID_TABLES + +#define HUFF_EXTEND(x,s) ((x) < (1<<((s)-1)) ? (x) + (((-1)<<(s)) + 1) : (x)) + +#else + +#define HUFF_EXTEND(x,s) ((x) < extend_test[s] ? (x) + extend_offset[s] : (x)) + +static const int extend_test[16] = /* entry n is 2**(n-1) */ + { 0, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080, + 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000 }; + +static const int extend_offset[16] = /* entry n is (-1 << n) + 1 */ + { 0, ((-1)<<1) + 1, ((-1)<<2) + 1, ((-1)<<3) + 1, ((-1)<<4) + 1, + ((-1)<<5) + 1, ((-1)<<6) + 1, ((-1)<<7) + 1, ((-1)<<8) + 1, + ((-1)<<9) + 1, ((-1)<<10) + 1, ((-1)<<11) + 1, ((-1)<<12) + 1, + ((-1)<<13) + 1, ((-1)<<14) + 1, ((-1)<<15) + 1 }; + +#endif /* AVOID_TABLES */ + + +/* + * Check for a restart marker & resynchronize decoder. + * Returns FALSE if must suspend. + */ + +METHODDEF(boolean) +process_restart (j_decompress_ptr cinfo) +{ + j_lossless_d_ptr losslsd = (j_lossless_d_ptr) cinfo->codec; + lhuff_entropy_ptr entropy = (lhuff_entropy_ptr) losslsd->entropy_private; + /* int ci; */ + + /* Throw away any unused bits remaining in bit buffer; */ + /* include any full bytes in next_marker's count of discarded bytes */ + cinfo->marker->discarded_bytes += entropy->bitstate.bits_left / 8; + entropy->bitstate.bits_left = 0; + + /* Advance past the RSTn marker */ + if (! (*cinfo->marker->read_restart_marker) (cinfo)) + return FALSE; + + /* Reset out-of-data flag, unless read_restart_marker left us smack up + * against a marker. In that case we will end up treating the next data + * segment as empty, and we can avoid producing bogus output pixels by + * leaving the flag set. + */ + if (cinfo->unread_marker == 0) + entropy->insufficient_data = FALSE; + + return TRUE; +} + + +/* + * Decode and return nMCU's worth of Huffman-compressed differences. + * Each MCU is also disassembled and placed accordingly in diff_buf. + * + * MCU_col_num specifies the column of the first MCU being requested within + * the MCU-row. This tells us where to position the output row pointers in + * diff_buf. + * + * Returns the number of MCUs decoded. This may be less than nMCU if data + * source requested suspension. In that case no changes have been made to + * permanent state. (Exception: some output differences may already have + * been assigned. This is harmless for this module, since we'll just + * re-assign them on the next call.) + */ + +METHODDEF(JDIMENSION) +decode_mcus (j_decompress_ptr cinfo, JDIFFIMAGE diff_buf, + JDIMENSION MCU_row_num, JDIMENSION MCU_col_num, JDIMENSION nMCU) +{ + j_lossless_d_ptr losslsd = (j_lossless_d_ptr) cinfo->codec; + lhuff_entropy_ptr entropy = (lhuff_entropy_ptr) losslsd->entropy_private; + unsigned int mcu_num; + int sampn, ci, yoffset, MCU_width, ptrn; + BITREAD_STATE_VARS; + + /* Set output pointer locations based on MCU_col_num */ + for (ptrn = 0; ptrn < entropy->num_output_ptrs; ptrn++) { + ci = entropy->output_ptr_info[ptrn].ci; + yoffset = entropy->output_ptr_info[ptrn].yoffset; + MCU_width = entropy->output_ptr_info[ptrn].MCU_width; + entropy->output_ptr[ptrn] = + diff_buf[ci][MCU_row_num + yoffset] + (MCU_col_num * MCU_width); + } + + /* + * If we've run out of data, zero out the buffers and return. + * By resetting the undifferencer, the output samples will be CENTERJSAMPLE. + * + * NB: We should find a way to do this without interacting with the + * undifferencer module directly. + */ + if (entropy->insufficient_data) { + for (ptrn = 0; ptrn < entropy->num_output_ptrs; ptrn++) + jzero_far((void FAR *) entropy->output_ptr[ptrn], + nMCU * entropy->output_ptr_info[ptrn].MCU_width * SIZEOF(JDIFF)); + + (*losslsd->predict_process_restart) (cinfo); + } + + else { + + /* Load up working state */ + BITREAD_LOAD_STATE(cinfo,entropy->bitstate); + + /* Outer loop handles the number of MCU requested */ + + for (mcu_num = 0; mcu_num < nMCU; mcu_num++) { + + /* Inner loop handles the samples in the MCU */ + for (sampn = 0; sampn < cinfo->data_units_in_MCU; sampn++) { + d_derived_tbl * dctbl = entropy->cur_tbls[sampn]; + register int s, r; + + /* Section H.2.2: decode the sample difference */ + HUFF_DECODE(s, br_state, dctbl, return mcu_num, label1); + if (s) { + if (s == 16) /* special case: always output 32768 */ + s = 32768; + else { /* normal case: fetch subsequent bits */ + CHECK_BIT_BUFFER(br_state, s, return mcu_num); + r = GET_BITS(s); + s = HUFF_EXTEND(r, s); + } + } + + /* Output the sample difference */ + *entropy->output_ptr[entropy->output_ptr_index[sampn]]++ = (JDIFF) s; + } + + /* Completed MCU, so update state */ + BITREAD_SAVE_STATE(cinfo,entropy->bitstate); + } + } + + return nMCU; +} + + +/* + * Module initialization routine for lossless Huffman entropy decoding. + */ + +GLOBAL(void) +jinit_lhuff_decoder (j_decompress_ptr cinfo) +{ + j_lossless_d_ptr losslsd = (j_lossless_d_ptr) cinfo->codec; + lhuff_entropy_ptr entropy; + int i; + + entropy = (lhuff_entropy_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(lhuff_entropy_decoder)); + losslsd->entropy_private = (void *) entropy; + losslsd->entropy_start_pass = start_pass_lhuff_decoder; + losslsd->entropy_process_restart = process_restart; + losslsd->entropy_decode_mcus = decode_mcus; + + /* Mark tables unallocated */ + for (i = 0; i < NUM_HUFF_TBLS; i++) { + entropy->derived_tbls[i] = NULL; + } +} + +#endif /* D_LOSSLESS_SUPPORTED */ diff --git a/Utilities/ITK/Utilities/itkjpeg/jdlossls.c b/Utilities/ITK/Utilities/itkjpeg/jdlossls.c new file mode 100644 index 0000000000000000000000000000000000000000..046cd3b729ad63d50d32a943b923c44d1f44bed7 --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jdlossls.c @@ -0,0 +1,94 @@ +/* + * jdlossls.c + * + * Copyright (C) 1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the control logic for the lossless JPEG decompressor. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jlossls.h" + + +#ifdef D_LOSSLESS_SUPPORTED + +/* + * Compute output image dimensions and related values. + */ + +METHODDEF(void) +calc_output_dimensions (j_decompress_ptr cinfo) +{ + /* Hardwire it to "no scaling" */ + cinfo->output_width = cinfo->image_width; + cinfo->output_height = cinfo->image_height; + /* jdinput.c has already initialized codec_data_unit to 1, + * and has computed unscaled downsampled_width and downsampled_height. + */ +} + + +/* + * Initialize for an input processing pass. + */ + +METHODDEF(void) +start_input_pass (j_decompress_ptr cinfo) +{ + j_lossless_d_ptr losslsd = (j_lossless_d_ptr) cinfo->codec; + + (*losslsd->entropy_start_pass) (cinfo); + (*losslsd->predict_start_pass) (cinfo); + (*losslsd->scaler_start_pass) (cinfo); + (*losslsd->diff_start_input_pass) (cinfo); +} + + +/* + * Initialize the lossless decompression codec. + * This is called only once, during master selection. + */ + +GLOBAL(void) +jinit_lossless_d_codec(j_decompress_ptr cinfo) +{ + j_lossless_d_ptr losslsd; + boolean use_c_buffer; + + /* Create subobject in permanent pool */ + losslsd = (j_lossless_d_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + SIZEOF(jpeg_lossless_d_codec)); + cinfo->codec = (struct jpeg_d_codec *) losslsd; + + /* Initialize sub-modules */ + /* Entropy decoding: either Huffman or arithmetic coding. */ + if (cinfo->arith_code) { + jinit_arith_decoder(cinfo); + } else { + jinit_lhuff_decoder(cinfo); + } + + /* Undifferencer */ + jinit_undifferencer(cinfo); + + /* Scaler */ + jinit_d_scaler(cinfo); + + use_c_buffer = cinfo->inputctl->has_multiple_scans || cinfo->buffered_image; + jinit_d_diff_controller(cinfo, use_c_buffer); + + /* Initialize method pointers. + * + * Note: consume_data, start_output_pass and decompress_data are + * assigned in jddiffct.c. + */ + losslsd->pub.calc_output_dimensions = calc_output_dimensions; + losslsd->pub.start_input_pass = start_input_pass; +} + +#endif /* D_LOSSLESS_SUPPORTED */ diff --git a/Utilities/ITK/Utilities/itkjpeg/jdlossy.c b/Utilities/ITK/Utilities/itkjpeg/jdlossy.c new file mode 100644 index 0000000000000000000000000000000000000000..637714facf49cd0c8ac7a333aced907bd0d86ee6 --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jdlossy.c @@ -0,0 +1,228 @@ +/* + * jdlossy.c + * + * Copyright (C) 1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the control logic for the lossy JPEG decompressor. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jlossy.h" + + +/* + * Compute output image dimensions and related values. + */ + +METHODDEF(void) +calc_output_dimensions (j_decompress_ptr cinfo) +{ +#ifdef IDCT_SCALING_SUPPORTED + int ci; + jpeg_component_info *compptr; + + /* Compute actual output image dimensions and DCT scaling choices. */ + if (cinfo->scale_num * 8 <= cinfo->scale_denom) { + /* Provide 1/8 scaling */ + cinfo->output_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width, 8L); + cinfo->output_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height, 8L); + cinfo->min_codec_data_unit = 1; + } else if (cinfo->scale_num * 4 <= cinfo->scale_denom) { + /* Provide 1/4 scaling */ + cinfo->output_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width, 4L); + cinfo->output_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height, 4L); + cinfo->min_codec_data_unit = 2; + } else if (cinfo->scale_num * 2 <= cinfo->scale_denom) { + /* Provide 1/2 scaling */ + cinfo->output_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width, 2L); + cinfo->output_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height, 2L); + cinfo->min_codec_data_unit = 4; + } else { + /* Provide 1/1 scaling */ + cinfo->output_width = cinfo->image_width; + cinfo->output_height = cinfo->image_height; + cinfo->min_codec_data_unit = DCTSIZE; + } + /* In selecting the actual DCT scaling for each component, we try to + * scale up the chroma components via IDCT scaling rather than upsampling. + * This saves time if the upsampler gets to use 1:1 scaling. + * Note this code assumes that the supported DCT scalings are powers of 2. + */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + int ssize = cinfo->min_codec_data_unit; + while (ssize < DCTSIZE && + (compptr->h_samp_factor * ssize * 2 <= + cinfo->max_h_samp_factor * cinfo->min_codec_data_unit) && + (compptr->v_samp_factor * ssize * 2 <= + cinfo->max_v_samp_factor * cinfo->min_codec_data_unit)) { + ssize = ssize * 2; + } + compptr->codec_data_unit = ssize; + } + + /* Recompute downsampled dimensions of components; + * application needs to know these if using raw downsampled data. + */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Size in samples, after IDCT scaling */ + compptr->downsampled_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * + (long) (compptr->h_samp_factor * compptr->codec_data_unit), + (long) (cinfo->max_h_samp_factor * DCTSIZE)); + compptr->downsampled_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * + (long) (compptr->v_samp_factor * compptr->codec_data_unit), + (long) (cinfo->max_v_samp_factor * DCTSIZE)); + } + +#else /* !IDCT_SCALING_SUPPORTED */ + + /* Hardwire it to "no scaling" */ + cinfo->output_width = cinfo->image_width; + cinfo->output_height = cinfo->image_height; + /* jdinput.c has already initialized codec_data_unit to DCTSIZE, + * and has computed unscaled downsampled_width and downsampled_height. + */ + +#endif /* IDCT_SCALING_SUPPORTED */ +} + + +/* + * Save away a copy of the Q-table referenced by each component present + * in the current scan, unless already saved during a prior scan. + * + * In a multiple-scan JPEG file, the encoder could assign different components + * the same Q-table slot number, but change table definitions between scans + * so that each component uses a different Q-table. (The IJG encoder is not + * currently capable of doing this, but other encoders might.) Since we want + * to be able to dequantize all the components at the end of the file, this + * means that we have to save away the table actually used for each component. + * We do this by copying the table at the start of the first scan containing + * the component. + * The JPEG spec prohibits the encoder from changing the contents of a Q-table + * slot between scans of a component using that slot. If the encoder does so + * anyway, this decoder will simply use the Q-table values that were current + * at the start of the first scan for the component. + * + * The decompressor output side looks only at the saved quant tables, + * not at the current Q-table slots. + */ + +LOCAL(void) +latch_quant_tables (j_decompress_ptr cinfo) +{ + int ci, qtblno; + jpeg_component_info *compptr; + JQUANT_TBL * qtbl; + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + /* No work if we already saved Q-table for this component */ + if (compptr->quant_table != NULL) + continue; + /* Make sure specified quantization table is present */ + qtblno = compptr->quant_tbl_no; + if (qtblno < 0 || qtblno >= NUM_QUANT_TBLS || + cinfo->quant_tbl_ptrs[qtblno] == NULL) + ERREXIT1(cinfo, JERR_NO_QUANT_TABLE, qtblno); + /* OK, save away the quantization table */ + qtbl = (JQUANT_TBL *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(JQUANT_TBL)); + MEMCOPY(qtbl, cinfo->quant_tbl_ptrs[qtblno], SIZEOF(JQUANT_TBL)); + compptr->quant_table = qtbl; + } +} + + +/* + * Initialize for an input processing pass. + */ + +METHODDEF(void) +start_input_pass (j_decompress_ptr cinfo) +{ + j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; + + latch_quant_tables(cinfo); + (*lossyd->entropy_start_pass) (cinfo); + (*lossyd->coef_start_input_pass) (cinfo); +} + + +/* + * Initialize for an output processing pass. + */ + +METHODDEF(void) +start_output_pass (j_decompress_ptr cinfo) +{ + j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; + + (*lossyd->idct_start_pass) (cinfo); + (*lossyd->coef_start_output_pass) (cinfo); +} + +/* + * Initialize the lossy decompression codec. + * This is called only once, during master selection. + */ + +GLOBAL(void) +jinit_lossy_d_codec (j_decompress_ptr cinfo) +{ + j_lossy_d_ptr lossyd; + boolean use_c_buffer; + + /* Create subobject in permanent pool */ + lossyd = (j_lossy_d_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + SIZEOF(jpeg_lossy_d_codec)); + cinfo->codec = (struct jpeg_d_codec *) lossyd; + + /* Initialize sub-modules */ + + /* Inverse DCT */ + jinit_inverse_dct(cinfo); + /* Entropy decoding: either Huffman or arithmetic coding. */ + if (cinfo->arith_code) { + jinit_arith_decoder(cinfo); + } else { + if (cinfo->process == JPROC_PROGRESSIVE) { +#ifdef D_PROGRESSIVE_SUPPORTED + jinit_phuff_decoder(cinfo); +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else + jinit_shuff_decoder(cinfo); + } + + use_c_buffer = cinfo->inputctl->has_multiple_scans || cinfo->buffered_image; + jinit_d_coef_controller(cinfo, use_c_buffer); + + /* Initialize method pointers. + * + * Note: consume_data and decompress_data are assigned in jdcoefct.c. + */ + lossyd->pub.calc_output_dimensions = calc_output_dimensions; + lossyd->pub.start_input_pass = start_input_pass; + lossyd->pub.start_output_pass = start_output_pass; +} + + + + diff --git a/Utilities/ITK/Utilities/itkjpeg/jdmainct.c b/Utilities/ITK/Utilities/itkjpeg/jdmainct.c new file mode 100644 index 0000000000000000000000000000000000000000..43cb09b719e48f297974d8c8a1babbe797166741 --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jdmainct.c @@ -0,0 +1,512 @@ +/* + * jdmainct.c + * + * Copyright (C) 1994-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the main buffer controller for decompression. + * The main buffer lies between the JPEG decompressor proper and the + * post-processor; it holds downsampled data in the JPEG colorspace. + * + * Note that this code is bypassed in raw-data mode, since the application + * supplies the equivalent of the main buffer in that case. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* + * In the current system design, the main buffer need never be a full-image + * buffer; any full-height buffers will be found inside the coefficient or + * postprocessing controllers. Nonetheless, the main controller is not + * trivial. Its responsibility is to provide context rows for upsampling/ + * rescaling, and doing this in an efficient fashion is a bit tricky. + * + * Postprocessor input data is counted in "row groups". A row group + * is defined to be (v_samp_factor * codec_data_unit / min_codec_data_unit) + * sample rows of each component. (We require codec_data_unit values to be + * chosen such that these numbers are integers. In practice codec_data_unit + * values will likely be powers of two, so we actually have the stronger + * condition that codec_data_unit / min_codec_data_unit is an integer.) + * Upsampling will typically produce max_v_samp_factor pixel rows from each + * row group (times any additional scale factor that the upsampler is + * applying). + * + * The decompression codec will deliver data to us one iMCU row at a time; + * each iMCU row contains v_samp_factor * codec_data_unit sample rows, or + * exactly min_codec_data_unit row groups. (This amount of data corresponds + * to one row of MCUs when the image is fully interleaved.) Note that the + * number of sample rows varies across components, but the number of row + * groups does not. Some garbage sample rows may be included in the last iMCU + * row at the bottom of the image. + * + * Depending on the vertical scaling algorithm used, the upsampler may need + * access to the sample row(s) above and below its current input row group. + * The upsampler is required to set need_context_rows TRUE at global selection + * time if so. When need_context_rows is FALSE, this controller can simply + * obtain one iMCU row at a time from the coefficient controller and dole it + * out as row groups to the postprocessor. + * + * When need_context_rows is TRUE, this controller guarantees that the buffer + * passed to postprocessing contains at least one row group's worth of samples + * above and below the row group(s) being processed. Note that the context + * rows "above" the first passed row group appear at negative row offsets in + * the passed buffer. At the top and bottom of the image, the required + * context rows are manufactured by duplicating the first or last real sample + * row; this avoids having special cases in the upsampling inner loops. + * + * The amount of context is fixed at one row group just because that's a + * convenient number for this controller to work with. The existing + * upsamplers really only need one sample row of context. An upsampler + * supporting arbitrary output rescaling might wish for more than one row + * group of context when shrinking the image; tough, we don't handle that. + * (This is justified by the assumption that downsizing will be handled mostly + * by adjusting the codec_data_unit values, so that the actual scale factor at + * the upsample step needn't be much less than one.) + * + * To provide the desired context, we have to retain the last two row groups + * of one iMCU row while reading in the next iMCU row. (The last row group + * can't be processed until we have another row group for its below-context, + * and so we have to save the next-to-last group too for its above-context.) + * We could do this most simply by copying data around in our buffer, but + * that'd be very slow. We can avoid copying any data by creating a rather + * strange pointer structure. Here's how it works. We allocate a workspace + * consisting of M+2 row groups (where M = min_codec_data_unit is the number + * of row groups per iMCU row). We create two sets of redundant pointers to + * the workspace. Labeling the physical row groups 0 to M+1, the synthesized + * pointer lists look like this: + * M+1 M-1 + * master pointer --> 0 master pointer --> 0 + * 1 1 + * ... ... + * M-3 M-3 + * M-2 M + * M-1 M+1 + * M M-2 + * M+1 M-1 + * 0 0 + * We read alternate iMCU rows using each master pointer; thus the last two + * row groups of the previous iMCU row remain un-overwritten in the workspace. + * The pointer lists are set up so that the required context rows appear to + * be adjacent to the proper places when we pass the pointer lists to the + * upsampler. + * + * The above pictures describe the normal state of the pointer lists. + * At top and bottom of the image, we diddle the pointer lists to duplicate + * the first or last sample row as necessary (this is cheaper than copying + * sample rows around). + * + * This scheme breaks down if M < 2, ie, min_codec_data_unit is 1. In that + * situation each iMCU row provides only one row group so the buffering logic + * must be different (eg, we must read two iMCU rows before we can emit the + * first row group). For now, we simply do not support providing context + * rows when min_codec_data_unit is 1. That combination seems unlikely to + * be worth providing --- if someone wants a 1/8th-size preview, they probably + * want it quick and dirty, so a context-free upsampler is sufficient. + */ + + +/* Private buffer controller object */ + +typedef struct { + struct jpeg_d_main_controller pub; /* public fields */ + + /* Pointer to allocated workspace (M or M+2 row groups). */ + JSAMPARRAY buffer[MAX_COMPONENTS]; + + boolean buffer_full; /* Have we gotten an iMCU row from decoder? */ + JDIMENSION rowgroup_ctr; /* counts row groups output to postprocessor */ + + /* Remaining fields are only used in the context case. */ + + /* These are the master pointers to the funny-order pointer lists. */ + JSAMPIMAGE xbuffer[2]; /* pointers to weird pointer lists */ + + int whichptr; /* indicates which pointer set is now in use */ + int context_state; /* process_data state machine status */ + JDIMENSION rowgroups_avail; /* row groups available to postprocessor */ + JDIMENSION iMCU_row_ctr; /* counts iMCU rows to detect image top/bot */ +} my_main_controller; + +typedef my_main_controller * my_main_ptr; + +/* context_state values: */ +#define CTX_PREPARE_FOR_IMCU 0 /* need to prepare for MCU row */ +#define CTX_PROCESS_IMCU 1 /* feeding iMCU to postprocessor */ +#define CTX_POSTPONED_ROW 2 /* feeding postponed row group */ + + +/* Forward declarations */ +METHODDEF(void) process_data_simple_main + JPP((j_decompress_ptr cinfo, JSAMPARRAY output_buf, + JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)); +METHODDEF(void) process_data_context_main + JPP((j_decompress_ptr cinfo, JSAMPARRAY output_buf, + JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)); +#ifdef QUANT_2PASS_SUPPORTED +METHODDEF(void) process_data_crank_post + JPP((j_decompress_ptr cinfo, JSAMPARRAY output_buf, + JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)); +#endif + + +LOCAL(void) +alloc_funny_pointers (j_decompress_ptr cinfo) +/* Allocate space for the funny pointer lists. + * This is done only once, not once per pass. + */ +{ + my_main_ptr mainPtr = (my_main_ptr) cinfo->main; + int ci, rgroup; + int M = cinfo->min_codec_data_unit; + jpeg_component_info *compptr; + JSAMPARRAY xbuf; + + /* Get top-level space for component array pointers. + * We alloc both arrays with one call to save a few cycles. + */ + mainPtr->xbuffer[0] = (JSAMPIMAGE) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + cinfo->num_components * 2 * SIZEOF(JSAMPARRAY)); + mainPtr->xbuffer[1] = mainPtr->xbuffer[0] + cinfo->num_components; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + rgroup = (compptr->v_samp_factor * compptr->codec_data_unit) / + cinfo->min_codec_data_unit; /* height of a row group of component */ + /* Get space for pointer lists --- M+4 row groups in each list. + * We alloc both pointer lists with one call to save a few cycles. + */ + xbuf = (JSAMPARRAY) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + 2 * (rgroup * (M + 4)) * SIZEOF(JSAMPROW)); + xbuf += rgroup; /* want one row group at negative offsets */ + mainPtr->xbuffer[0][ci] = xbuf; + xbuf += rgroup * (M + 4); + mainPtr->xbuffer[1][ci] = xbuf; + } +} + + +LOCAL(void) +make_funny_pointers (j_decompress_ptr cinfo) +/* Create the funny pointer lists discussed in the comments above. + * The actual workspace is already allocated (in mainPtr->buffer), + * and the space for the pointer lists is allocated too. + * This routine just fills in the curiously ordered lists. + * This will be repeated at the beginning of each pass. + */ +{ + my_main_ptr mainPtr = (my_main_ptr) cinfo->main; + int ci, i, rgroup; + int M = cinfo->min_codec_data_unit; + jpeg_component_info *compptr; + JSAMPARRAY buf, xbuf0, xbuf1; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + rgroup = (compptr->v_samp_factor * compptr->codec_data_unit) / + cinfo->min_codec_data_unit; /* height of a row group of component */ + xbuf0 = mainPtr->xbuffer[0][ci]; + xbuf1 = mainPtr->xbuffer[1][ci]; + /* First copy the workspace pointers as-is */ + buf = mainPtr->buffer[ci]; + for (i = 0; i < rgroup * (M + 2); i++) { + xbuf0[i] = xbuf1[i] = buf[i]; + } + /* In the second list, put the last four row groups in swapped order */ + for (i = 0; i < rgroup * 2; i++) { + xbuf1[rgroup*(M-2) + i] = buf[rgroup*M + i]; + xbuf1[rgroup*M + i] = buf[rgroup*(M-2) + i]; + } + /* The wraparound pointers at top and bottom will be filled later + * (see set_wraparound_pointers, below). Initially we want the "above" + * pointers to duplicate the first actual data line. This only needs + * to happen in xbuffer[0]. + */ + for (i = 0; i < rgroup; i++) { + xbuf0[i - rgroup] = xbuf0[0]; + } + } +} + + +LOCAL(void) +set_wraparound_pointers (j_decompress_ptr cinfo) +/* Set up the "wraparound" pointers at top and bottom of the pointer lists. + * This changes the pointer list state from top-of-image to the normal state. + */ +{ + my_main_ptr mainPtr = (my_main_ptr) cinfo->main; + int ci, i, rgroup; + int M = cinfo->min_codec_data_unit; + jpeg_component_info *compptr; + JSAMPARRAY xbuf0, xbuf1; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + rgroup = (compptr->v_samp_factor * compptr->codec_data_unit) / + cinfo->min_codec_data_unit; /* height of a row group of component */ + xbuf0 = mainPtr->xbuffer[0][ci]; + xbuf1 = mainPtr->xbuffer[1][ci]; + for (i = 0; i < rgroup; i++) { + xbuf0[i - rgroup] = xbuf0[rgroup*(M+1) + i]; + xbuf1[i - rgroup] = xbuf1[rgroup*(M+1) + i]; + xbuf0[rgroup*(M+2) + i] = xbuf0[i]; + xbuf1[rgroup*(M+2) + i] = xbuf1[i]; + } + } +} + + +LOCAL(void) +set_bottom_pointers (j_decompress_ptr cinfo) +/* Change the pointer lists to duplicate the last sample row at the bottom + * of the image. whichptr indicates which xbuffer holds the final iMCU row. + * Also sets rowgroups_avail to indicate number of nondummy row groups in row. + */ +{ + my_main_ptr mainPtr = (my_main_ptr) cinfo->main; + int ci, i, rgroup, iMCUheight, rows_left; + jpeg_component_info *compptr; + JSAMPARRAY xbuf; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Count sample rows in one iMCU row and in one row group */ + iMCUheight = compptr->v_samp_factor * compptr->codec_data_unit; + rgroup = iMCUheight / cinfo->min_codec_data_unit; + /* Count nondummy sample rows remaining for this component */ + rows_left = (int) (compptr->downsampled_height % (JDIMENSION) iMCUheight); + if (rows_left == 0) rows_left = iMCUheight; + /* Count nondummy row groups. Should get same answer for each component, + * so we need only do it once. + */ + if (ci == 0) { + mainPtr->rowgroups_avail = (JDIMENSION) ((rows_left-1) / rgroup + 1); + } + /* Duplicate the last real sample row rgroup*2 times; this pads out the + * last partial rowgroup and ensures at least one full rowgroup of context. + */ + xbuf = mainPtr->xbuffer[mainPtr->whichptr][ci]; + for (i = 0; i < rgroup * 2; i++) { + xbuf[rows_left + i] = xbuf[rows_left-1]; + } + } +} + + +/* + * Initialize for a processing pass. + */ + +METHODDEF(void) +start_pass_main (j_decompress_ptr cinfo, J_BUF_MODE pass_mode) +{ + my_main_ptr mainPtr = (my_main_ptr) cinfo->main; + + switch (pass_mode) { + case JBUF_PASS_THRU: + if (cinfo->upsample->need_context_rows) { + mainPtr->pub.process_data = process_data_context_main; + make_funny_pointers(cinfo); /* Create the xbuffer[] lists */ + mainPtr->whichptr = 0; /* Read first iMCU row into xbuffer[0] */ + mainPtr->context_state = CTX_PREPARE_FOR_IMCU; + mainPtr->iMCU_row_ctr = 0; + } else { + /* Simple case with no context needed */ + mainPtr->pub.process_data = process_data_simple_main; + } + mainPtr->buffer_full = FALSE; /* Mark buffer empty */ + mainPtr->rowgroup_ctr = 0; + break; +#ifdef QUANT_2PASS_SUPPORTED + case JBUF_CRANK_DEST: + /* For last pass of 2-pass quantization, just crank the postprocessor */ + mainPtr->pub.process_data = process_data_crank_post; + break; +#endif + default: + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + break; + } +} + + +/* + * Process some data. + * This handles the simple case where no context is required. + */ + +METHODDEF(void) +process_data_simple_main (j_decompress_ptr cinfo, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) +{ + my_main_ptr mainPtr = (my_main_ptr) cinfo->main; + JDIMENSION rowgroups_avail; + + /* Read input data if we haven't filled the main buffer yet */ + if (! mainPtr->buffer_full) { + if (! (*cinfo->codec->decompress_data) (cinfo, mainPtr->buffer)) + return; /* suspension forced, can do nothing more */ + mainPtr->buffer_full = TRUE; /* OK, we have an iMCU row to work with */ + } + + /* There are always min_codec_data_unit row groups in an iMCU row. */ + rowgroups_avail = (JDIMENSION) cinfo->min_codec_data_unit; + /* Note: at the bottom of the image, we may pass extra garbage row groups + * to the postprocessor. The postprocessor has to check for bottom + * of image anyway (at row resolution), so no point in us doing it too. + */ + + /* Feed the postprocessor */ + (*cinfo->post->post_process_data) (cinfo, mainPtr->buffer, + &mainPtr->rowgroup_ctr, rowgroups_avail, + output_buf, out_row_ctr, out_rows_avail); + + /* Has postprocessor consumed all the data yet? If so, mark buffer empty */ + if (mainPtr->rowgroup_ctr >= rowgroups_avail) { + mainPtr->buffer_full = FALSE; + mainPtr->rowgroup_ctr = 0; + } +} + + +/* + * Process some data. + * This handles the case where context rows must be provided. + */ + +METHODDEF(void) +process_data_context_main (j_decompress_ptr cinfo, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) +{ + my_main_ptr mainPtr = (my_main_ptr) cinfo->main; + + /* Read input data if we haven't filled the main buffer yet */ + if (! mainPtr->buffer_full) { + if (! (*cinfo->codec->decompress_data) (cinfo, + mainPtr->xbuffer[mainPtr->whichptr])) + return; /* suspension forced, can do nothing more */ + mainPtr->buffer_full = TRUE; /* OK, we have an iMCU row to work with */ + mainPtr->iMCU_row_ctr++; /* count rows received */ + } + + /* Postprocessor typically will not swallow all the input data it is handed + * in one call (due to filling the output buffer first). Must be prepared + * to exit and restart. This switch lets us keep track of how far we got. + * Note that each case falls through to the next on successful completion. + */ + switch (mainPtr->context_state) { + case CTX_POSTPONED_ROW: + /* Call postprocessor using previously set pointers for postponed row */ + (*cinfo->post->post_process_data) (cinfo, mainPtr->xbuffer[mainPtr->whichptr], + &mainPtr->rowgroup_ctr, mainPtr->rowgroups_avail, + output_buf, out_row_ctr, out_rows_avail); + if (mainPtr->rowgroup_ctr < mainPtr->rowgroups_avail) + return; /* Need to suspend */ + mainPtr->context_state = CTX_PREPARE_FOR_IMCU; + if (*out_row_ctr >= out_rows_avail) + return; /* Postprocessor exactly filled output buf */ + /*FALLTHROUGH*/ + case CTX_PREPARE_FOR_IMCU: + /* Prepare to process first M-1 row groups of this iMCU row */ + mainPtr->rowgroup_ctr = 0; + mainPtr->rowgroups_avail = (JDIMENSION) (cinfo->min_codec_data_unit - 1); + /* Check for bottom of image: if so, tweak pointers to "duplicate" + * the last sample row, and adjust rowgroups_avail to ignore padding rows. + */ + if (mainPtr->iMCU_row_ctr == cinfo->total_iMCU_rows) + set_bottom_pointers(cinfo); + mainPtr->context_state = CTX_PROCESS_IMCU; + /*FALLTHROUGH*/ + case CTX_PROCESS_IMCU: + /* Call postprocessor using previously set pointers */ + (*cinfo->post->post_process_data) (cinfo, mainPtr->xbuffer[mainPtr->whichptr], + &mainPtr->rowgroup_ctr, mainPtr->rowgroups_avail, + output_buf, out_row_ctr, out_rows_avail); + if (mainPtr->rowgroup_ctr < mainPtr->rowgroups_avail) + return; /* Need to suspend */ + /* After the first iMCU, change wraparound pointers to normal state */ + if (mainPtr->iMCU_row_ctr == 1) + set_wraparound_pointers(cinfo); + /* Prepare to load new iMCU row using other xbuffer list */ + mainPtr->whichptr ^= 1; /* 0=>1 or 1=>0 */ + mainPtr->buffer_full = FALSE; + /* Still need to process last row group of this iMCU row, */ + /* which is saved at index M+1 of the other xbuffer */ + mainPtr->rowgroup_ctr = (JDIMENSION) (cinfo->min_codec_data_unit + 1); + mainPtr->rowgroups_avail = (JDIMENSION) (cinfo->min_codec_data_unit + 2); + mainPtr->context_state = CTX_POSTPONED_ROW; + } +} + + +/* + * Process some data. + * Final pass of two-pass quantization: just call the postprocessor. + * Source data will be the postprocessor controller's internal buffer. + */ + +#ifdef QUANT_2PASS_SUPPORTED + +METHODDEF(void) +process_data_crank_post (j_decompress_ptr cinfo, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) +{ + (*cinfo->post->post_process_data) (cinfo, (JSAMPIMAGE) NULL, + (JDIMENSION *) NULL, (JDIMENSION) 0, + output_buf, out_row_ctr, out_rows_avail); +} + +#endif /* QUANT_2PASS_SUPPORTED */ + + +/* + * Initialize main buffer controller. + */ + +GLOBAL(void) +jinit_d_main_controller (j_decompress_ptr cinfo, boolean need_full_buffer) +{ + my_main_ptr mainPtr; + int ci, rgroup, ngroups; + jpeg_component_info *compptr; + + mainPtr = (my_main_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_main_controller)); + cinfo->main = (struct jpeg_d_main_controller *) mainPtr; + mainPtr->pub.start_pass = start_pass_main; + + if (need_full_buffer) /* shouldn't happen */ + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + + /* Allocate the workspace. + * ngroups is the number of row groups we need. + */ + if (cinfo->upsample->need_context_rows) { + if (cinfo->min_codec_data_unit < 2) /* unsupported, see comments above */ + ERREXIT(cinfo, JERR_NOTIMPL); + alloc_funny_pointers(cinfo); /* Alloc space for xbuffer[] lists */ + ngroups = cinfo->min_codec_data_unit + 2; + } else { + ngroups = cinfo->min_codec_data_unit; + } + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + rgroup = (compptr->v_samp_factor * compptr->codec_data_unit) / + cinfo->min_codec_data_unit; /* height of a row group of component */ + mainPtr->buffer[ci] = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + compptr->width_in_data_units * compptr->codec_data_unit, + (JDIMENSION) (rgroup * ngroups)); + } +} diff --git a/Utilities/ITK/Utilities/itkjpeg/jdmarker.c b/Utilities/ITK/Utilities/itkjpeg/jdmarker.c new file mode 100644 index 0000000000000000000000000000000000000000..e280621b295bc88d09d159c4ec75a665073c2920 --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jdmarker.c @@ -0,0 +1,1370 @@ +/* + * jdmarker.c + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to decode JPEG datastream markers. + * Most of the complexity arises from our desire to support input + * suspension: if not all of the data for a marker is available, + * we must exit back to the application. On resumption, we reprocess + * the marker. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +typedef enum { /* JPEG marker codes */ + M_SOF0 = 0xc0, + M_SOF1 = 0xc1, + M_SOF2 = 0xc2, + M_SOF3 = 0xc3, + + M_SOF5 = 0xc5, + M_SOF6 = 0xc6, + M_SOF7 = 0xc7, + + M_JPG = 0xc8, + M_SOF9 = 0xc9, + M_SOF10 = 0xca, + M_SOF11 = 0xcb, + + M_SOF13 = 0xcd, + M_SOF14 = 0xce, + M_SOF15 = 0xcf, + + M_DHT = 0xc4, + + M_DAC = 0xcc, + + M_RST0 = 0xd0, + M_RST1 = 0xd1, + M_RST2 = 0xd2, + M_RST3 = 0xd3, + M_RST4 = 0xd4, + M_RST5 = 0xd5, + M_RST6 = 0xd6, + M_RST7 = 0xd7, + + M_SOI = 0xd8, + M_EOI = 0xd9, + M_SOS = 0xda, + M_DQT = 0xdb, + M_DNL = 0xdc, + M_DRI = 0xdd, + M_DHP = 0xde, + M_EXP = 0xdf, + + M_APP0 = 0xe0, + M_APP1 = 0xe1, + M_APP2 = 0xe2, + M_APP3 = 0xe3, + M_APP4 = 0xe4, + M_APP5 = 0xe5, + M_APP6 = 0xe6, + M_APP7 = 0xe7, + M_APP8 = 0xe8, + M_APP9 = 0xe9, + M_APP10 = 0xea, + M_APP11 = 0xeb, + M_APP12 = 0xec, + M_APP13 = 0xed, + M_APP14 = 0xee, + M_APP15 = 0xef, + + M_JPG0 = 0xf0, + M_JPG13 = 0xfd, + M_COM = 0xfe, + + M_TEM = 0x01, + + M_ERROR = 0x100 +} JPEG_MARKER; + + +/* Private state */ + +typedef struct { + struct jpeg_marker_reader pub; /* public fields */ + + /* Application-overridable marker processing methods */ + jpeg_marker_parser_method process_COM; + jpeg_marker_parser_method process_APPn[16]; + + /* Limit on marker data length to save for each marker type */ + unsigned int length_limit_COM; + unsigned int length_limit_APPn[16]; + + /* Status of COM/APPn marker saving */ + jpeg_saved_marker_ptr cur_marker; /* NULL if not processing a marker */ + unsigned int bytes_read; /* data bytes read so far in marker */ + /* Note: cur_marker is not linked into marker_list until it's all read. */ +} my_marker_reader; + +typedef my_marker_reader * my_marker_ptr; + + +/* + * Macros for fetching data from the data source module. + * + * At all times, cinfo->src->next_input_byte and ->bytes_in_buffer reflect + * the current restart point; we update them only when we have reached a + * suitable place to restart if a suspension occurs. + */ + +/* Declare and initialize local copies of input pointer/count */ +#define INPUT_VARS(cinfo) \ + struct jpeg_source_mgr * datasrc = (cinfo)->src; \ + const JOCTET * next_input_byte = datasrc->next_input_byte; \ + size_t bytes_in_buffer = datasrc->bytes_in_buffer + +/* Unload the local copies --- do this only at a restart boundary */ +#define INPUT_SYNC(cinfo) \ + ( datasrc->next_input_byte = next_input_byte, \ + datasrc->bytes_in_buffer = bytes_in_buffer ) + +/* Reload the local copies --- used only in MAKE_BYTE_AVAIL */ +#define INPUT_RELOAD(cinfo) \ + ( next_input_byte = datasrc->next_input_byte, \ + bytes_in_buffer = datasrc->bytes_in_buffer ) + +/* Internal macro for INPUT_BYTE and INPUT_2BYTES: make a byte available. + * Note we do *not* do INPUT_SYNC before calling fill_input_buffer, + * but we must reload the local copies after a successful fill. + */ +#define MAKE_BYTE_AVAIL(cinfo,action) \ + if (bytes_in_buffer == 0) { \ + if (! (*datasrc->fill_input_buffer) (cinfo)) \ + { action; } \ + INPUT_RELOAD(cinfo); \ + } + +/* Read a byte into variable V. + * If must suspend, take the specified action (typically "return FALSE"). + */ +#define INPUT_BYTE(cinfo,V,action) \ + MAKESTMT( MAKE_BYTE_AVAIL(cinfo,action); \ + bytes_in_buffer--; \ + V = GETJOCTET(*next_input_byte++); ) + +/* As above, but read two bytes interpreted as an unsigned 16-bit integer. + * V should be declared unsigned int or perhaps INT32. + */ +#define INPUT_2BYTES(cinfo,V,action) \ + MAKESTMT( MAKE_BYTE_AVAIL(cinfo,action); \ + bytes_in_buffer--; \ + V = ((unsigned int) GETJOCTET(*next_input_byte++)) << 8; \ + MAKE_BYTE_AVAIL(cinfo,action); \ + bytes_in_buffer--; \ + V += GETJOCTET(*next_input_byte++); ) + + +/* + * Routines to process JPEG markers. + * + * Entry condition: JPEG marker itself has been read and its code saved + * in cinfo->unread_marker; input restart point is just after the marker. + * + * Exit: if return TRUE, have read and processed any parameters, and have + * updated the restart point to point after the parameters. + * If return FALSE, was forced to suspend before reaching end of + * marker parameters; restart point has not been moved. Same routine + * will be called again after application supplies more input data. + * + * This approach to suspension assumes that all of a marker's parameters + * can fit into a single input bufferload. This should hold for "normal" + * markers. Some COM/APPn markers might have large parameter segments + * that might not fit. If we are simply dropping such a marker, we use + * skip_input_data to get past it, and thereby put the problem on the + * source manager's shoulders. If we are saving the marker's contents + * into memory, we use a slightly different convention: when forced to + * suspend, the marker processor updates the restart point to the end of + * what it's consumed (ie, the end of the buffer) before returning FALSE. + * On resumption, cinfo->unread_marker still contains the marker code, + * but the data source will point to the next chunk of marker data. + * The marker processor must retain internal state to deal with this. + * + * Note that we don't bother to avoid duplicate trace messages if a + * suspension occurs within marker parameters. Other side effects + * require more care. + */ + + +LOCAL(boolean) +get_soi (j_decompress_ptr cinfo) +/* Process an SOI marker */ +{ + int i; + + TRACEMS(cinfo, 1, JTRC_SOI); + + if (cinfo->marker->saw_SOI) + ERREXIT(cinfo, JERR_SOI_DUPLICATE); + + /* Reset all parameters that are defined to be reset by SOI */ + + for (i = 0; i < NUM_ARITH_TBLS; i++) { + cinfo->arith_dc_L[i] = 0; + cinfo->arith_dc_U[i] = 1; + cinfo->arith_ac_K[i] = 5; + } + cinfo->restart_interval = 0; + + /* Set initial assumptions for colorspace etc */ + + cinfo->jpeg_color_space = JCS_UNKNOWN; + cinfo->CCIR601_sampling = FALSE; /* Assume non-CCIR sampling??? */ + + cinfo->saw_JFIF_marker = FALSE; + cinfo->JFIF_major_version = 1; /* set default JFIF APP0 values */ + cinfo->JFIF_minor_version = 1; + cinfo->density_unit = 0; + cinfo->X_density = 1; + cinfo->Y_density = 1; + cinfo->saw_Adobe_marker = FALSE; + cinfo->Adobe_transform = 0; + + cinfo->marker->saw_SOI = TRUE; + + return TRUE; +} + + +LOCAL(boolean) +get_sof (j_decompress_ptr cinfo, J_CODEC_PROCESS process, boolean is_arith, + int data_unit) +/* Process a SOFn marker */ +{ + INT32 length; + int c, ci; + jpeg_component_info * compptr; + INPUT_VARS(cinfo); + + cinfo->data_unit = data_unit; + cinfo->process = process; + cinfo->arith_code = is_arith; + + INPUT_2BYTES(cinfo, length, return FALSE); + + INPUT_BYTE(cinfo, cinfo->data_precision, return FALSE); + INPUT_2BYTES(cinfo, cinfo->image_height, return FALSE); + INPUT_2BYTES(cinfo, cinfo->image_width, return FALSE); + INPUT_BYTE(cinfo, cinfo->num_components, return FALSE); + + length -= 8; + + TRACEMS4(cinfo, 1, JTRC_SOF, cinfo->unread_marker, + (int) cinfo->image_width, (int) cinfo->image_height, + cinfo->num_components); + + if (cinfo->marker->saw_SOF) + ERREXIT(cinfo, JERR_SOF_DUPLICATE); + + /* We don't support files in which the image height is initially specified */ + /* as 0 and is later redefined by DNL. As long as we have to check that, */ + /* might as well have a general sanity check. */ + if (cinfo->image_height <= 0 || cinfo->image_width <= 0 + || cinfo->num_components <= 0) + ERREXIT(cinfo, JERR_EMPTY_IMAGE); + + if (length != (cinfo->num_components * 3)) + ERREXIT(cinfo, JERR_BAD_LENGTH); + + if (cinfo->comp_info == NULL) /* do only once, even if suspend */ + cinfo->comp_info = (jpeg_component_info *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + cinfo->num_components * SIZEOF(jpeg_component_info)); + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + compptr->component_index = ci; + INPUT_BYTE(cinfo, compptr->component_id, return FALSE); + INPUT_BYTE(cinfo, c, return FALSE); + compptr->h_samp_factor = (c >> 4) & 15; + compptr->v_samp_factor = (c ) & 15; + INPUT_BYTE(cinfo, compptr->quant_tbl_no, return FALSE); + + TRACEMS4(cinfo, 1, JTRC_SOF_COMPONENT, + compptr->component_id, compptr->h_samp_factor, + compptr->v_samp_factor, compptr->quant_tbl_no); + } + + cinfo->marker->saw_SOF = TRUE; + + INPUT_SYNC(cinfo); + return TRUE; +} + + +LOCAL(boolean) +get_sos (j_decompress_ptr cinfo) +/* Process a SOS marker */ +{ + INT32 length; + int i, ci, n, c, cc; + jpeg_component_info * compptr; + INPUT_VARS(cinfo); + + if (! cinfo->marker->saw_SOF) + ERREXIT(cinfo, JERR_SOS_NO_SOF); + + INPUT_2BYTES(cinfo, length, return FALSE); + + INPUT_BYTE(cinfo, n, return FALSE); /* Number of components */ + + TRACEMS1(cinfo, 1, JTRC_SOS, n); + + if (length != (n * 2 + 6) || n < 1 || n > MAX_COMPS_IN_SCAN) + ERREXIT(cinfo, JERR_BAD_LENGTH); + + cinfo->comps_in_scan = n; + + /* Collect the component-spec parameters */ + + for (i = 0; i < n; i++) { + INPUT_BYTE(cinfo, cc, return FALSE); + INPUT_BYTE(cinfo, c, return FALSE); + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + if (cc == compptr->component_id) + goto id_found; + } + + ERREXIT1(cinfo, JERR_BAD_COMPONENT_ID, cc); + + id_found: + + cinfo->cur_comp_info[i] = compptr; + compptr->dc_tbl_no = (c >> 4) & 15; + compptr->ac_tbl_no = (c ) & 15; + + TRACEMS3(cinfo, 1, JTRC_SOS_COMPONENT, cc, + compptr->dc_tbl_no, compptr->ac_tbl_no); + } + + /* Collect the additional scan parameters Ss, Se, Ah/Al. */ + INPUT_BYTE(cinfo, c, return FALSE); + cinfo->Ss = c; + INPUT_BYTE(cinfo, c, return FALSE); + cinfo->Se = c; + INPUT_BYTE(cinfo, c, return FALSE); + cinfo->Ah = (c >> 4) & 15; + cinfo->Al = (c ) & 15; + + TRACEMS4(cinfo, 1, JTRC_SOS_PARAMS, cinfo->Ss, cinfo->Se, + cinfo->Ah, cinfo->Al); + + /* Prepare to scan data & restart markers */ + cinfo->marker->next_restart_num = 0; + + /* Count another SOS marker */ + cinfo->input_scan_number++; + + INPUT_SYNC(cinfo); + return TRUE; +} + + +#ifdef D_ARITH_CODING_SUPPORTED + +LOCAL(boolean) +get_dac (j_decompress_ptr cinfo) +/* Process a DAC marker */ +{ + INT32 length; + int index, val; + INPUT_VARS(cinfo); + + INPUT_2BYTES(cinfo, length, return FALSE); + length -= 2; + + while (length > 0) { + INPUT_BYTE(cinfo, index, return FALSE); + INPUT_BYTE(cinfo, val, return FALSE); + + length -= 2; + + TRACEMS2(cinfo, 1, JTRC_DAC, index, val); + + if (index < 0 || index >= (2*NUM_ARITH_TBLS)) + ERREXIT1(cinfo, JERR_DAC_INDEX, index); + + if (index >= NUM_ARITH_TBLS) { /* define AC table */ + cinfo->arith_ac_K[index-NUM_ARITH_TBLS] = (UINT8) val; + } else { /* define DC table */ + cinfo->arith_dc_L[index] = (UINT8) (val & 0x0F); + cinfo->arith_dc_U[index] = (UINT8) (val >> 4); + if (cinfo->arith_dc_L[index] > cinfo->arith_dc_U[index]) + ERREXIT1(cinfo, JERR_DAC_VALUE, val); + } + } + + if (length != 0) + ERREXIT(cinfo, JERR_BAD_LENGTH); + + INPUT_SYNC(cinfo); + return TRUE; +} + +#else /* ! D_ARITH_CODING_SUPPORTED */ + +#define get_dac(cinfo) skip_variable(cinfo) + +#endif /* D_ARITH_CODING_SUPPORTED */ + + +LOCAL(boolean) +get_dht (j_decompress_ptr cinfo) +/* Process a DHT marker */ +{ + INT32 length; + UINT8 bits[17]; + UINT8 huffval[256]; + int i, index, count; + JHUFF_TBL **htblptr; + INPUT_VARS(cinfo); + + INPUT_2BYTES(cinfo, length, return FALSE); + length -= 2; + + while (length > 16) { + INPUT_BYTE(cinfo, index, return FALSE); + + TRACEMS1(cinfo, 1, JTRC_DHT, index); + + bits[0] = 0; + count = 0; + for (i = 1; i <= 16; i++) { + INPUT_BYTE(cinfo, bits[i], return FALSE); + count += bits[i]; + } + + length -= 1 + 16; + + TRACEMS8(cinfo, 2, JTRC_HUFFBITS, + bits[1], bits[2], bits[3], bits[4], + bits[5], bits[6], bits[7], bits[8]); + TRACEMS8(cinfo, 2, JTRC_HUFFBITS, + bits[9], bits[10], bits[11], bits[12], + bits[13], bits[14], bits[15], bits[16]); + + /* Here we just do minimal validation of the counts to avoid walking + * off the end of our table space. jdhuff.c will check more carefully. + */ + if (count > 256 || ((INT32) count) > length) + ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); + + for (i = 0; i < count; i++) + INPUT_BYTE(cinfo, huffval[i], return FALSE); + + length -= count; + + if (index & 0x10) { /* AC table definition */ + index -= 0x10; + htblptr = &cinfo->ac_huff_tbl_ptrs[index]; + } else { /* DC table definition */ + htblptr = &cinfo->dc_huff_tbl_ptrs[index]; + } + + if (index < 0 || index >= NUM_HUFF_TBLS) + ERREXIT1(cinfo, JERR_DHT_INDEX, index); + + if (*htblptr == NULL) + *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo); + + MEMCOPY((*htblptr)->bits, bits, SIZEOF((*htblptr)->bits)); + MEMCOPY((*htblptr)->huffval, huffval, SIZEOF((*htblptr)->huffval)); + } + + if (length != 0) + ERREXIT(cinfo, JERR_BAD_LENGTH); + + INPUT_SYNC(cinfo); + return TRUE; +} + + +LOCAL(boolean) +get_dqt (j_decompress_ptr cinfo) +/* Process a DQT marker */ +{ + INT32 length; + int n, i, prec; + unsigned int tmp; + JQUANT_TBL *quant_ptr; + INPUT_VARS(cinfo); + + INPUT_2BYTES(cinfo, length, return FALSE); + length -= 2; + + while (length > 0) { + INPUT_BYTE(cinfo, n, return FALSE); + prec = n >> 4; + n &= 0x0F; + + TRACEMS2(cinfo, 1, JTRC_DQT, n, prec); + + if (n >= NUM_QUANT_TBLS) + ERREXIT1(cinfo, JERR_DQT_INDEX, n); + + if (cinfo->quant_tbl_ptrs[n] == NULL) + cinfo->quant_tbl_ptrs[n] = jpeg_alloc_quant_table((j_common_ptr) cinfo); + quant_ptr = cinfo->quant_tbl_ptrs[n]; + + for (i = 0; i < DCTSIZE2; i++) { + if (prec) + INPUT_2BYTES(cinfo, tmp, return FALSE); + else + INPUT_BYTE(cinfo, tmp, return FALSE); + /* We convert the zigzag-order table to natural array order. */ + quant_ptr->quantval[jpeg_natural_order[i]] = (UINT16) tmp; + } + + if (cinfo->err->trace_level >= 2) { + for (i = 0; i < DCTSIZE2; i += 8) { + TRACEMS8(cinfo, 2, JTRC_QUANTVALS, + quant_ptr->quantval[i], quant_ptr->quantval[i+1], + quant_ptr->quantval[i+2], quant_ptr->quantval[i+3], + quant_ptr->quantval[i+4], quant_ptr->quantval[i+5], + quant_ptr->quantval[i+6], quant_ptr->quantval[i+7]); + } + } + + length -= DCTSIZE2+1; + if (prec) length -= DCTSIZE2; + } + + if (length != 0) + ERREXIT(cinfo, JERR_BAD_LENGTH); + + INPUT_SYNC(cinfo); + return TRUE; +} + + +LOCAL(boolean) +get_dri (j_decompress_ptr cinfo) +/* Process a DRI marker */ +{ + INT32 length; + unsigned int tmp; + INPUT_VARS(cinfo); + + INPUT_2BYTES(cinfo, length, return FALSE); + + if (length != 4) + ERREXIT(cinfo, JERR_BAD_LENGTH); + + INPUT_2BYTES(cinfo, tmp, return FALSE); + + TRACEMS1(cinfo, 1, JTRC_DRI, tmp); + + cinfo->restart_interval = tmp; + + INPUT_SYNC(cinfo); + return TRUE; +} + + +/* + * Routines for processing APPn and COM markers. + * These are either saved in memory or discarded, per application request. + * APP0 and APP14 are specially checked to see if they are + * JFIF and Adobe markers, respectively. + */ + +#define APP0_DATA_LEN 14 /* Length of interesting data in APP0 */ +#define APP14_DATA_LEN 12 /* Length of interesting data in APP14 */ +#define APPN_DATA_LEN 14 /* Must be the largest of the above!! */ + + +LOCAL(void) +examine_app0 (j_decompress_ptr cinfo, JOCTET FAR * data, + unsigned int datalen, INT32 remaining) +/* Examine first few bytes from an APP0. + * Take appropriate action if it is a JFIF marker. + * datalen is # of bytes at data[], remaining is length of rest of marker data. + */ +{ + INT32 totallen = (INT32) datalen + remaining; + + if (datalen >= APP0_DATA_LEN && + GETJOCTET(data[0]) == 0x4A && + GETJOCTET(data[1]) == 0x46 && + GETJOCTET(data[2]) == 0x49 && + GETJOCTET(data[3]) == 0x46 && + GETJOCTET(data[4]) == 0) { + /* Found JFIF APP0 marker: save info */ + cinfo->saw_JFIF_marker = TRUE; + cinfo->JFIF_major_version = GETJOCTET(data[5]); + cinfo->JFIF_minor_version = GETJOCTET(data[6]); + cinfo->density_unit = GETJOCTET(data[7]); + cinfo->X_density = (GETJOCTET(data[8]) << 8) + GETJOCTET(data[9]); + cinfo->Y_density = (GETJOCTET(data[10]) << 8) + GETJOCTET(data[11]); + /* Check version. + * Major version must be 1, anything else signals an incompatible change. + * (We used to treat this as an error, but now it's a nonfatal warning, + * because some bozo at Hijaak couldn't read the spec.) + * Minor version should be 0..2, but process anyway if newer. + */ + if (cinfo->JFIF_major_version != 1) + WARNMS2(cinfo, JWRN_JFIF_MAJOR, + cinfo->JFIF_major_version, cinfo->JFIF_minor_version); + /* Generate trace messages */ + TRACEMS5(cinfo, 1, JTRC_JFIF, + cinfo->JFIF_major_version, cinfo->JFIF_minor_version, + cinfo->X_density, cinfo->Y_density, cinfo->density_unit); + /* Validate thumbnail dimensions and issue appropriate messages */ + if (GETJOCTET(data[12]) | GETJOCTET(data[13])) + TRACEMS2(cinfo, 1, JTRC_JFIF_THUMBNAIL, + GETJOCTET(data[12]), GETJOCTET(data[13])); + totallen -= APP0_DATA_LEN; + if (totallen != + ((INT32)GETJOCTET(data[12]) * (INT32)GETJOCTET(data[13]) * (INT32) 3)) + TRACEMS1(cinfo, 1, JTRC_JFIF_BADTHUMBNAILSIZE, (int) totallen); + } else if (datalen >= 6 && + GETJOCTET(data[0]) == 0x4A && + GETJOCTET(data[1]) == 0x46 && + GETJOCTET(data[2]) == 0x58 && + GETJOCTET(data[3]) == 0x58 && + GETJOCTET(data[4]) == 0) { + /* Found JFIF "JFXX" extension APP0 marker */ + /* The library doesn't actually do anything with these, + * but we try to produce a helpful trace message. + */ + switch (GETJOCTET(data[5])) { + case 0x10: + TRACEMS1(cinfo, 1, JTRC_THUMB_JPEG, (int) totallen); + break; + case 0x11: + TRACEMS1(cinfo, 1, JTRC_THUMB_PALETTE, (int) totallen); + break; + case 0x13: + TRACEMS1(cinfo, 1, JTRC_THUMB_RGB, (int) totallen); + break; + default: + TRACEMS2(cinfo, 1, JTRC_JFIF_EXTENSION, + GETJOCTET(data[5]), (int) totallen); + break; + } + } else { + /* Start of APP0 does not match "JFIF" or "JFXX", or too short */ + TRACEMS1(cinfo, 1, JTRC_APP0, (int) totallen); + } +} + + +LOCAL(void) +examine_app14 (j_decompress_ptr cinfo, JOCTET FAR * data, + unsigned int datalen, INT32 remaining) +/* Examine first few bytes from an APP14. + * Take appropriate action if it is an Adobe marker. + * datalen is # of bytes at data[], remaining is length of rest of marker data. + */ +{ + unsigned int version, flags0, flags1, transform; + + if (datalen >= APP14_DATA_LEN && + GETJOCTET(data[0]) == 0x41 && + GETJOCTET(data[1]) == 0x64 && + GETJOCTET(data[2]) == 0x6F && + GETJOCTET(data[3]) == 0x62 && + GETJOCTET(data[4]) == 0x65) { + /* Found Adobe APP14 marker */ + version = (GETJOCTET(data[5]) << 8) + GETJOCTET(data[6]); + flags0 = (GETJOCTET(data[7]) << 8) + GETJOCTET(data[8]); + flags1 = (GETJOCTET(data[9]) << 8) + GETJOCTET(data[10]); + transform = GETJOCTET(data[11]); + TRACEMS4(cinfo, 1, JTRC_ADOBE, version, flags0, flags1, transform); + cinfo->saw_Adobe_marker = TRUE; + cinfo->Adobe_transform = (UINT8) transform; + } else { + /* Start of APP14 does not match "Adobe", or too short */ + TRACEMS1(cinfo, 1, JTRC_APP14, (int) (datalen + remaining)); + } +} + + +METHODDEF(boolean) +get_interesting_appn (j_decompress_ptr cinfo) +/* Process an APP0 or APP14 marker without saving it */ +{ + INT32 length; + JOCTET b[APPN_DATA_LEN]; + unsigned int i, numtoread; + INPUT_VARS(cinfo); + + INPUT_2BYTES(cinfo, length, return FALSE); + length -= 2; + + /* get the interesting part of the marker data */ + if (length >= APPN_DATA_LEN) + numtoread = APPN_DATA_LEN; + else if (length > 0) + numtoread = (unsigned int) length; + else + numtoread = 0; + for (i = 0; i < numtoread; i++) + INPUT_BYTE(cinfo, b[i], return FALSE); + length -= numtoread; + + /* process it */ + switch (cinfo->unread_marker) { + case M_APP0: + examine_app0(cinfo, (JOCTET FAR *) b, numtoread, length); + break; + case M_APP14: + examine_app14(cinfo, (JOCTET FAR *) b, numtoread, length); + break; + default: + /* can't get here unless jpeg_save_markers chooses wrong processor */ + ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, cinfo->unread_marker); + break; + } + + /* skip any remaining data -- could be lots */ + INPUT_SYNC(cinfo); + if (length > 0) + (*cinfo->src->skip_input_data) (cinfo, (long) length); + + return TRUE; +} + + +#ifdef SAVE_MARKERS_SUPPORTED + +METHODDEF(boolean) +save_marker (j_decompress_ptr cinfo) +/* Save an APPn or COM marker into the marker list */ +{ + my_marker_ptr marker = (my_marker_ptr) cinfo->marker; + jpeg_saved_marker_ptr cur_marker = marker->cur_marker; + unsigned int bytes_read, data_length; + JOCTET FAR * data; + INT32 length = 0; + INPUT_VARS(cinfo); + + if (cur_marker == NULL) { + /* begin reading a marker */ + INPUT_2BYTES(cinfo, length, return FALSE); + length -= 2; + if (length >= 0) { /* watch out for bogus length word */ + /* figure out how much we want to save */ + unsigned int limit; + if (cinfo->unread_marker == (int) M_COM) + limit = marker->length_limit_COM; + else + limit = marker->length_limit_APPn[cinfo->unread_marker - (int) M_APP0]; + if ((unsigned int) length < limit) + limit = (unsigned int) length; + /* allocate and initialize the marker item */ + cur_marker = (jpeg_saved_marker_ptr) + (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(struct jpeg_marker_struct) + limit); + cur_marker->next = NULL; + cur_marker->marker = (UINT8) cinfo->unread_marker; + cur_marker->original_length = (unsigned int) length; + cur_marker->data_length = limit; + /* data area is just beyond the jpeg_marker_struct */ + data = cur_marker->data = (JOCTET FAR *) (cur_marker + 1); + marker->cur_marker = cur_marker; + marker->bytes_read = 0; + bytes_read = 0; + data_length = limit; + } else { + /* deal with bogus length word */ + bytes_read = data_length = 0; + data = NULL; + } + } else { + /* resume reading a marker */ + bytes_read = marker->bytes_read; + data_length = cur_marker->data_length; + data = cur_marker->data + bytes_read; + } + + while (bytes_read < data_length) { + INPUT_SYNC(cinfo); /* move the restart point to here */ + marker->bytes_read = bytes_read; + /* If there's not at least one byte in buffer, suspend */ + MAKE_BYTE_AVAIL(cinfo, return FALSE); + /* Copy bytes with reasonable rapidity */ + while (bytes_read < data_length && bytes_in_buffer > 0) { + *data++ = *next_input_byte++; + bytes_in_buffer--; + bytes_read++; + } + } + + /* Done reading what we want to read */ + if (cur_marker != NULL) { /* will be NULL if bogus length word */ + /* Add new marker to end of list */ + if (cinfo->marker_list == NULL) { + cinfo->marker_list = cur_marker; + } else { + jpeg_saved_marker_ptr prev = cinfo->marker_list; + while (prev->next != NULL) + prev = prev->next; + prev->next = cur_marker; + } + /* Reset pointer & calc remaining data length */ + data = cur_marker->data; + length = cur_marker->original_length - data_length; + } + /* Reset to initial state for next marker */ + marker->cur_marker = NULL; + + /* Process the marker if interesting; else just make a generic trace msg */ + switch (cinfo->unread_marker) { + case M_APP0: + examine_app0(cinfo, data, data_length, length); + break; + case M_APP14: + examine_app14(cinfo, data, data_length, length); + break; + default: + TRACEMS2(cinfo, 1, JTRC_MISC_MARKER, cinfo->unread_marker, + (int) (data_length + length)); + break; + } + + /* skip any remaining data -- could be lots */ + INPUT_SYNC(cinfo); /* do before skip_input_data */ + if (length > 0) + (*cinfo->src->skip_input_data) (cinfo, (long) length); + + return TRUE; +} + +#endif /* SAVE_MARKERS_SUPPORTED */ + + +METHODDEF(boolean) +skip_variable (j_decompress_ptr cinfo) +/* Skip over an unknown or uninteresting variable-length marker */ +{ + INT32 length; + INPUT_VARS(cinfo); + + INPUT_2BYTES(cinfo, length, return FALSE); + length -= 2; + + TRACEMS2(cinfo, 1, JTRC_MISC_MARKER, cinfo->unread_marker, (int) length); + + INPUT_SYNC(cinfo); /* do before skip_input_data */ + if (length > 0) + (*cinfo->src->skip_input_data) (cinfo, (long) length); + + return TRUE; +} + + +/* + * Find the next JPEG marker, save it in cinfo->unread_marker. + * Returns FALSE if had to suspend before reaching a marker; + * in that case cinfo->unread_marker is unchanged. + * + * Note that the result might not be a valid marker code, + * but it will never be 0 or FF. + */ + +LOCAL(boolean) +next_marker (j_decompress_ptr cinfo) +{ + int c; + INPUT_VARS(cinfo); + + for (;;) { + INPUT_BYTE(cinfo, c, return FALSE); + /* Skip any non-FF bytes. + * This may look a bit inefficient, but it will not occur in a valid file. + * We sync after each discarded byte so that a suspending data source + * can discard the byte from its buffer. + */ + while (c != 0xFF) { + cinfo->marker->discarded_bytes++; + INPUT_SYNC(cinfo); + INPUT_BYTE(cinfo, c, return FALSE); + } + /* This loop swallows any duplicate FF bytes. Extra FFs are legal as + * pad bytes, so don't count them in discarded_bytes. We assume there + * will not be so many consecutive FF bytes as to overflow a suspending + * data source's input buffer. + */ + do { + INPUT_BYTE(cinfo, c, return FALSE); + } while (c == 0xFF); + if (c != 0) + break; /* found a valid marker, exit loop */ + /* Reach here if we found a stuffed-zero data sequence (FF/00). + * Discard it and loop back to try again. + */ + cinfo->marker->discarded_bytes += 2; + INPUT_SYNC(cinfo); + } + + if (cinfo->marker->discarded_bytes != 0) { + WARNMS2(cinfo, JWRN_EXTRANEOUS_DATA, cinfo->marker->discarded_bytes, c); + cinfo->marker->discarded_bytes = 0; + } + + cinfo->unread_marker = c; + + INPUT_SYNC(cinfo); + return TRUE; +} + + +LOCAL(boolean) +first_marker (j_decompress_ptr cinfo) +/* Like next_marker, but used to obtain the initial SOI marker. */ +/* For this marker, we do not allow preceding garbage or fill; otherwise, + * we might well scan an entire input file before realizing it ain't JPEG. + * If an application wants to process non-JFIF files, it must seek to the + * SOI before calling the JPEG library. + */ +{ + int c, c2; + INPUT_VARS(cinfo); + + INPUT_BYTE(cinfo, c, return FALSE); + INPUT_BYTE(cinfo, c2, return FALSE); + if (c != 0xFF || c2 != (int) M_SOI) + ERREXIT2(cinfo, JERR_NO_SOI, c, c2); + + cinfo->unread_marker = c2; + + INPUT_SYNC(cinfo); + return TRUE; +} + + +/* + * Read markers until SOS or EOI. + * + * Returns same codes as are defined for jpeg_consume_input: + * JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI. + */ + +METHODDEF(int) +read_markers (j_decompress_ptr cinfo) +{ + /* Outer loop repeats once for each marker. */ + for (;;) { + /* Collect the marker proper, unless we already did. */ + /* NB: first_marker() enforces the requirement that SOI appear first. */ + if (cinfo->unread_marker == 0) { + if (! cinfo->marker->saw_SOI) { + if (! first_marker(cinfo)) + return JPEG_SUSPENDED; + } else { + if (! next_marker(cinfo)) + return JPEG_SUSPENDED; + } + } + /* At this point cinfo->unread_marker contains the marker code and the + * input point is just past the marker proper, but before any parameters. + * A suspension will cause us to return with this state still true. + */ + switch (cinfo->unread_marker) { + case M_SOI: + if (! get_soi(cinfo)) + return JPEG_SUSPENDED; + break; + + case M_SOF0: /* Baseline */ + case M_SOF1: /* Extended sequential, Huffman */ + if (! get_sof(cinfo, JPROC_SEQUENTIAL, FALSE, DCTSIZE)) + return JPEG_SUSPENDED; + break; + + case M_SOF2: /* Progressive, Huffman */ + if (! get_sof(cinfo, JPROC_PROGRESSIVE, FALSE, DCTSIZE)) + return JPEG_SUSPENDED; + break; + + case M_SOF3: /* Lossless, Huffman */ + if (! get_sof(cinfo, JPROC_LOSSLESS, FALSE, 1)) + return JPEG_SUSPENDED; + break; + + case M_SOF9: /* Extended sequential, arithmetic */ + if (! get_sof(cinfo, JPROC_SEQUENTIAL, TRUE, DCTSIZE)) + return JPEG_SUSPENDED; + break; + + case M_SOF10: /* Progressive, arithmetic */ + if (! get_sof(cinfo, JPROC_PROGRESSIVE, TRUE, DCTSIZE)) + return JPEG_SUSPENDED; + break; + + case M_SOF11: /* Lossless, arithmetic */ + if (! get_sof(cinfo, JPROC_LOSSLESS, TRUE, 1)) + return JPEG_SUSPENDED; + break; + + /* Currently unsupported SOFn types */ + case M_SOF5: /* Differential sequential, Huffman */ + case M_SOF6: /* Differential progressive, Huffman */ + case M_SOF7: /* Differential lossless, Huffman */ + case M_JPG: /* Reserved for JPEG extensions */ + case M_SOF13: /* Differential sequential, arithmetic */ + case M_SOF14: /* Differential progressive, arithmetic */ + case M_SOF15: /* Differential lossless, arithmetic */ + ERREXIT1(cinfo, JERR_SOF_UNSUPPORTED, cinfo->unread_marker); + break; + + case M_SOS: + if (! get_sos(cinfo)) + return JPEG_SUSPENDED; + cinfo->unread_marker = 0; /* processed the marker */ + return JPEG_REACHED_SOS; + + case M_EOI: + TRACEMS(cinfo, 1, JTRC_EOI); + cinfo->unread_marker = 0; /* processed the marker */ + return JPEG_REACHED_EOI; + + case M_DAC: + if (! get_dac(cinfo)) + return JPEG_SUSPENDED; + break; + + case M_DHT: + if (! get_dht(cinfo)) + return JPEG_SUSPENDED; + break; + + case M_DQT: + if (! get_dqt(cinfo)) + return JPEG_SUSPENDED; + break; + + case M_DRI: + if (! get_dri(cinfo)) + return JPEG_SUSPENDED; + break; + + case M_APP0: + case M_APP1: + case M_APP2: + case M_APP3: + case M_APP4: + case M_APP5: + case M_APP6: + case M_APP7: + case M_APP8: + case M_APP9: + case M_APP10: + case M_APP11: + case M_APP12: + case M_APP13: + case M_APP14: + case M_APP15: + if (! (*((my_marker_ptr) cinfo->marker)->process_APPn[ + cinfo->unread_marker - (int) M_APP0]) (cinfo)) + return JPEG_SUSPENDED; + break; + + case M_COM: + if (! (*((my_marker_ptr) cinfo->marker)->process_COM) (cinfo)) + return JPEG_SUSPENDED; + break; + + case M_RST0: /* these are all parameterless */ + case M_RST1: + case M_RST2: + case M_RST3: + case M_RST4: + case M_RST5: + case M_RST6: + case M_RST7: + case M_TEM: + TRACEMS1(cinfo, 1, JTRC_PARMLESS_MARKER, cinfo->unread_marker); + break; + + case M_DNL: /* Ignore DNL ... perhaps the wrong thing */ + if (! skip_variable(cinfo)) + return JPEG_SUSPENDED; + break; + + default: /* must be DHP, EXP, JPGn, or RESn */ + /* For now, we treat the reserved markers as fatal errors since they are + * likely to be used to signal incompatible JPEG Part 3 extensions. + * Once the JPEG 3 version-number marker is well defined, this code + * ought to change! + */ + ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, cinfo->unread_marker); + break; + } + /* Successfully processed marker, so reset state variable */ + cinfo->unread_marker = 0; + } /* end loop */ +} + + +/* + * Read a restart marker, which is expected to appear next in the datastream; + * if the marker is not there, take appropriate recovery action. + * Returns FALSE if suspension is required. + * + * This is called by the entropy decoder after it has read an appropriate + * number of MCUs. cinfo->unread_marker may be nonzero if the entropy decoder + * has already read a marker from the data source. Under normal conditions + * cinfo->unread_marker will be reset to 0 before returning; if not reset, + * it holds a marker which the decoder will be unable to read past. + */ + +METHODDEF(boolean) +read_restart_marker (j_decompress_ptr cinfo) +{ + /* Obtain a marker unless we already did. */ + /* Note that next_marker will complain if it skips any data. */ + if (cinfo->unread_marker == 0) { + if (! next_marker(cinfo)) + return FALSE; + } + + if (cinfo->unread_marker == + ((int) M_RST0 + cinfo->marker->next_restart_num)) { + /* Normal case --- swallow the marker and let entropy decoder continue */ + TRACEMS1(cinfo, 3, JTRC_RST, cinfo->marker->next_restart_num); + cinfo->unread_marker = 0; + } else { + /* Uh-oh, the restart markers have been messed up. */ + /* Let the data source manager determine how to resync. */ + if (! (*cinfo->src->resync_to_restart) (cinfo, + cinfo->marker->next_restart_num)) + return FALSE; + } + + /* Update next-restart state */ + cinfo->marker->next_restart_num = (cinfo->marker->next_restart_num + 1) & 7; + + return TRUE; +} + + +/* + * This is the default resync_to_restart method for data source managers + * to use if they don't have any better approach. Some data source managers + * may be able to back up, or may have additional knowledge about the data + * which permits a more intelligent recovery strategy; such managers would + * presumably supply their own resync method. + * + * read_restart_marker calls resync_to_restart if it finds a marker other than + * the restart marker it was expecting. (This code is *not* used unless + * a nonzero restart interval has been declared.) cinfo->unread_marker is + * the marker code actually found (might be anything, except 0 or FF). + * The desired restart marker number (0..7) is passed as a parameter. + * This routine is supposed to apply whatever error recovery strategy seems + * appropriate in order to position the input stream to the next data segment. + * Note that cinfo->unread_marker is treated as a marker appearing before + * the current data-source input point; usually it should be reset to zero + * before returning. + * Returns FALSE if suspension is required. + * + * This implementation is substantially constrained by wanting to treat the + * input as a data stream; this means we can't back up. Therefore, we have + * only the following actions to work with: + * 1. Simply discard the marker and let the entropy decoder resume at next + * byte of file. + * 2. Read forward until we find another marker, discarding intervening + * data. (In theory we could look ahead within the current bufferload, + * without having to discard data if we don't find the desired marker. + * This idea is not implemented here, in part because it makes behavior + * dependent on buffer size and chance buffer-boundary positions.) + * 3. Leave the marker unread (by failing to zero cinfo->unread_marker). + * This will cause the entropy decoder to process an empty data segment, + * inserting dummy zeroes, and then we will reprocess the marker. + * + * #2 is appropriate if we think the desired marker lies ahead, while #3 is + * appropriate if the found marker is a future restart marker (indicating + * that we have missed the desired restart marker, probably because it got + * corrupted). + * We apply #2 or #3 if the found marker is a restart marker no more than + * two counts behind or ahead of the expected one. We also apply #2 if the + * found marker is not a legal JPEG marker code (it's certainly bogus data). + * If the found marker is a restart marker more than 2 counts away, we do #1 + * (too much risk that the marker is erroneous; with luck we will be able to + * resync at some future point). + * For any valid non-restart JPEG marker, we apply #3. This keeps us from + * overrunning the end of a scan. An implementation limited to single-scan + * files might find it better to apply #2 for markers other than EOI, since + * any other marker would have to be bogus data in that case. + */ + +GLOBAL(boolean) +jpeg_resync_to_restart (j_decompress_ptr cinfo, int desired) +{ + int marker = cinfo->unread_marker; + int action = 1; + + /* Always put up a warning. */ + WARNMS2(cinfo, JWRN_MUST_RESYNC, marker, desired); + + /* Outer loop handles repeated decision after scanning forward. */ + for (;;) { + if (marker < (int) M_SOF0) + action = 2; /* invalid marker */ + else if (marker < (int) M_RST0 || marker > (int) M_RST7) + action = 3; /* valid non-restart marker */ + else { + if (marker == ((int) M_RST0 + ((desired+1) & 7)) || + marker == ((int) M_RST0 + ((desired+2) & 7))) + action = 3; /* one of the next two expected restarts */ + else if (marker == ((int) M_RST0 + ((desired-1) & 7)) || + marker == ((int) M_RST0 + ((desired-2) & 7))) + action = 2; /* a prior restart, so advance */ + else + action = 1; /* desired restart or too far away */ + } + TRACEMS2(cinfo, 4, JTRC_RECOVERY_ACTION, marker, action); + switch (action) { + case 1: + /* Discard marker and let entropy decoder resume processing. */ + cinfo->unread_marker = 0; + return TRUE; + case 2: + /* Scan to the next marker, and repeat the decision loop. */ + if (! next_marker(cinfo)) + return FALSE; + marker = cinfo->unread_marker; + break; + case 3: + /* Return without advancing past this marker. */ + /* Entropy decoder will be forced to process an empty segment. */ + return TRUE; + } + } /* end loop */ +} + + +/* + * Reset marker processing state to begin a fresh datastream. + */ + +METHODDEF(void) +reset_marker_reader (j_decompress_ptr cinfo) +{ + my_marker_ptr marker = (my_marker_ptr) cinfo->marker; + + cinfo->comp_info = NULL; /* until allocated by get_sof */ + cinfo->input_scan_number = 0; /* no SOS seen yet */ + cinfo->unread_marker = 0; /* no pending marker */ + marker->pub.saw_SOI = FALSE; /* set internal state too */ + marker->pub.saw_SOF = FALSE; + marker->pub.discarded_bytes = 0; + marker->cur_marker = NULL; +} + + +/* + * Initialize the marker reader module. + * This is called only once, when the decompression object is created. + */ + +GLOBAL(void) +jinit_marker_reader (j_decompress_ptr cinfo) +{ + my_marker_ptr marker; + int i; + + /* Create subobject in permanent pool */ + marker = (my_marker_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + SIZEOF(my_marker_reader)); + cinfo->marker = (struct jpeg_marker_reader *) marker; + /* Initialize public method pointers */ + marker->pub.reset_marker_reader = reset_marker_reader; + marker->pub.read_markers = read_markers; + marker->pub.read_restart_marker = read_restart_marker; + /* Initialize COM/APPn processing. + * By default, we examine and then discard APP0 and APP14, + * but simply discard COM and all other APPn. + */ + marker->process_COM = skip_variable; + marker->length_limit_COM = 0; + for (i = 0; i < 16; i++) { + marker->process_APPn[i] = skip_variable; + marker->length_limit_APPn[i] = 0; + } + marker->process_APPn[0] = get_interesting_appn; + marker->process_APPn[14] = get_interesting_appn; + /* Reset marker processing state */ + reset_marker_reader(cinfo); +} + + +/* + * Control saving of COM and APPn markers into marker_list. + */ + +#ifdef SAVE_MARKERS_SUPPORTED + +GLOBAL(void) +jpeg_save_markers (j_decompress_ptr cinfo, int marker_code, + unsigned int length_limit) +{ + my_marker_ptr marker = (my_marker_ptr) cinfo->marker; + long maxlength; + jpeg_marker_parser_method processor; + + /* Length limit mustn't be larger than what we can allocate + * (should only be a concern in a 16-bit environment). + */ + maxlength = cinfo->mem->max_alloc_chunk - SIZEOF(struct jpeg_marker_struct); + if (((long) length_limit) > maxlength) + length_limit = (unsigned int) maxlength; + + /* Choose processor routine to use. + * APP0/APP14 have special requirements. + */ + if (length_limit) { + processor = save_marker; + /* If saving APP0/APP14, save at least enough for our internal use. */ + if (marker_code == (int) M_APP0 && length_limit < APP0_DATA_LEN) + length_limit = APP0_DATA_LEN; + else if (marker_code == (int) M_APP14 && length_limit < APP14_DATA_LEN) + length_limit = APP14_DATA_LEN; + } else { + processor = skip_variable; + /* If discarding APP0/APP14, use our regular on-the-fly processor. */ + if (marker_code == (int) M_APP0 || marker_code == (int) M_APP14) + processor = get_interesting_appn; + } + + if (marker_code == (int) M_COM) { + marker->process_COM = processor; + marker->length_limit_COM = length_limit; + } else if (marker_code >= (int) M_APP0 && marker_code <= (int) M_APP15) { + marker->process_APPn[marker_code - (int) M_APP0] = processor; + marker->length_limit_APPn[marker_code - (int) M_APP0] = length_limit; + } else + ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, marker_code); +} + +#endif /* SAVE_MARKERS_SUPPORTED */ + + +/* + * Install a special processing method for COM or APPn markers. + */ + +GLOBAL(void) +jpeg_set_marker_processor (j_decompress_ptr cinfo, int marker_code, + jpeg_marker_parser_method routine) +{ + my_marker_ptr marker = (my_marker_ptr) cinfo->marker; + + if (marker_code == (int) M_COM) + marker->process_COM = routine; + else if (marker_code >= (int) M_APP0 && marker_code <= (int) M_APP15) + marker->process_APPn[marker_code - (int) M_APP0] = routine; + else + ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, marker_code); +} diff --git a/Utilities/ITK/Utilities/itkjpeg/jdmaster.c b/Utilities/ITK/Utilities/itkjpeg/jdmaster.c new file mode 100644 index 0000000000000000000000000000000000000000..cb06e011003c82847e666065c16d2ac738d59afa --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jdmaster.c @@ -0,0 +1,460 @@ +/* + * jdmaster.c + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains master control logic for the JPEG decompressor. + * These routines are concerned with selecting the modules to be executed + * and with determining the number of passes and the work to be done in each + * pass. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Private state */ + +typedef struct { + struct jpeg_decomp_master pub; /* public fields */ + + int pass_number; /* # of passes completed */ + + boolean using_merged_upsample; /* TRUE if using merged upsample/cconvert */ + + /* Saved references to initialized quantizer modules, + * in case we need to switch modes. + */ + struct jpeg_color_quantizer * quantizer_1pass; + struct jpeg_color_quantizer * quantizer_2pass; +} my_decomp_master; + +typedef my_decomp_master * my_master_ptr; + + +/* + * Determine whether merged upsample/color conversion should be used. + * CRUCIAL: this must match the actual capabilities of jdmerge.c! + */ + +LOCAL(boolean) +use_merged_upsample (j_decompress_ptr cinfo) +{ +#ifdef UPSAMPLE_MERGING_SUPPORTED + /* Merging is the equivalent of plain box-filter upsampling */ + if (cinfo->do_fancy_upsampling || cinfo->CCIR601_sampling) + return FALSE; + /* jdmerge.c only supports YCC=>RGB color conversion */ + if (cinfo->jpeg_color_space != JCS_YCbCr || cinfo->num_components != 3 || + cinfo->out_color_space != JCS_RGB || + cinfo->out_color_components != RGB_PIXELSIZE) + return FALSE; + /* and it only handles 2h1v or 2h2v sampling ratios */ + if (cinfo->comp_info[0].h_samp_factor != 2 || + cinfo->comp_info[1].h_samp_factor != 1 || + cinfo->comp_info[2].h_samp_factor != 1 || + cinfo->comp_info[0].v_samp_factor > 2 || + cinfo->comp_info[1].v_samp_factor != 1 || + cinfo->comp_info[2].v_samp_factor != 1) + return FALSE; + /* furthermore, it doesn't work if each component has been + processed differently */ + if (cinfo->comp_info[0].codec_data_unit != cinfo->min_codec_data_unit || + cinfo->comp_info[1].codec_data_unit != cinfo->min_codec_data_unit || + cinfo->comp_info[2].codec_data_unit != cinfo->min_codec_data_unit) + return FALSE; + /* ??? also need to test for upsample-time rescaling, when & if supported */ + return TRUE; /* by golly, it'll work... */ +#else + return FALSE; +#endif +} + + +/* + * Compute output image dimensions and related values. + * NOTE: this is exported for possible use by application. + * Hence it mustn't do anything that can't be done twice. + * Also note that it may be called before the master module is initialized! + */ + +GLOBAL(void) +jpeg_calc_output_dimensions (j_decompress_ptr cinfo) +/* Do computations that are needed before master selection phase */ +{ + /* Prevent application from calling me at wrong times */ + if (cinfo->global_state != DSTATE_READY) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + (*cinfo->codec->calc_output_dimensions) (cinfo); + + /* Report number of components in selected colorspace. */ + /* Probably this should be in the color conversion module... */ + switch (cinfo->out_color_space) { + case JCS_GRAYSCALE: + cinfo->out_color_components = 1; + break; + case JCS_RGB: +#if RGB_PIXELSIZE != 3 + cinfo->out_color_components = RGB_PIXELSIZE; + break; +#endif /* else share code with YCbCr */ + case JCS_YCbCr: + cinfo->out_color_components = 3; + break; + case JCS_CMYK: + case JCS_YCCK: + cinfo->out_color_components = 4; + break; + default: /* else must be same colorspace as in file */ + cinfo->out_color_components = cinfo->num_components; + break; + } + cinfo->output_components = (cinfo->quantize_colors ? 1 : + cinfo->out_color_components); + + /* See if upsampler will want to emit more than one row at a time */ + if (use_merged_upsample(cinfo)) + cinfo->rec_outbuf_height = cinfo->max_v_samp_factor; + else + cinfo->rec_outbuf_height = 1; +} + + +/* + * Several decompression processes need to range-limit values to the range + * 0..MAXJSAMPLE; the input value may fall somewhat outside this range + * due to noise introduced by quantization, roundoff error, etc. These + * processes are inner loops and need to be as fast as possible. On most + * machines, particularly CPUs with pipelines or instruction prefetch, + * a (subscript-check-less) C table lookup + * x = sample_range_limit[x]; + * is faster than explicit tests + * if (x < 0) x = 0; + * else if (x > MAXJSAMPLE) x = MAXJSAMPLE; + * These processes all use a common table prepared by the routine below. + * + * For most steps we can mathematically guarantee that the initial value + * of x is within MAXJSAMPLE+1 of the legal range, so a table running from + * -(MAXJSAMPLE+1) to 2*MAXJSAMPLE+1 is sufficient. But for the initial + * limiting step (just after the IDCT), a wildly out-of-range value is + * possible if the input data is corrupt. To avoid any chance of indexing + * off the end of memory and getting a bad-pointer trap, we perform the + * post-IDCT limiting thus: + * x = range_limit[x & MASK]; + * where MASK is 2 bits wider than legal sample data, ie 10 bits for 8-bit + * samples. Under normal circumstances this is more than enough range and + * a correct output will be generated; with bogus input data the mask will + * cause wraparound, and we will safely generate a bogus-but-in-range output. + * For the post-IDCT step, we want to convert the data from signed to unsigned + * representation by adding CENTERJSAMPLE at the same time that we limit it. + * So the post-IDCT limiting table ends up looking like this: + * CENTERJSAMPLE,CENTERJSAMPLE+1,...,MAXJSAMPLE, + * MAXJSAMPLE (repeat 2*(MAXJSAMPLE+1)-CENTERJSAMPLE times), + * 0 (repeat 2*(MAXJSAMPLE+1)-CENTERJSAMPLE times), + * 0,1,...,CENTERJSAMPLE-1 + * Negative inputs select values from the upper half of the table after + * masking. + * + * We can save some space by overlapping the start of the post-IDCT table + * with the simpler range limiting table. The post-IDCT table begins at + * sample_range_limit + CENTERJSAMPLE. + * + * Note that the table is allocated in near data space on PCs; it's small + * enough and used often enough to justify this. + */ + +LOCAL(void) +prepare_range_limit_table (j_decompress_ptr cinfo) +/* Allocate and fill in the sample_range_limit table */ +{ + JSAMPLE * table; + int i; + + table = (JSAMPLE *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (5 * (MAXJSAMPLE+1) + CENTERJSAMPLE) * SIZEOF(JSAMPLE)); + table += (MAXJSAMPLE+1); /* allow negative subscripts of simple table */ + cinfo->sample_range_limit = table; + /* First segment of "simple" table: limit[x] = 0 for x < 0 */ + MEMZERO(table - (MAXJSAMPLE+1), (MAXJSAMPLE+1) * SIZEOF(JSAMPLE)); + /* Main part of "simple" table: limit[x] = x */ + for (i = 0; i <= MAXJSAMPLE; i++) + table[i] = (JSAMPLE) i; + table += CENTERJSAMPLE; /* Point to where post-IDCT table starts */ + /* End of simple table, rest of first half of post-IDCT table */ + for (i = CENTERJSAMPLE; i < 2*(MAXJSAMPLE+1); i++) + table[i] = MAXJSAMPLE; + /* Second half of post-IDCT table */ + MEMZERO(table + (2 * (MAXJSAMPLE+1)), + (2 * (MAXJSAMPLE+1) - CENTERJSAMPLE) * SIZEOF(JSAMPLE)); + MEMCOPY(table + (4 * (MAXJSAMPLE+1) - CENTERJSAMPLE), + cinfo->sample_range_limit, CENTERJSAMPLE * SIZEOF(JSAMPLE)); +} + + +/* + * Master selection of decompression modules. + * This is done once at jpeg_start_decompress time. We determine + * which modules will be used and give them appropriate initialization calls. + * We also initialize the decompressor input side to begin consuming data. + * + * Since jpeg_read_header has finished, we know what is in the SOF + * and (first) SOS markers. We also have all the application parameter + * settings. + */ + +LOCAL(void) +master_selection (j_decompress_ptr cinfo) +{ + my_master_ptr master = (my_master_ptr) cinfo->master; + long samplesperrow; + JDIMENSION jd_samplesperrow; + + /* Initialize dimensions and other stuff */ + jpeg_calc_output_dimensions(cinfo); + prepare_range_limit_table(cinfo); + + /* Width of an output scanline must be representable as JDIMENSION. */ + samplesperrow = (long) cinfo->output_width * (long) cinfo->out_color_components; + jd_samplesperrow = (JDIMENSION) samplesperrow; + if ((long) jd_samplesperrow != samplesperrow) + ERREXIT(cinfo, JERR_WIDTH_OVERFLOW); + + /* Initialize my private state */ + master->pass_number = 0; + master->using_merged_upsample = use_merged_upsample(cinfo); + + /* Color quantizer selection */ + master->quantizer_1pass = NULL; + master->quantizer_2pass = NULL; + /* No mode changes if not using buffered-image mode. */ + if (! cinfo->quantize_colors || ! cinfo->buffered_image) { + cinfo->enable_1pass_quant = FALSE; + cinfo->enable_external_quant = FALSE; + cinfo->enable_2pass_quant = FALSE; + } + if (cinfo->quantize_colors) { + if (cinfo->raw_data_out) + ERREXIT(cinfo, JERR_NOTIMPL); + /* 2-pass quantizer only works in 3-component color space. */ + if (cinfo->out_color_components != 3) { + cinfo->enable_1pass_quant = TRUE; + cinfo->enable_external_quant = FALSE; + cinfo->enable_2pass_quant = FALSE; + cinfo->colormap = NULL; + } else if (cinfo->colormap != NULL) { + cinfo->enable_external_quant = TRUE; + } else if (cinfo->two_pass_quantize) { + cinfo->enable_2pass_quant = TRUE; + } else { + cinfo->enable_1pass_quant = TRUE; + } + + if (cinfo->enable_1pass_quant) { +#ifdef QUANT_1PASS_SUPPORTED + jinit_1pass_quantizer(cinfo); + master->quantizer_1pass = cinfo->cquantize; +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } + + /* We use the 2-pass code to map to external colormaps. */ + if (cinfo->enable_2pass_quant || cinfo->enable_external_quant) { +#ifdef QUANT_2PASS_SUPPORTED + jinit_2pass_quantizer(cinfo); + master->quantizer_2pass = cinfo->cquantize; +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } + /* If both quantizers are initialized, the 2-pass one is left active; + * this is necessary for starting with quantization to an external map. + */ + } + + /* Post-processing: in particular, color conversion first */ + if (! cinfo->raw_data_out) { + if (master->using_merged_upsample) { +#ifdef UPSAMPLE_MERGING_SUPPORTED + jinit_merged_upsampler(cinfo); /* does color conversion too */ +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else { + jinit_color_deconverter(cinfo); + jinit_upsampler(cinfo); + } + jinit_d_post_controller(cinfo, cinfo->enable_2pass_quant); + } + + /* Initialize principal buffer controllers. */ + if (! cinfo->raw_data_out) + jinit_d_main_controller(cinfo, FALSE /* never need full buffer here */); + + /* We can now tell the memory manager to allocate virtual arrays. */ + (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo); + + /* Initialize input side of decompressor to consume first scan. */ + (*cinfo->inputctl->start_input_pass) (cinfo); + +#ifdef D_MULTISCAN_FILES_SUPPORTED + /* If jpeg_start_decompress will read the whole file, initialize + * progress monitoring appropriately. The input step is counted + * as one pass. + */ + if (cinfo->progress != NULL && ! cinfo->buffered_image && + cinfo->inputctl->has_multiple_scans) { + int nscans; + /* Estimate number of scans to set pass_limit. */ + if (cinfo->process == JPROC_PROGRESSIVE) { + /* Arbitrarily estimate 2 interleaved DC scans + 3 AC scans/component. */ + nscans = 2 + 3 * cinfo->num_components; + } else { + /* For a nonprogressive multiscan file, estimate 1 scan per component. */ + nscans = cinfo->num_components; + } + cinfo->progress->pass_counter = 0L; + cinfo->progress->pass_limit = (long) cinfo->total_iMCU_rows * nscans; + cinfo->progress->completed_passes = 0; + cinfo->progress->total_passes = (cinfo->enable_2pass_quant ? 3 : 2); + /* Count the input pass as done */ + master->pass_number++; + } +#endif /* D_MULTISCAN_FILES_SUPPORTED */ +} + + +/* + * Per-pass setup. + * This is called at the beginning of each output pass. We determine which + * modules will be active during this pass and give them appropriate + * start_pass calls. We also set is_dummy_pass to indicate whether this + * is a "real" output pass or a dummy pass for color quantization. + * (In the latter case, jdapistd.c will crank the pass to completion.) + */ + +METHODDEF(void) +prepare_for_output_pass (j_decompress_ptr cinfo) +{ + my_master_ptr master = (my_master_ptr) cinfo->master; + + if (master->pub.is_dummy_pass) { +#ifdef QUANT_2PASS_SUPPORTED + /* Final pass of 2-pass quantization */ + master->pub.is_dummy_pass = FALSE; + (*cinfo->cquantize->start_pass) (cinfo, FALSE); + (*cinfo->post->start_pass) (cinfo, JBUF_CRANK_DEST); + (*cinfo->main->start_pass) (cinfo, JBUF_CRANK_DEST); +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif /* QUANT_2PASS_SUPPORTED */ + } else { + if (cinfo->quantize_colors && cinfo->colormap == NULL) { + /* Select new quantization method */ + if (cinfo->two_pass_quantize && cinfo->enable_2pass_quant) { + cinfo->cquantize = master->quantizer_2pass; + master->pub.is_dummy_pass = TRUE; + } else if (cinfo->enable_1pass_quant) { + cinfo->cquantize = master->quantizer_1pass; + } else { + ERREXIT(cinfo, JERR_MODE_CHANGE); + } + } + (*cinfo->codec->start_output_pass) (cinfo); + if (! cinfo->raw_data_out) { + if (! master->using_merged_upsample) + (*cinfo->cconvert->start_pass) (cinfo); + (*cinfo->upsample->start_pass) (cinfo); + if (cinfo->quantize_colors) + (*cinfo->cquantize->start_pass) (cinfo, master->pub.is_dummy_pass); + (*cinfo->post->start_pass) (cinfo, + (master->pub.is_dummy_pass ? JBUF_SAVE_AND_PASS : JBUF_PASS_THRU)); + (*cinfo->main->start_pass) (cinfo, JBUF_PASS_THRU); + } + } + + /* Set up progress monitor's pass info if present */ + if (cinfo->progress != NULL) { + cinfo->progress->completed_passes = master->pass_number; + cinfo->progress->total_passes = master->pass_number + + (master->pub.is_dummy_pass ? 2 : 1); + /* In buffered-image mode, we assume one more output pass if EOI not + * yet reached, but no more passes if EOI has been reached. + */ + if (cinfo->buffered_image && ! cinfo->inputctl->eoi_reached) { + cinfo->progress->total_passes += (cinfo->enable_2pass_quant ? 2 : 1); + } + } +} + + +/* + * Finish up at end of an output pass. + */ + +METHODDEF(void) +finish_output_pass (j_decompress_ptr cinfo) +{ + my_master_ptr master = (my_master_ptr) cinfo->master; + + if (cinfo->quantize_colors) + (*cinfo->cquantize->finish_pass) (cinfo); + master->pass_number++; +} + + +#ifdef D_MULTISCAN_FILES_SUPPORTED + +/* + * Switch to a new external colormap between output passes. + */ + +GLOBAL(void) +jpeg_new_colormap (j_decompress_ptr cinfo) +{ + my_master_ptr master = (my_master_ptr) cinfo->master; + + /* Prevent application from calling me at wrong times */ + if (cinfo->global_state != DSTATE_BUFIMAGE) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + if (cinfo->quantize_colors && cinfo->enable_external_quant && + cinfo->colormap != NULL) { + /* Select 2-pass quantizer for external colormap use */ + cinfo->cquantize = master->quantizer_2pass; + /* Notify quantizer of colormap change */ + (*cinfo->cquantize->new_color_map) (cinfo); + master->pub.is_dummy_pass = FALSE; /* just in case */ + } else + ERREXIT(cinfo, JERR_MODE_CHANGE); +} + +#endif /* D_MULTISCAN_FILES_SUPPORTED */ + + +/* + * Initialize master decompression control and select active modules. + * This is performed at the start of jpeg_start_decompress. + */ + +GLOBAL(void) +jinit_master_decompress (j_decompress_ptr cinfo) +{ + my_master_ptr master; + + master = (my_master_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_decomp_master)); + cinfo->master = (struct jpeg_decomp_master *) master; + master->pub.prepare_for_output_pass = prepare_for_output_pass; + master->pub.finish_output_pass = finish_output_pass; + + master->pub.is_dummy_pass = FALSE; + + master_selection(cinfo); +} diff --git a/Utilities/ITK/Utilities/itkjpeg/jdmerge.c b/Utilities/ITK/Utilities/itkjpeg/jdmerge.c new file mode 100644 index 0000000000000000000000000000000000000000..7a235959126955f8ac9f124e23972fbf76530ef7 --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jdmerge.c @@ -0,0 +1,402 @@ +/* + * jdmerge.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains code for merged upsampling/color conversion. + * + * This file combines functions from jdsample.c and jdcolor.c; + * read those files first to understand what's going on. + * + * When the chroma components are to be upsampled by simple replication + * (ie, box filtering), we can save some work in color conversion by + * calculating all the output pixels corresponding to a pair of chroma + * samples at one time. In the conversion equations + * R = Y + K1 * Cr + * G = Y + K2 * Cb + K3 * Cr + * B = Y + K4 * Cb + * only the Y term varies among the group of pixels corresponding to a pair + * of chroma samples, so the rest of the terms can be calculated just once. + * At typical sampling ratios, this eliminates half or three-quarters of the + * multiplications needed for color conversion. + * + * This file currently provides implementations for the following cases: + * YCbCr => RGB color conversion only. + * Sampling ratios of 2h1v or 2h2v. + * No scaling needed at upsample time. + * Corner-aligned (non-CCIR601) sampling alignment. + * Other special cases could be added, but in most applications these are + * the only common cases. (For uncommon cases we fall back on the more + * general code in jdsample.c and jdcolor.c.) + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + +#ifdef UPSAMPLE_MERGING_SUPPORTED + + +/* Private subobject */ + +typedef struct { + struct jpeg_upsampler pub; /* public fields */ + + /* Pointer to routine to do actual upsampling/conversion of one row group */ + JMETHOD(void, upmethod, (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr, + JSAMPARRAY output_buf)); + + /* Private state for YCC->RGB conversion */ + int * Cr_r_tab; /* => table for Cr to R conversion */ + int * Cb_b_tab; /* => table for Cb to B conversion */ + INT32 * Cr_g_tab; /* => table for Cr to G conversion */ + INT32 * Cb_g_tab; /* => table for Cb to G conversion */ + + /* For 2:1 vertical sampling, we produce two output rows at a time. + * We need a "spare" row buffer to hold the second output row if the + * application provides just a one-row buffer; we also use the spare + * to discard the dummy last row if the image height is odd. + */ + JSAMPROW spare_row; + boolean spare_full; /* T if spare buffer is occupied */ + + JDIMENSION out_row_width; /* samples per output row */ + JDIMENSION rows_to_go; /* counts rows remaining in image */ +} my_upsampler; + +typedef my_upsampler * my_upsample_ptr; + +#define SCALEBITS 16 /* speediest right-shift on some machines */ +#define ONE_HALF ((INT32) 1 << (SCALEBITS-1)) +#define FIX(x) ((INT32) ((x) * (1L<<SCALEBITS) + 0.5)) + + +/* + * Initialize tables for YCC->RGB colorspace conversion. + * This is taken directly from jdcolor.c; see that file for more info. + */ + +LOCAL(void) +build_ycc_rgb_table (j_decompress_ptr cinfo) +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + int i; + INT32 x; + SHIFT_TEMPS + + upsample->Cr_r_tab = (int *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (MAXJSAMPLE+1) * SIZEOF(int)); + upsample->Cb_b_tab = (int *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (MAXJSAMPLE+1) * SIZEOF(int)); + upsample->Cr_g_tab = (INT32 *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (MAXJSAMPLE+1) * SIZEOF(INT32)); + upsample->Cb_g_tab = (INT32 *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (MAXJSAMPLE+1) * SIZEOF(INT32)); + + for (i = 0, x = -CENTERJSAMPLE; i <= MAXJSAMPLE; i++, x++) { + /* i is the actual input pixel value, in the range 0..MAXJSAMPLE */ + /* The Cb or Cr value we are thinking of is x = i - CENTERJSAMPLE */ + /* Cr=>R value is nearest int to 1.40200 * x */ + upsample->Cr_r_tab[i] = (int) + RIGHT_SHIFT(FIX(1.40200) * x + ONE_HALF, SCALEBITS); + /* Cb=>B value is nearest int to 1.77200 * x */ + upsample->Cb_b_tab[i] = (int) + RIGHT_SHIFT(FIX(1.77200) * x + ONE_HALF, SCALEBITS); + /* Cr=>G value is scaled-up -0.71414 * x */ + upsample->Cr_g_tab[i] = (- FIX(0.71414)) * x; + /* Cb=>G value is scaled-up -0.34414 * x */ + /* We also add in ONE_HALF so that need not do it in inner loop */ + upsample->Cb_g_tab[i] = (- FIX(0.34414)) * x + ONE_HALF; + } +} + + +/* + * Initialize for an upsampling pass. + */ + +METHODDEF(void) +start_pass_merged_upsample (j_decompress_ptr cinfo) +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + + /* Mark the spare buffer empty */ + upsample->spare_full = FALSE; + /* Initialize total-height counter for detecting bottom of image */ + upsample->rows_to_go = cinfo->output_height; +} + + +/* + * Control routine to do upsampling (and color conversion). + * + * The control routine just handles the row buffering considerations. + */ + +METHODDEF(void) +merged_2v_upsample (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) +/* 2:1 vertical sampling case: may need a spare row. */ +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + JSAMPROW work_ptrs[2]; + JDIMENSION num_rows; /* number of rows returned to caller */ + (void)in_row_groups_avail; + + if (upsample->spare_full) { + /* If we have a spare row saved from a previous cycle, just return it. */ + jcopy_sample_rows(& upsample->spare_row, 0, output_buf + *out_row_ctr, 0, + 1, upsample->out_row_width); + num_rows = 1; + upsample->spare_full = FALSE; + } else { + /* Figure number of rows to return to caller. */ + num_rows = 2; + /* Not more than the distance to the end of the image. */ + if (num_rows > upsample->rows_to_go) + num_rows = upsample->rows_to_go; + /* And not more than what the client can accept: */ + out_rows_avail -= *out_row_ctr; + if (num_rows > out_rows_avail) + num_rows = out_rows_avail; + /* Create output pointer array for upsampler. */ + work_ptrs[0] = output_buf[*out_row_ctr]; + if (num_rows > 1) { + work_ptrs[1] = output_buf[*out_row_ctr + 1]; + } else { + work_ptrs[1] = upsample->spare_row; + upsample->spare_full = TRUE; + } + /* Now do the upsampling. */ + (*upsample->upmethod) (cinfo, input_buf, *in_row_group_ctr, work_ptrs); + } + + /* Adjust counts */ + *out_row_ctr += num_rows; + upsample->rows_to_go -= num_rows; + /* When the buffer is emptied, declare this input row group consumed */ + if (! upsample->spare_full) + (*in_row_group_ctr)++; +} + + +METHODDEF(void) +merged_1v_upsample (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) +/* 1:1 vertical sampling case: much easier, never need a spare row. */ +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + (void)in_row_groups_avail;(void)out_rows_avail; + + /* Just do the upsampling. */ + (*upsample->upmethod) (cinfo, input_buf, *in_row_group_ctr, + output_buf + *out_row_ctr); + /* Adjust counts */ + (*out_row_ctr)++; + (*in_row_group_ctr)++; +} + + +/* + * These are the routines invoked by the control routines to do + * the actual upsampling/conversion. One row group is processed per call. + * + * Note: since we may be writing directly into application-supplied buffers, + * we have to be honest about the output width; we can't assume the buffer + * has been rounded up to an even width. + */ + + +/* + * Upsample and color convert for the case of 2:1 horizontal and 1:1 vertical. + */ + +METHODDEF(void) +h2v1_merged_upsample (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr, + JSAMPARRAY output_buf) +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + register int y, cred, cgreen, cblue; + int cb, cr; + register JSAMPROW outptr; + JSAMPROW inptr0, inptr1, inptr2; + JDIMENSION col; + /* copy these pointers into registers if possible */ + register JSAMPLE * range_limit = cinfo->sample_range_limit; + int * Crrtab = upsample->Cr_r_tab; + int * Cbbtab = upsample->Cb_b_tab; + INT32 * Crgtab = upsample->Cr_g_tab; + INT32 * Cbgtab = upsample->Cb_g_tab; + SHIFT_TEMPS + + inptr0 = input_buf[0][in_row_group_ctr]; + inptr1 = input_buf[1][in_row_group_ctr]; + inptr2 = input_buf[2][in_row_group_ctr]; + outptr = output_buf[0]; + /* Loop for each pair of output pixels */ + for (col = cinfo->output_width >> 1; col > 0; col--) { + /* Do the chroma part of the calculation */ + cb = GETJSAMPLE(*inptr1++); + cr = GETJSAMPLE(*inptr2++); + cred = Crrtab[cr]; + cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS); + cblue = Cbbtab[cb]; + /* Fetch 2 Y values and emit 2 pixels */ + y = GETJSAMPLE(*inptr0++); + outptr[RGB_RED] = range_limit[y + cred]; + outptr[RGB_GREEN] = range_limit[y + cgreen]; + outptr[RGB_BLUE] = range_limit[y + cblue]; + outptr += RGB_PIXELSIZE; + y = GETJSAMPLE(*inptr0++); + outptr[RGB_RED] = range_limit[y + cred]; + outptr[RGB_GREEN] = range_limit[y + cgreen]; + outptr[RGB_BLUE] = range_limit[y + cblue]; + outptr += RGB_PIXELSIZE; + } + /* If image width is odd, do the last output column separately */ + if (cinfo->output_width & 1) { + cb = GETJSAMPLE(*inptr1); + cr = GETJSAMPLE(*inptr2); + cred = Crrtab[cr]; + cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS); + cblue = Cbbtab[cb]; + y = GETJSAMPLE(*inptr0); + outptr[RGB_RED] = range_limit[y + cred]; + outptr[RGB_GREEN] = range_limit[y + cgreen]; + outptr[RGB_BLUE] = range_limit[y + cblue]; + } +} + + +/* + * Upsample and color convert for the case of 2:1 horizontal and 2:1 vertical. + */ + +METHODDEF(void) +h2v2_merged_upsample (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr, + JSAMPARRAY output_buf) +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + register int y, cred, cgreen, cblue; + int cb, cr; + register JSAMPROW outptr0, outptr1; + JSAMPROW inptr00, inptr01, inptr1, inptr2; + JDIMENSION col; + /* copy these pointers into registers if possible */ + register JSAMPLE * range_limit = cinfo->sample_range_limit; + int * Crrtab = upsample->Cr_r_tab; + int * Cbbtab = upsample->Cb_b_tab; + INT32 * Crgtab = upsample->Cr_g_tab; + INT32 * Cbgtab = upsample->Cb_g_tab; + SHIFT_TEMPS + + inptr00 = input_buf[0][in_row_group_ctr*2]; + inptr01 = input_buf[0][in_row_group_ctr*2 + 1]; + inptr1 = input_buf[1][in_row_group_ctr]; + inptr2 = input_buf[2][in_row_group_ctr]; + outptr0 = output_buf[0]; + outptr1 = output_buf[1]; + /* Loop for each group of output pixels */ + for (col = cinfo->output_width >> 1; col > 0; col--) { + /* Do the chroma part of the calculation */ + cb = GETJSAMPLE(*inptr1++); + cr = GETJSAMPLE(*inptr2++); + cred = Crrtab[cr]; + cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS); + cblue = Cbbtab[cb]; + /* Fetch 4 Y values and emit 4 pixels */ + y = GETJSAMPLE(*inptr00++); + outptr0[RGB_RED] = range_limit[y + cred]; + outptr0[RGB_GREEN] = range_limit[y + cgreen]; + outptr0[RGB_BLUE] = range_limit[y + cblue]; + outptr0 += RGB_PIXELSIZE; + y = GETJSAMPLE(*inptr00++); + outptr0[RGB_RED] = range_limit[y + cred]; + outptr0[RGB_GREEN] = range_limit[y + cgreen]; + outptr0[RGB_BLUE] = range_limit[y + cblue]; + outptr0 += RGB_PIXELSIZE; + y = GETJSAMPLE(*inptr01++); + outptr1[RGB_RED] = range_limit[y + cred]; + outptr1[RGB_GREEN] = range_limit[y + cgreen]; + outptr1[RGB_BLUE] = range_limit[y + cblue]; + outptr1 += RGB_PIXELSIZE; + y = GETJSAMPLE(*inptr01++); + outptr1[RGB_RED] = range_limit[y + cred]; + outptr1[RGB_GREEN] = range_limit[y + cgreen]; + outptr1[RGB_BLUE] = range_limit[y + cblue]; + outptr1 += RGB_PIXELSIZE; + } + /* If image width is odd, do the last output column separately */ + if (cinfo->output_width & 1) { + cb = GETJSAMPLE(*inptr1); + cr = GETJSAMPLE(*inptr2); + cred = Crrtab[cr]; + cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS); + cblue = Cbbtab[cb]; + y = GETJSAMPLE(*inptr00); + outptr0[RGB_RED] = range_limit[y + cred]; + outptr0[RGB_GREEN] = range_limit[y + cgreen]; + outptr0[RGB_BLUE] = range_limit[y + cblue]; + y = GETJSAMPLE(*inptr01); + outptr1[RGB_RED] = range_limit[y + cred]; + outptr1[RGB_GREEN] = range_limit[y + cgreen]; + outptr1[RGB_BLUE] = range_limit[y + cblue]; + } +} + + +/* + * Module initialization routine for merged upsampling/color conversion. + * + * NB: this is called under the conditions determined by use_merged_upsample() + * in jdmaster.c. That routine MUST correspond to the actual capabilities + * of this module; no safety checks are made here. + */ + +GLOBAL(void) +jinit_merged_upsampler (j_decompress_ptr cinfo) +{ + my_upsample_ptr upsample; + + upsample = (my_upsample_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_upsampler)); + cinfo->upsample = (struct jpeg_upsampler *) upsample; + upsample->pub.start_pass = start_pass_merged_upsample; + upsample->pub.need_context_rows = FALSE; + + upsample->out_row_width = cinfo->output_width * cinfo->out_color_components; + + if (cinfo->max_v_samp_factor == 2) { + upsample->pub.upsample = merged_2v_upsample; + upsample->upmethod = h2v2_merged_upsample; + /* Allocate a spare row buffer */ + upsample->spare_row = (JSAMPROW) + (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (size_t) (upsample->out_row_width * SIZEOF(JSAMPLE))); + } else { + upsample->pub.upsample = merged_1v_upsample; + upsample->upmethod = h2v1_merged_upsample; + /* No spare row needed */ + upsample->spare_row = NULL; + } + + build_ycc_rgb_table(cinfo); +} + +#endif /* UPSAMPLE_MERGING_SUPPORTED */ diff --git a/Utilities/ITK/Utilities/itkjpeg/jdphuff.c b/Utilities/ITK/Utilities/itkjpeg/jdphuff.c new file mode 100644 index 0000000000000000000000000000000000000000..7baaff921518a91ab846def6f1b3fdbbedc4f1d4 --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jdphuff.c @@ -0,0 +1,675 @@ +/* + * jdphuff.c + * + * Copyright (C) 1995-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains Huffman entropy decoding routines for progressive JPEG. + * + * Much of the complexity here has to do with supporting input suspension. + * If the data source module demands suspension, we want to be able to back + * up to the start of the current MCU. To do this, we copy state variables + * into local working storage, and update them back to the permanent + * storage only upon successful completion of an MCU. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jlossy.h" /* Private declarations for lossy subsystem */ +#include "jdhuff.h" /* Declarations shared with jd*huff.c */ + + +#ifdef D_PROGRESSIVE_SUPPORTED + +/* + * Private entropy decoder object for progressive Huffman decoding. + * + * The savable_state subrecord contains fields that change within an MCU, + * but must not be updated permanently until we complete the MCU. + */ + +typedef struct { + unsigned int EOBRUN; /* remaining EOBs in EOBRUN */ + int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */ +} savable_state; + +/* This macro is to work around compilers with missing or broken + * structure assignment. You'll need to fix this code if you have + * such a compiler and you change MAX_COMPS_IN_SCAN. + */ + +#ifndef NO_STRUCT_ASSIGN +#define ASSIGN_STATE(dest,src) ((dest) = (src)) +#else +#if MAX_COMPS_IN_SCAN == 4 +#define ASSIGN_STATE(dest,src) \ + ((dest).EOBRUN = (src).EOBRUN, \ + (dest).last_dc_val[0] = (src).last_dc_val[0], \ + (dest).last_dc_val[1] = (src).last_dc_val[1], \ + (dest).last_dc_val[2] = (src).last_dc_val[2], \ + (dest).last_dc_val[3] = (src).last_dc_val[3]) +#endif +#endif + + +typedef struct { + huffd_common_fields; /* Fields shared with other entropy decoders */ + + /* These fields are loaded into local variables at start of each MCU. + * In case of suspension, we exit WITHOUT updating them. + */ + savable_state saved; /* Other state at start of MCU */ + + /* These fields are NOT loaded into local working state. */ + unsigned int restarts_to_go; /* MCUs left in this restart interval */ + + /* Pointers to derived tables (these workspaces have image lifespan) */ + d_derived_tbl * derived_tbls[NUM_HUFF_TBLS]; + + d_derived_tbl * ac_derived_tbl; /* active table during an AC scan */ +} phuff_entropy_decoder; + +typedef phuff_entropy_decoder * phuff_entropy_ptr; + +/* Forward declarations */ +METHODDEF(boolean) decode_mcu_DC_first JPP((j_decompress_ptr cinfo, + JBLOCKROW *MCU_data)); +METHODDEF(boolean) decode_mcu_AC_first JPP((j_decompress_ptr cinfo, + JBLOCKROW *MCU_data)); +METHODDEF(boolean) decode_mcu_DC_refine JPP((j_decompress_ptr cinfo, + JBLOCKROW *MCU_data)); +METHODDEF(boolean) decode_mcu_AC_refine JPP((j_decompress_ptr cinfo, + JBLOCKROW *MCU_data)); + + +/* + * Initialize for a Huffman-compressed scan. + */ + +METHODDEF(void) +start_pass_phuff_decoder (j_decompress_ptr cinfo) +{ + j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; + phuff_entropy_ptr entropy = (phuff_entropy_ptr) lossyd->entropy_private; + boolean is_DC_band, bad; + int ci, coefi, tbl; + int *coef_bit_ptr; + jpeg_component_info * compptr; + + is_DC_band = (cinfo->Ss == 0); + + /* Validate scan parameters */ + bad = FALSE; + if (is_DC_band) { + if (cinfo->Se != 0) + bad = TRUE; + } else { + /* need not check Ss/Se < 0 since they came from unsigned bytes */ + if (cinfo->Ss > cinfo->Se || cinfo->Se >= DCTSIZE2) + bad = TRUE; + /* AC scans may have only one component */ + if (cinfo->comps_in_scan != 1) + bad = TRUE; + } + if (cinfo->Ah != 0) { + /* Successive approximation refinement scan: must have Al = Ah-1. */ + if (cinfo->Al != cinfo->Ah-1) + bad = TRUE; + } + if (cinfo->Al > 13) /* need not check for < 0 */ + bad = TRUE; + /* Arguably the maximum Al value should be less than 13 for 8-bit precision, + * but the spec doesn't say so, and we try to be liberal about what we + * accept. Note: large Al values could result in out-of-range DC + * coefficients during early scans, leading to bizarre displays due to + * overflows in the IDCT math. But we won't crash. + */ + if (bad) + ERREXIT4(cinfo, JERR_BAD_PROGRESSION, + cinfo->Ss, cinfo->Se, cinfo->Ah, cinfo->Al); + /* Update progression status, and verify that scan order is legal. + * Note that inter-scan inconsistencies are treated as warnings + * not fatal errors ... not clear if this is right way to behave. + */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + int cindex = cinfo->cur_comp_info[ci]->component_index; + coef_bit_ptr = & cinfo->coef_bits[cindex][0]; + if (!is_DC_band && coef_bit_ptr[0] < 0) /* AC without prior DC scan */ + WARNMS2(cinfo, JWRN_BOGUS_PROGRESSION, cindex, 0); + for (coefi = cinfo->Ss; coefi <= cinfo->Se; coefi++) { + int expected = (coef_bit_ptr[coefi] < 0) ? 0 : coef_bit_ptr[coefi]; + if (cinfo->Ah != expected) + WARNMS2(cinfo, JWRN_BOGUS_PROGRESSION, cindex, coefi); + coef_bit_ptr[coefi] = cinfo->Al; + } + } + + /* Select MCU decoding routine */ + if (cinfo->Ah == 0) { + if (is_DC_band) + lossyd->entropy_decode_mcu = decode_mcu_DC_first; + else + lossyd->entropy_decode_mcu = decode_mcu_AC_first; + } else { + if (is_DC_band) + lossyd->entropy_decode_mcu = decode_mcu_DC_refine; + else + lossyd->entropy_decode_mcu = decode_mcu_AC_refine; + } + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + /* Make sure requested tables are present, and compute derived tables. + * We may build same derived table more than once, but it's not expensive. + */ + if (is_DC_band) { + if (cinfo->Ah == 0) { /* DC refinement needs no table */ + tbl = compptr->dc_tbl_no; + jpeg_make_d_derived_tbl(cinfo, TRUE, tbl, + & entropy->derived_tbls[tbl]); + } + } else { + tbl = compptr->ac_tbl_no; + jpeg_make_d_derived_tbl(cinfo, FALSE, tbl, + & entropy->derived_tbls[tbl]); + /* remember the single active table */ + entropy->ac_derived_tbl = entropy->derived_tbls[tbl]; + } + /* Initialize DC predictions to 0 */ + entropy->saved.last_dc_val[ci] = 0; + } + + /* Initialize bitread state variables */ + entropy->bitstate.bits_left = 0; + entropy->bitstate.get_buffer = 0; /* unnecessary, but keeps Purify quiet */ + entropy->insufficient_data = FALSE; + + /* Initialize private state variables */ + entropy->saved.EOBRUN = 0; + + /* Initialize restart counter */ + entropy->restarts_to_go = cinfo->restart_interval; +} + + +/* + * Figure F.12: extend sign bit. + * On some machines, a shift and add will be faster than a table lookup. + */ + +#ifdef AVOID_TABLES + +#define HUFF_EXTEND(x,s) ((x) < (1<<((s)-1)) ? (x) + (((-1)<<(s)) + 1) : (x)) + +#else + +#define HUFF_EXTEND(x,s) ((x) < extend_test[s] ? (x) + extend_offset[s] : (x)) + +static const int extend_test[16] = /* entry n is 2**(n-1) */ + { 0, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080, + 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000 }; + +static const int extend_offset[16] = /* entry n is (-1 << n) + 1 */ + { 0, ((-1)<<1) + 1, ((-1)<<2) + 1, ((-1)<<3) + 1, ((-1)<<4) + 1, + ((-1)<<5) + 1, ((-1)<<6) + 1, ((-1)<<7) + 1, ((-1)<<8) + 1, + ((-1)<<9) + 1, ((-1)<<10) + 1, ((-1)<<11) + 1, ((-1)<<12) + 1, + ((-1)<<13) + 1, ((-1)<<14) + 1, ((-1)<<15) + 1 }; + +#endif /* AVOID_TABLES */ + + +/* + * Check for a restart marker & resynchronize decoder. + * Returns FALSE if must suspend. + */ + +LOCAL(boolean) +process_restart (j_decompress_ptr cinfo) +{ + j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; + phuff_entropy_ptr entropy = (phuff_entropy_ptr) lossyd->entropy_private; + int ci; + + /* Throw away any unused bits remaining in bit buffer; */ + /* include any full bytes in next_marker's count of discarded bytes */ + cinfo->marker->discarded_bytes += entropy->bitstate.bits_left / 8; + entropy->bitstate.bits_left = 0; + + /* Advance past the RSTn marker */ + if (! (*cinfo->marker->read_restart_marker) (cinfo)) + return FALSE; + + /* Re-initialize DC predictions to 0 */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) + entropy->saved.last_dc_val[ci] = 0; + /* Re-init EOB run count, too */ + entropy->saved.EOBRUN = 0; + + /* Reset restart counter */ + entropy->restarts_to_go = cinfo->restart_interval; + + /* Reset out-of-data flag, unless read_restart_marker left us smack up + * against a marker. In that case we will end up treating the next data + * segment as empty, and we can avoid producing bogus output pixels by + * leaving the flag set. + */ + if (cinfo->unread_marker == 0) + entropy->insufficient_data = FALSE; + + return TRUE; +} + + +/* + * Huffman MCU decoding. + * Each of these routines decodes and returns one MCU's worth of + * Huffman-compressed coefficients. + * The coefficients are reordered from zigzag order into natural array order, + * but are not dequantized. + * + * The i'th block of the MCU is stored into the block pointed to by + * MCU_data[i]. WE ASSUME THIS AREA IS INITIALLY ZEROED BY THE CALLER. + * + * We return FALSE if data source requested suspension. In that case no + * changes have been made to permanent state. (Exception: some output + * coefficients may already have been assigned. This is harmless for + * spectral selection, since we'll just re-assign them on the next call. + * Successive approximation AC refinement has to be more careful, however.) + */ + +/* + * MCU decoding for DC initial scan (either spectral selection, + * or first pass of successive approximation). + */ + +METHODDEF(boolean) +decode_mcu_DC_first (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) +{ + j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; + phuff_entropy_ptr entropy = (phuff_entropy_ptr) lossyd->entropy_private; + int Al = cinfo->Al; + register int s, r; + int blkn, ci; + JBLOCKROW block; + BITREAD_STATE_VARS; + savable_state state; + d_derived_tbl * tbl; + jpeg_component_info * compptr; + + /* Process restart marker if needed; may have to suspend */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) + if (! process_restart(cinfo)) + return FALSE; + } + + /* If we've run out of data, just leave the MCU set to zeroes. + * This way, we return uniform gray for the remainder of the segment. + */ + if (! entropy->insufficient_data) { + + /* Load up working state */ + BITREAD_LOAD_STATE(cinfo,entropy->bitstate); + ASSIGN_STATE(state, entropy->saved); + + /* Outer loop handles each block in the MCU */ + + for (blkn = 0; blkn < cinfo->data_units_in_MCU; blkn++) { + block = MCU_data[blkn]; + ci = cinfo->MCU_membership[blkn]; + compptr = cinfo->cur_comp_info[ci]; + tbl = entropy->derived_tbls[compptr->dc_tbl_no]; + + /* Decode a single block's worth of coefficients */ + + /* Section F.2.2.1: decode the DC coefficient difference */ + HUFF_DECODE(s, br_state, tbl, return FALSE, label1); + if (s) { + CHECK_BIT_BUFFER(br_state, s, return FALSE); + r = GET_BITS(s); + s = HUFF_EXTEND(r, s); + } + + /* Convert DC difference to actual value, update last_dc_val */ + s += state.last_dc_val[ci]; + state.last_dc_val[ci] = s; + /* Scale and output the coefficient (assumes jpeg_natural_order[0]=0) */ + (*block)[0] = (JCOEF) (s << Al); + } + + /* Completed MCU, so update state */ + BITREAD_SAVE_STATE(cinfo,entropy->bitstate); + ASSIGN_STATE(entropy->saved, state); + } + + /* Account for restart interval (no-op if not using restarts) */ + entropy->restarts_to_go--; + + return TRUE; +} + + +/* + * MCU decoding for AC initial scan (either spectral selection, + * or first pass of successive approximation). + */ + +METHODDEF(boolean) +decode_mcu_AC_first (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) +{ + j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; + phuff_entropy_ptr entropy = (phuff_entropy_ptr) lossyd->entropy_private; + int Se = cinfo->Se; + int Al = cinfo->Al; + register int s, k, r; + unsigned int EOBRUN; + JBLOCKROW block; + BITREAD_STATE_VARS; + d_derived_tbl * tbl; + + /* Process restart marker if needed; may have to suspend */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) + if (! process_restart(cinfo)) + return FALSE; + } + + /* If we've run out of data, just leave the MCU set to zeroes. + * This way, we return uniform gray for the remainder of the segment. + */ + if (! entropy->insufficient_data) { + + /* Load up working state. + * We can avoid loading/saving bitread state if in an EOB run. + */ + EOBRUN = entropy->saved.EOBRUN; /* only part of saved state we need */ + + /* There is always only one block per MCU */ + + if (EOBRUN > 0) /* if it's a band of zeroes... */ + EOBRUN--; /* ...process it now (we do nothing) */ + else { + BITREAD_LOAD_STATE(cinfo,entropy->bitstate); + block = MCU_data[0]; + tbl = entropy->ac_derived_tbl; + + for (k = cinfo->Ss; k <= Se; k++) { + HUFF_DECODE(s, br_state, tbl, return FALSE, label2); + r = s >> 4; + s &= 15; + if (s) { + k += r; + CHECK_BIT_BUFFER(br_state, s, return FALSE); + r = GET_BITS(s); + s = HUFF_EXTEND(r, s); + /* Scale and output coefficient in natural (dezigzagged) order */ + (*block)[jpeg_natural_order[k]] = (JCOEF) (s << Al); + } else { + if (r == 15) { /* ZRL */ + k += 15; /* skip 15 zeroes in band */ + } else { /* EOBr, run length is 2^r + appended bits */ + EOBRUN = 1 << r; + if (r) { /* EOBr, r > 0 */ + CHECK_BIT_BUFFER(br_state, r, return FALSE); + r = GET_BITS(r); + EOBRUN += r; + } + EOBRUN--; /* this band is processed at this moment */ + break; /* force end-of-band */ + } + } + } + + BITREAD_SAVE_STATE(cinfo,entropy->bitstate); + } + + /* Completed MCU, so update state */ + entropy->saved.EOBRUN = EOBRUN; /* only part of saved state we need */ + } + + /* Account for restart interval (no-op if not using restarts) */ + entropy->restarts_to_go--; + + return TRUE; +} + + +/* + * MCU decoding for DC successive approximation refinement scan. + * Note: we assume such scans can be multi-component, although the spec + * is not very clear on the point. + */ + +METHODDEF(boolean) +decode_mcu_DC_refine (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) +{ + j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; + phuff_entropy_ptr entropy = (phuff_entropy_ptr) lossyd->entropy_private; + int p1 = 1 << cinfo->Al; /* 1 in the bit position being coded */ + int blkn; + JBLOCKROW block; + BITREAD_STATE_VARS; + + /* Process restart marker if needed; may have to suspend */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) + if (! process_restart(cinfo)) + return FALSE; + } + + /* Not worth the cycles to check insufficient_data here, + * since we will not change the data anyway if we read zeroes. + */ + + /* Load up working state */ + BITREAD_LOAD_STATE(cinfo,entropy->bitstate); + + /* Outer loop handles each block in the MCU */ + + for (blkn = 0; blkn < cinfo->data_units_in_MCU; blkn++) { + block = MCU_data[blkn]; + + /* Encoded data is simply the next bit of the two's-complement DC value */ + CHECK_BIT_BUFFER(br_state, 1, return FALSE); + if (GET_BITS(1)) + (*block)[0] |= p1; + /* Note: since we use |=, repeating the assignment later is safe */ + } + + /* Completed MCU, so update state */ + BITREAD_SAVE_STATE(cinfo,entropy->bitstate); + + /* Account for restart interval (no-op if not using restarts) */ + entropy->restarts_to_go--; + + return TRUE; +} + + +/* + * MCU decoding for AC successive approximation refinement scan. + */ + +METHODDEF(boolean) +decode_mcu_AC_refine (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) +{ + j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; + phuff_entropy_ptr entropy = (phuff_entropy_ptr) lossyd->entropy_private; + int Se = cinfo->Se; + int p1 = 1 << cinfo->Al; /* 1 in the bit position being coded */ + int m1 = (-1) << cinfo->Al; /* -1 in the bit position being coded */ + register int s, k, r; + unsigned int EOBRUN; + JBLOCKROW block; + JCOEFPTR thiscoef; + BITREAD_STATE_VARS; + d_derived_tbl * tbl; + int num_newnz; + int newnz_pos[DCTSIZE2]; + + /* Process restart marker if needed; may have to suspend */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) + if (! process_restart(cinfo)) + return FALSE; + } + + /* If we've run out of data, don't modify the MCU. + */ + if (! entropy->insufficient_data) { + + /* Load up working state */ + BITREAD_LOAD_STATE(cinfo,entropy->bitstate); + EOBRUN = entropy->saved.EOBRUN; /* only part of saved state we need */ + + /* There is always only one block per MCU */ + block = MCU_data[0]; + tbl = entropy->ac_derived_tbl; + + /* If we are forced to suspend, we must undo the assignments to any newly + * nonzero coefficients in the block, because otherwise we'd get confused + * next time about which coefficients were already nonzero. + * But we need not undo addition of bits to already-nonzero coefficients; + * instead, we can test the current bit to see if we already did it. + */ + num_newnz = 0; + + /* initialize coefficient loop counter to start of band */ + k = cinfo->Ss; + + if (EOBRUN == 0) { + for (; k <= Se; k++) { + HUFF_DECODE(s, br_state, tbl, goto undoit, label3); + r = s >> 4; + s &= 15; + if (s) { + if (s != 1) /* size of new coef should always be 1 */ + WARNMS(cinfo, JWRN_HUFF_BAD_CODE); + CHECK_BIT_BUFFER(br_state, 1, goto undoit); + if (GET_BITS(1)) + s = p1; /* newly nonzero coef is positive */ + else + s = m1; /* newly nonzero coef is negative */ + } else { + if (r != 15) { + EOBRUN = 1 << r; /* EOBr, run length is 2^r + appended bits */ + if (r) { + CHECK_BIT_BUFFER(br_state, r, goto undoit); + r = GET_BITS(r); + EOBRUN += r; + } + break; /* rest of block is handled by EOB logic */ + } + /* note s = 0 for processing ZRL */ + } + /* Advance over already-nonzero coefs and r still-zero coefs, + * appending correction bits to the nonzeroes. A correction bit is 1 + * if the absolute value of the coefficient must be increased. + */ + do { + thiscoef = *block + jpeg_natural_order[k]; + if (*thiscoef != 0) { + CHECK_BIT_BUFFER(br_state, 1, goto undoit); + if (GET_BITS(1)) { + if ((*thiscoef & p1) == 0) { /* do nothing if already set it */ + if (*thiscoef >= 0) + *thiscoef += p1; + else + *thiscoef += m1; + } + } + } else { + if (--r < 0) + break; /* reached target zero coefficient */ + } + k++; + } while (k <= Se); + if (s) { + int pos = jpeg_natural_order[k]; + /* Output newly nonzero coefficient */ + (*block)[pos] = (JCOEF) s; + /* Remember its position in case we have to suspend */ + newnz_pos[num_newnz++] = pos; + } + } + } + + if (EOBRUN > 0) { + /* Scan any remaining coefficient positions after the end-of-band + * (the last newly nonzero coefficient, if any). Append a correction + * bit to each already-nonzero coefficient. A correction bit is 1 + * if the absolute value of the coefficient must be increased. + */ + for (; k <= Se; k++) { + thiscoef = *block + jpeg_natural_order[k]; + if (*thiscoef != 0) { + CHECK_BIT_BUFFER(br_state, 1, goto undoit); + if (GET_BITS(1)) { + if ((*thiscoef & p1) == 0) { /* do nothing if already changed it */ + if (*thiscoef >= 0) + *thiscoef += p1; + else + *thiscoef += m1; + } + } + } + } + /* Count one block completed in EOB run */ + EOBRUN--; + } + + /* Completed MCU, so update state */ + BITREAD_SAVE_STATE(cinfo,entropy->bitstate); + entropy->saved.EOBRUN = EOBRUN; /* only part of saved state we need */ + } + + /* Account for restart interval (no-op if not using restarts) */ + entropy->restarts_to_go--; + + return TRUE; + +undoit: + /* Re-zero any output coefficients that we made newly nonzero */ + while (num_newnz > 0) + (*block)[newnz_pos[--num_newnz]] = 0; + + return FALSE; +} + + +/* + * Module initialization routine for progressive Huffman entropy decoding. + */ + +GLOBAL(void) +jinit_phuff_decoder (j_decompress_ptr cinfo) +{ + j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; + phuff_entropy_ptr entropy; + int *coef_bit_ptr; + int ci, i; + + entropy = (phuff_entropy_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(phuff_entropy_decoder)); + lossyd->entropy_private = (void *) entropy; + lossyd->entropy_start_pass = start_pass_phuff_decoder; + + /* Mark derived tables unallocated */ + for (i = 0; i < NUM_HUFF_TBLS; i++) { + entropy->derived_tbls[i] = NULL; + } + + /* Create progression status table */ + cinfo->coef_bits = (int (*)[DCTSIZE2]) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + cinfo->num_components*DCTSIZE2*SIZEOF(int)); + coef_bit_ptr = & cinfo->coef_bits[0][0]; + for (ci = 0; ci < cinfo->num_components; ci++) + for (i = 0; i < DCTSIZE2; i++) + *coef_bit_ptr++ = -1; +} + +#endif /* D_PROGRESSIVE_SUPPORTED */ diff --git a/Utilities/ITK/Utilities/itkjpeg/jdpostct.c b/Utilities/ITK/Utilities/itkjpeg/jdpostct.c new file mode 100644 index 0000000000000000000000000000000000000000..760eb19abd0d0c93b0cd738d64b608865ce3699e --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jdpostct.c @@ -0,0 +1,292 @@ +/* + * jdpostct.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the decompression postprocessing controller. + * This controller manages the upsampling, color conversion, and color + * quantization/reduction steps; specifically, it controls the buffering + * between upsample/color conversion and color quantization/reduction. + * + * If no color quantization/reduction is required, then this module has no + * work to do, and it just hands off to the upsample/color conversion code. + * An integrated upsample/convert/quantize process would replace this module + * entirely. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Private buffer controller object */ + +typedef struct { + struct jpeg_d_post_controller pub; /* public fields */ + + /* Color quantization source buffer: this holds output data from + * the upsample/color conversion step to be passed to the quantizer. + * For two-pass color quantization, we need a full-image buffer; + * for one-pass operation, a strip buffer is sufficient. + */ + jvirt_sarray_ptr whole_image; /* virtual array, or NULL if one-pass */ + JSAMPARRAY buffer; /* strip buffer, or current strip of virtual */ + JDIMENSION strip_height; /* buffer size in rows */ + /* for two-pass mode only: */ + JDIMENSION starting_row; /* row # of first row in current strip */ + JDIMENSION next_row; /* index of next row to fill/empty in strip */ +} my_post_controller; + +typedef my_post_controller * my_post_ptr; + + +/* Forward declarations */ +METHODDEF(void) post_process_1pass + JPP((j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail)); +#ifdef QUANT_2PASS_SUPPORTED +METHODDEF(void) post_process_prepass + JPP((j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail)); +METHODDEF(void) post_process_2pass + JPP((j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail)); +#endif + + +/* + * Initialize for a processing pass. + */ + +METHODDEF(void) +start_pass_dpost (j_decompress_ptr cinfo, J_BUF_MODE pass_mode) +{ + my_post_ptr post = (my_post_ptr) cinfo->post; + + switch (pass_mode) { + case JBUF_PASS_THRU: + if (cinfo->quantize_colors) { + /* Single-pass processing with color quantization. */ + post->pub.post_process_data = post_process_1pass; + /* We could be doing buffered-image output before starting a 2-pass + * color quantization; in that case, jinit_d_post_controller did not + * allocate a strip buffer. Use the virtual-array buffer as workspace. + */ + if (post->buffer == NULL) { + post->buffer = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, post->whole_image, + (JDIMENSION) 0, post->strip_height, TRUE); + } + } else { + /* For single-pass processing without color quantization, + * I have no work to do; just call the upsampler directly. + */ + post->pub.post_process_data = cinfo->upsample->upsample; + } + break; +#ifdef QUANT_2PASS_SUPPORTED + case JBUF_SAVE_AND_PASS: + /* First pass of 2-pass quantization */ + if (post->whole_image == NULL) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + post->pub.post_process_data = post_process_prepass; + break; + case JBUF_CRANK_DEST: + /* Second pass of 2-pass quantization */ + if (post->whole_image == NULL) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + post->pub.post_process_data = post_process_2pass; + break; +#endif /* QUANT_2PASS_SUPPORTED */ + default: + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + break; + } + post->starting_row = post->next_row = 0; +} + + +/* + * Process some data in the one-pass (strip buffer) case. + * This is used for color precision reduction as well as one-pass quantization. + */ + +METHODDEF(void) +post_process_1pass (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) +{ + my_post_ptr post = (my_post_ptr) cinfo->post; + JDIMENSION num_rows, max_rows; + + /* Fill the buffer, but not more than what we can dump out in one go. */ + /* Note we rely on the upsampler to detect bottom of image. */ + max_rows = out_rows_avail - *out_row_ctr; + if (max_rows > post->strip_height) + max_rows = post->strip_height; + num_rows = 0; + (*cinfo->upsample->upsample) (cinfo, + input_buf, in_row_group_ctr, in_row_groups_avail, + post->buffer, &num_rows, max_rows); + /* Quantize and emit data. */ + (*cinfo->cquantize->color_quantize) (cinfo, + post->buffer, output_buf + *out_row_ctr, (int) num_rows); + *out_row_ctr += num_rows; +} + + +#ifdef QUANT_2PASS_SUPPORTED + +/* + * Process some data in the first pass of 2-pass quantization. + */ + +METHODDEF(void) +post_process_prepass (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) +{ + my_post_ptr post = (my_post_ptr) cinfo->post; + JDIMENSION old_next_row, num_rows; + (void)output_buf;(void)out_rows_avail; + + /* Reposition virtual buffer if at start of strip. */ + if (post->next_row == 0) { + post->buffer = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, post->whole_image, + post->starting_row, post->strip_height, TRUE); + } + + /* Upsample some data (up to a strip height's worth). */ + old_next_row = post->next_row; + (*cinfo->upsample->upsample) (cinfo, + input_buf, in_row_group_ctr, in_row_groups_avail, + post->buffer, &post->next_row, post->strip_height); + + /* Allow quantizer to scan new data. No data is emitted, */ + /* but we advance out_row_ctr so outer loop can tell when we're done. */ + if (post->next_row > old_next_row) { + num_rows = post->next_row - old_next_row; + (*cinfo->cquantize->color_quantize) (cinfo, post->buffer + old_next_row, + (JSAMPARRAY) NULL, (int) num_rows); + *out_row_ctr += num_rows; + } + + /* Advance if we filled the strip. */ + if (post->next_row >= post->strip_height) { + post->starting_row += post->strip_height; + post->next_row = 0; + } +} + + +/* + * Process some data in the second pass of 2-pass quantization. + */ + +METHODDEF(void) +post_process_2pass (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) +{ + my_post_ptr post = (my_post_ptr) cinfo->post; + JDIMENSION num_rows, max_rows; + (void)input_buf;(void)in_row_group_ctr;(void)in_row_groups_avail; + + /* Reposition virtual buffer if at start of strip. */ + if (post->next_row == 0) { + post->buffer = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, post->whole_image, + post->starting_row, post->strip_height, FALSE); + } + + /* Determine number of rows to emit. */ + num_rows = post->strip_height - post->next_row; /* available in strip */ + max_rows = out_rows_avail - *out_row_ctr; /* available in output area */ + if (num_rows > max_rows) + num_rows = max_rows; + /* We have to check bottom of image here, can't depend on upsampler. */ + max_rows = cinfo->output_height - post->starting_row; + if (num_rows > max_rows) + num_rows = max_rows; + + /* Quantize and emit data. */ + (*cinfo->cquantize->color_quantize) (cinfo, + post->buffer + post->next_row, output_buf + *out_row_ctr, + (int) num_rows); + *out_row_ctr += num_rows; + + /* Advance if we filled the strip. */ + post->next_row += num_rows; + if (post->next_row >= post->strip_height) { + post->starting_row += post->strip_height; + post->next_row = 0; + } +} + +#endif /* QUANT_2PASS_SUPPORTED */ + + +/* + * Initialize postprocessing controller. + */ + +GLOBAL(void) +jinit_d_post_controller (j_decompress_ptr cinfo, boolean need_full_buffer) +{ + my_post_ptr post; + + post = (my_post_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_post_controller)); + cinfo->post = (struct jpeg_d_post_controller *) post; + post->pub.start_pass = start_pass_dpost; + post->whole_image = NULL; /* flag for no virtual arrays */ + post->buffer = NULL; /* flag for no strip buffer */ + + /* Create the quantization buffer, if needed */ + if (cinfo->quantize_colors) { + /* The buffer strip height is max_v_samp_factor, which is typically + * an efficient number of rows for upsampling to return. + * (In the presence of output rescaling, we might want to be smarter?) + */ + post->strip_height = (JDIMENSION) cinfo->max_v_samp_factor; + if (need_full_buffer) { + /* Two-pass color quantization: need full-image storage. */ + /* We round up the number of rows to a multiple of the strip height. */ +#ifdef QUANT_2PASS_SUPPORTED + post->whole_image = (*cinfo->mem->request_virt_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE, + cinfo->output_width * cinfo->out_color_components, + (JDIMENSION) jround_up((long) cinfo->output_height, + (long) post->strip_height), + post->strip_height); +#else + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); +#endif /* QUANT_2PASS_SUPPORTED */ + } else { + /* One-pass color quantization: just make a strip buffer. */ + post->buffer = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + cinfo->output_width * cinfo->out_color_components, + post->strip_height); + } + } +} diff --git a/Utilities/ITK/Utilities/itkjpeg/jdpred.c b/Utilities/ITK/Utilities/itkjpeg/jdpred.c new file mode 100644 index 0000000000000000000000000000000000000000..4704fc4f9c3491959c56b1a6fcfe873f35e5253b --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jdpred.c @@ -0,0 +1,258 @@ +/* + * jdpred.c + * + * Copyright (C) 1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains sample undifferencing (reconstruction) for lossless JPEG. + * + * In order to avoid paying the performance penalty of having to check the + * predictor being used and the row being processed for each call of the + * undifferencer, and to promote optimization, we have separate undifferencing + * functions for each case. + * + * We are able to avoid duplicating source code by implementing the predictors + * and undifferencers as macros. Each of the undifferencing functions are + * simply wrappers around an UNDIFFERENCE macro with the appropriate PREDICTOR + * macro passed as an argument. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jlossls.h" /* Private declarations for lossless codec */ + + +#ifdef D_LOSSLESS_SUPPORTED + +/* Predictor for the first column of the first row: 2^(P-Pt-1) */ +#define INITIAL_PREDICTORx (1 << (cinfo->data_precision - cinfo->Al - 1)) + +/* Predictor for the first column of the remaining rows: Rb */ +#define INITIAL_PREDICTOR2 GETJSAMPLE(prev_row[0]) + + +/* + * 1-Dimensional undifferencer routine. + * + * This macro implements the 1-D horizontal predictor (1). INITIAL_PREDICTOR + * is used as the special case predictor for the first column, which must be + * either INITIAL_PREDICTOR2 or INITIAL_PREDICTORx. The remaining samples + * use PREDICTOR1. + * + * The reconstructed sample is supposed to be calculated modulo 2^16, so we + * logically AND the result with 0xFFFF. +*/ + +#define UNDIFFERENCE_1D(INITIAL_PREDICTOR) \ + unsigned int xindex; \ + int Ra; \ + \ + Ra = (diff_buf[0] + INITIAL_PREDICTOR) & 0xFFFF; \ + undiff_buf[0] = Ra; \ + \ + for (xindex = 1; xindex < width; xindex++) { \ + Ra = (diff_buf[xindex] + PREDICTOR1) & 0xFFFF; \ + undiff_buf[xindex] = Ra; \ + } + +/* + * 2-Dimensional undifferencer routine. + * + * This macro implements the 2-D horizontal predictors (#2-7). PREDICTOR2 is + * used as the special case predictor for the first column. The remaining + * samples use PREDICTOR, which is a function of Ra, Rb, Rc. + * + * Because prev_row and output_buf may point to the same storage area (in an + * interleaved image with Vi=1, for example), we must take care to buffer Rb/Rc + * before writing the current reconstructed sample value into output_buf. + * + * The reconstructed sample is supposed to be calculated modulo 2^16, so we + * logically AND the result with 0xFFFF. + */ + +#define UNDIFFERENCE_2D(PREDICTOR) \ + unsigned int xindex; \ + int Ra, Rb, Rc; \ + \ + Rb = GETJSAMPLE(prev_row[0]); \ + Ra = (diff_buf[0] + PREDICTOR2) & 0xFFFF; \ + undiff_buf[0] = Ra; \ + \ + for (xindex = 1; xindex < width; xindex++) { \ + Rc = Rb; \ + Rb = GETJSAMPLE(prev_row[xindex]); \ + Ra = (diff_buf[xindex] + PREDICTOR) & 0xFFFF; \ + undiff_buf[xindex] = Ra; \ + } + + +/* + * Undifferencers for the all rows but the first in a scan or restart interval. + * The first sample in the row is undifferenced using the vertical + * predictor (2). The rest of the samples are undifferenced using the + * predictor specified in the scan header. + */ + +METHODDEF(void) +jpeg_undifference1(j_decompress_ptr cinfo, int comp_index, + JDIFFROW diff_buf, JDIFFROW prev_row, + JDIFFROW undiff_buf, JDIMENSION width) +{ + UNDIFFERENCE_1D(INITIAL_PREDICTOR2); + (void)cinfo;(void)comp_index;(void)diff_buf;(void)prev_row;(void)undiff_buf;(void)width; +} + +METHODDEF(void) +jpeg_undifference2(j_decompress_ptr cinfo, int comp_index, + JDIFFROW diff_buf, JDIFFROW prev_row, + JDIFFROW undiff_buf, JDIMENSION width) +{ + UNDIFFERENCE_2D(PREDICTOR2); + (void)cinfo;(void)comp_index;(void)diff_buf;(void)prev_row;(void)undiff_buf;(void)width; +} + +METHODDEF(void) +jpeg_undifference3(j_decompress_ptr cinfo, int comp_index, + JDIFFROW diff_buf, JDIFFROW prev_row, + JDIFFROW undiff_buf, JDIMENSION width) +{ + UNDIFFERENCE_2D(PREDICTOR3); + (void)cinfo;(void)comp_index;(void)diff_buf;(void)prev_row;(void)undiff_buf;(void)width; +} + +METHODDEF(void) +jpeg_undifference4(j_decompress_ptr cinfo, int comp_index, + JDIFFROW diff_buf, JDIFFROW prev_row, + JDIFFROW undiff_buf, JDIMENSION width) +{ + UNDIFFERENCE_2D(PREDICTOR4); + (void)cinfo;(void)comp_index;(void)diff_buf;(void)prev_row;(void)undiff_buf;(void)width; +} + +METHODDEF(void) +jpeg_undifference5(j_decompress_ptr cinfo, int comp_index, + JDIFFROW diff_buf, JDIFFROW prev_row, + JDIFFROW undiff_buf, JDIMENSION width) +{ + SHIFT_TEMPS + UNDIFFERENCE_2D(PREDICTOR5); + (void)cinfo;(void)comp_index;(void)diff_buf;(void)prev_row;(void)undiff_buf;(void)width; +} + +METHODDEF(void) +jpeg_undifference6(j_decompress_ptr cinfo, int comp_index, + JDIFFROW diff_buf, JDIFFROW prev_row, + JDIFFROW undiff_buf, JDIMENSION width) +{ + SHIFT_TEMPS + UNDIFFERENCE_2D(PREDICTOR6); + (void)cinfo;(void)comp_index;(void)diff_buf;(void)prev_row;(void)undiff_buf;(void)width; +} + +METHODDEF(void) +jpeg_undifference7(j_decompress_ptr cinfo, int comp_index, + JDIFFROW diff_buf, JDIFFROW prev_row, + JDIFFROW undiff_buf, JDIMENSION width) +{ + SHIFT_TEMPS + UNDIFFERENCE_2D(PREDICTOR7); + (void)cinfo;(void)comp_index;(void)diff_buf;(void)prev_row;(void)undiff_buf;(void)width; +} + + +/* + * Undifferencer for the first row in a scan or restart interval. The first + * sample in the row is undifferenced using the special predictor constant + * x=2^(P-Pt-1). The rest of the samples are undifferenced using the + * 1-D horizontal predictor (1). + */ + +METHODDEF(void) +jpeg_undifference_first_row(j_decompress_ptr cinfo, int comp_index, + JDIFFROW diff_buf, JDIFFROW prev_row, + JDIFFROW undiff_buf, JDIMENSION width) +{ + j_lossless_d_ptr losslsd = (j_lossless_d_ptr) cinfo->codec; + + UNDIFFERENCE_1D(INITIAL_PREDICTORx); + (void)prev_row; + + /* + * Now that we have undifferenced the first row, we want to use the + * undifferencer which corresponds to the predictor specified in the + * scan header. + */ + switch (cinfo->Ss) { + case 1: + losslsd->predict_undifference[comp_index] = jpeg_undifference1; + break; + case 2: + losslsd->predict_undifference[comp_index] = jpeg_undifference2; + break; + case 3: + losslsd->predict_undifference[comp_index] = jpeg_undifference3; + break; + case 4: + losslsd->predict_undifference[comp_index] = jpeg_undifference4; + break; + case 5: + losslsd->predict_undifference[comp_index] = jpeg_undifference5; + break; + case 6: + losslsd->predict_undifference[comp_index] = jpeg_undifference6; + break; + case 7: + losslsd->predict_undifference[comp_index] = jpeg_undifference7; + break; + } +} + + +/* + * Initialize for an input processing pass. + */ + +METHODDEF(void) +predict_start_pass (j_decompress_ptr cinfo) +{ + j_lossless_d_ptr losslsd = (j_lossless_d_ptr) cinfo->codec; + int ci; + + /* Check that the scan parameters Ss, Se, Ah, Al are OK for lossless JPEG. + * + * Ss is the predictor selection value (psv). Legal values for sequential + * lossless JPEG are: 1 <= psv <= 7. + * + * Se and Ah are not used and should be zero. + * + * Al specifies the point transform (Pt). Legal values are: 0 <= Pt <= 15. + */ + if (cinfo->Ss < 1 || cinfo->Ss > 7 || + cinfo->Se != 0 || cinfo->Ah != 0 || + cinfo->Al > 15) /* need not check for < 0 */ + ERREXIT4(cinfo, JERR_BAD_LOSSLESS, + cinfo->Ss, cinfo->Se, cinfo->Ah, cinfo->Al); + + /* Set undifference functions to first row function */ + for (ci = 0; ci < cinfo->num_components; ci++) + losslsd->predict_undifference[ci] = jpeg_undifference_first_row; +} + + +/* + * Module initialization routine for the undifferencer. + */ + +GLOBAL(void) +jinit_undifferencer (j_decompress_ptr cinfo) +{ + j_lossless_d_ptr losslsd = (j_lossless_d_ptr) cinfo->codec; + + losslsd->predict_start_pass = predict_start_pass; + losslsd->predict_process_restart = predict_start_pass; +} + +#endif /* D_LOSSLESS_SUPPORTED */ + diff --git a/Utilities/ITK/Utilities/itkjpeg/jdsample.c b/Utilities/ITK/Utilities/itkjpeg/jdsample.c new file mode 100644 index 0000000000000000000000000000000000000000..a36283e29c293d8e218e9f99a1872e4ac57e9581 --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jdsample.c @@ -0,0 +1,483 @@ +/* + * jdsample.c + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains upsampling routines. + * + * Upsampling input data is counted in "row groups". A row group + * is defined to be (v_samp_factor * codec_data_unit / min_codec_data_unit) + * sample rows of each component. Upsampling will normally produce + * max_v_samp_factor pixel rows from each row group (but this could vary + * if the upsampler is applying a scale factor of its own). + * + * An excellent reference for image resampling is + * Digital Image Warping, George Wolberg, 1990. + * Pub. by IEEE Computer Society Press, Los Alamitos, CA. ISBN 0-8186-8944-7. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Pointer to routine to upsample a single component */ +typedef JMETHOD(void, upsample1_ptr, + (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)); + +/* Private subobject */ + +typedef struct { + struct jpeg_upsampler pub; /* public fields */ + + /* Color conversion buffer. When using separate upsampling and color + * conversion steps, this buffer holds one upsampled row group until it + * has been color converted and output. + * Note: we do not allocate any storage for component(s) which are full-size, + * ie do not need rescaling. The corresponding entry of color_buf[] is + * simply set to point to the input data array, thereby avoiding copying. + */ + JSAMPARRAY color_buf[MAX_COMPONENTS]; + + /* Per-component upsampling method pointers */ + upsample1_ptr methods[MAX_COMPONENTS]; + + int next_row_out; /* counts rows emitted from color_buf */ + JDIMENSION rows_to_go; /* counts rows remaining in image */ + + /* Height of an input row group for each component. */ + int rowgroup_height[MAX_COMPONENTS]; + + /* These arrays save pixel expansion factors so that int_expand need not + * recompute them each time. They are unused for other upsampling methods. + */ + UINT8 h_expand[MAX_COMPONENTS]; + UINT8 v_expand[MAX_COMPONENTS]; +} my_upsampler; + +typedef my_upsampler * my_upsample_ptr; + + +/* + * Initialize for an upsampling pass. + */ + +METHODDEF(void) +start_pass_upsample (j_decompress_ptr cinfo) +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + + /* Mark the conversion buffer empty */ + upsample->next_row_out = cinfo->max_v_samp_factor; + /* Initialize total-height counter for detecting bottom of image */ + upsample->rows_to_go = cinfo->output_height; +} + + +/* + * Control routine to do upsampling (and color conversion). + * + * In this version we upsample each component independently. + * We upsample one row group into the conversion buffer, then apply + * color conversion a row at a time. + */ + +METHODDEF(void) +sep_upsample (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + int ci; + jpeg_component_info * compptr; + JDIMENSION num_rows; + (void)in_row_groups_avail; + + /* Fill the conversion buffer, if it's empty */ + if (upsample->next_row_out >= cinfo->max_v_samp_factor) { + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Invoke per-component upsample method. Notice we pass a POINTER + * to color_buf[ci], so that fullsize_upsample can change it. + */ + (*upsample->methods[ci]) (cinfo, compptr, + input_buf[ci] + (*in_row_group_ctr * upsample->rowgroup_height[ci]), + upsample->color_buf + ci); + } + upsample->next_row_out = 0; + } + + /* Color-convert and emit rows */ + + /* How many we have in the buffer: */ + num_rows = (JDIMENSION) (cinfo->max_v_samp_factor - upsample->next_row_out); + /* Not more than the distance to the end of the image. Need this test + * in case the image height is not a multiple of max_v_samp_factor: + */ + if (num_rows > upsample->rows_to_go) + num_rows = upsample->rows_to_go; + /* And not more than what the client can accept: */ + out_rows_avail -= *out_row_ctr; + if (num_rows > out_rows_avail) + num_rows = out_rows_avail; + + (*cinfo->cconvert->color_convert) (cinfo, upsample->color_buf, + (JDIMENSION) upsample->next_row_out, + output_buf + *out_row_ctr, + (int) num_rows); + + /* Adjust counts */ + *out_row_ctr += num_rows; + upsample->rows_to_go -= num_rows; + upsample->next_row_out += num_rows; + /* When the buffer is emptied, declare this input row group consumed */ + if (upsample->next_row_out >= cinfo->max_v_samp_factor) + (*in_row_group_ctr)++; +} + + +/* + * These are the routines invoked by sep_upsample to upsample pixel values + * of a single component. One row group is processed per call. + */ + + +/* + * For full-size components, we just make color_buf[ci] point at the + * input buffer, and thus avoid copying any data. Note that this is + * safe only because sep_upsample doesn't declare the input row group + * "consumed" until we are done color converting and emitting it. + */ + +METHODDEF(void) +fullsize_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) +{ + (void)cinfo;(void)compptr; + *output_data_ptr = input_data; +} + + +/* + * This is a no-op version used for "uninteresting" components. + * These components will not be referenced by color conversion. + */ + +METHODDEF(void) +noop_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) +{ + (void)cinfo;(void)compptr;(void)input_data; + *output_data_ptr = NULL; /* safety check */ +} + + +/* + * This version handles any integral sampling ratios. + * This is not used for typical JPEG files, so it need not be fast. + * Nor, for that matter, is it particularly accurate: the algorithm is + * simple replication of the input pixel onto the corresponding output + * pixels. The hi-falutin sampling literature refers to this as a + * "box filter". A box filter tends to introduce visible artifacts, + * so if you are actually going to use 3:1 or 4:1 sampling ratios + * you would be well advised to improve this code. + */ + +METHODDEF(void) +int_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + JSAMPARRAY output_data = *output_data_ptr; + register JSAMPROW inptr, outptr; + register JSAMPLE invalue; + register int h; + JSAMPROW outend; + int h_expand, v_expand; + int inrow, outrow; + + h_expand = upsample->h_expand[compptr->component_index]; + v_expand = upsample->v_expand[compptr->component_index]; + + inrow = outrow = 0; + while (outrow < cinfo->max_v_samp_factor) { + /* Generate one output row with proper horizontal expansion */ + inptr = input_data[inrow]; + outptr = output_data[outrow]; + outend = outptr + cinfo->output_width; + while (outptr < outend) { + invalue = *inptr++; /* don't need GETJSAMPLE() here */ + for (h = h_expand; h > 0; h--) { + *outptr++ = invalue; + } + } + /* Generate any additional output rows by duplicating the first one */ + if (v_expand > 1) { + jcopy_sample_rows(output_data, outrow, output_data, outrow+1, + v_expand-1, cinfo->output_width); + } + inrow++; + outrow += v_expand; + } +} + + +/* + * Fast processing for the common case of 2:1 horizontal and 1:1 vertical. + * It's still a box filter. + */ + +METHODDEF(void) +h2v1_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) +{ + JSAMPARRAY output_data = *output_data_ptr; + register JSAMPROW inptr, outptr; + register JSAMPLE invalue; + JSAMPROW outend; + int inrow; + (void)compptr; + + for (inrow = 0; inrow < cinfo->max_v_samp_factor; inrow++) { + inptr = input_data[inrow]; + outptr = output_data[inrow]; + outend = outptr + cinfo->output_width; + while (outptr < outend) { + invalue = *inptr++; /* don't need GETJSAMPLE() here */ + *outptr++ = invalue; + *outptr++ = invalue; + } + } +} + + +/* + * Fast processing for the common case of 2:1 horizontal and 2:1 vertical. + * It's still a box filter. + */ + +METHODDEF(void) +h2v2_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) +{ + JSAMPARRAY output_data = *output_data_ptr; + register JSAMPROW inptr, outptr; + register JSAMPLE invalue; + JSAMPROW outend; + int inrow, outrow; + (void)compptr; + + inrow = outrow = 0; + while (outrow < cinfo->max_v_samp_factor) { + inptr = input_data[inrow]; + outptr = output_data[outrow]; + outend = outptr + cinfo->output_width; + while (outptr < outend) { + invalue = *inptr++; /* don't need GETJSAMPLE() here */ + *outptr++ = invalue; + *outptr++ = invalue; + } + jcopy_sample_rows(output_data, outrow, output_data, outrow+1, + 1, cinfo->output_width); + inrow++; + outrow += 2; + } +} + + +/* + * Fancy processing for the common case of 2:1 horizontal and 1:1 vertical. + * + * The upsampling algorithm is linear interpolation between pixel centers, + * also known as a "triangle filter". This is a good compromise between + * speed and visual quality. The centers of the output pixels are 1/4 and 3/4 + * of the way between input pixel centers. + * + * A note about the "bias" calculations: when rounding fractional values to + * integer, we do not want to always round 0.5 up to the next integer. + * If we did that, we'd introduce a noticeable bias towards larger values. + * Instead, this code is arranged so that 0.5 will be rounded up or down at + * alternate pixel locations (a simple ordered dither pattern). + */ + +METHODDEF(void) +h2v1_fancy_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) +{ + JSAMPARRAY output_data = *output_data_ptr; + register JSAMPROW inptr, outptr; + register int invalue; + register JDIMENSION colctr; + int inrow; + + for (inrow = 0; inrow < cinfo->max_v_samp_factor; inrow++) { + inptr = input_data[inrow]; + outptr = output_data[inrow]; + /* Special case for first column */ + invalue = GETJSAMPLE(*inptr++); + *outptr++ = (JSAMPLE) invalue; + *outptr++ = (JSAMPLE) ((invalue * 3 + GETJSAMPLE(*inptr) + 2) >> 2); + + for (colctr = compptr->downsampled_width - 2; colctr > 0; colctr--) { + /* General case: 3/4 * nearer pixel + 1/4 * further pixel */ + invalue = GETJSAMPLE(*inptr++) * 3; + *outptr++ = (JSAMPLE) ((invalue + GETJSAMPLE(inptr[-2]) + 1) >> 2); + *outptr++ = (JSAMPLE) ((invalue + GETJSAMPLE(*inptr) + 2) >> 2); + } + + /* Special case for last column */ + invalue = GETJSAMPLE(*inptr); + *outptr++ = (JSAMPLE) ((invalue * 3 + GETJSAMPLE(inptr[-1]) + 1) >> 2); + *outptr++ = (JSAMPLE) invalue; + } +} + + +/* + * Fancy processing for the common case of 2:1 horizontal and 2:1 vertical. + * Again a triangle filter; see comments for h2v1 case, above. + * + * It is OK for us to reference the adjacent input rows because we demanded + * context from the main buffer controller (see initialization code). + */ + +METHODDEF(void) +h2v2_fancy_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) +{ + JSAMPARRAY output_data = *output_data_ptr; + register JSAMPROW inptr0, inptr1, outptr; +#if BITS_IN_JSAMPLE == 8 + register int thiscolsum, lastcolsum, nextcolsum; +#else + register INT32 thiscolsum, lastcolsum, nextcolsum; +#endif + register JDIMENSION colctr; + int inrow, outrow, v; + + inrow = outrow = 0; + while (outrow < cinfo->max_v_samp_factor) { + for (v = 0; v < 2; v++) { + /* inptr0 points to nearest input row, inptr1 points to next nearest */ + inptr0 = input_data[inrow]; + if (v == 0) /* next nearest is row above */ + inptr1 = input_data[inrow-1]; + else /* next nearest is row below */ + inptr1 = input_data[inrow+1]; + outptr = output_data[outrow++]; + + /* Special case for first column */ + thiscolsum = GETJSAMPLE(*inptr0++) * 3 + GETJSAMPLE(*inptr1++); + nextcolsum = GETJSAMPLE(*inptr0++) * 3 + GETJSAMPLE(*inptr1++); + *outptr++ = (JSAMPLE) ((thiscolsum * 4 + 8) >> 4); + *outptr++ = (JSAMPLE) ((thiscolsum * 3 + nextcolsum + 7) >> 4); + lastcolsum = thiscolsum; thiscolsum = nextcolsum; + + for (colctr = compptr->downsampled_width - 2; colctr > 0; colctr--) { + /* General case: 3/4 * nearer pixel + 1/4 * further pixel in each */ + /* dimension, thus 9/16, 3/16, 3/16, 1/16 overall */ + nextcolsum = GETJSAMPLE(*inptr0++) * 3 + GETJSAMPLE(*inptr1++); + *outptr++ = (JSAMPLE) ((thiscolsum * 3 + lastcolsum + 8) >> 4); + *outptr++ = (JSAMPLE) ((thiscolsum * 3 + nextcolsum + 7) >> 4); + lastcolsum = thiscolsum; thiscolsum = nextcolsum; + } + + /* Special case for last column */ + *outptr++ = (JSAMPLE) ((thiscolsum * 3 + lastcolsum + 8) >> 4); + *outptr++ = (JSAMPLE) ((thiscolsum * 4 + 7) >> 4); + } + inrow++; + } +} + + +/* + * Module initialization routine for upsampling. + */ + +GLOBAL(void) +jinit_upsampler (j_decompress_ptr cinfo) +{ + my_upsample_ptr upsample; + int ci; + jpeg_component_info * compptr; + boolean need_buffer, do_fancy; + int h_in_group, v_in_group, h_out_group, v_out_group; + + upsample = (my_upsample_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_upsampler)); + cinfo->upsample = (struct jpeg_upsampler *) upsample; + upsample->pub.start_pass = start_pass_upsample; + upsample->pub.upsample = sep_upsample; + upsample->pub.need_context_rows = FALSE; /* until we find out differently */ + + if (cinfo->CCIR601_sampling) /* this isn't supported */ + ERREXIT(cinfo, JERR_CCIR601_NOTIMPL); + + /* jdmainct.c doesn't support context rows when min_codec_data_unit = 1, + * so don't ask for it. + */ + do_fancy = cinfo->do_fancy_upsampling && cinfo->min_codec_data_unit > 1; + + /* Verify we can handle the sampling factors, select per-component methods, + * and create storage as needed. + */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Compute size of an "input group" after IDCT scaling. This many samples + * are to be converted to max_h_samp_factor * max_v_samp_factor pixels. + */ + h_in_group = (compptr->h_samp_factor * compptr->codec_data_unit) / + cinfo->min_codec_data_unit; + v_in_group = (compptr->v_samp_factor * compptr->codec_data_unit) / + cinfo->min_codec_data_unit; + h_out_group = cinfo->max_h_samp_factor; + v_out_group = cinfo->max_v_samp_factor; + upsample->rowgroup_height[ci] = v_in_group; /* save for use later */ + need_buffer = TRUE; + if (! compptr->component_needed) { + /* Don't bother to upsample an uninteresting component. */ + upsample->methods[ci] = noop_upsample; + need_buffer = FALSE; + } else if (h_in_group == h_out_group && v_in_group == v_out_group) { + /* Fullsize components can be processed without any work. */ + upsample->methods[ci] = fullsize_upsample; + need_buffer = FALSE; + } else if (h_in_group * 2 == h_out_group && + v_in_group == v_out_group) { + /* Special cases for 2h1v upsampling */ + if (do_fancy && compptr->downsampled_width > 2) + upsample->methods[ci] = h2v1_fancy_upsample; + else + upsample->methods[ci] = h2v1_upsample; + } else if (h_in_group * 2 == h_out_group && + v_in_group * 2 == v_out_group) { + /* Special cases for 2h2v upsampling */ + if (do_fancy && compptr->downsampled_width > 2) { + upsample->methods[ci] = h2v2_fancy_upsample; + upsample->pub.need_context_rows = TRUE; + } else + upsample->methods[ci] = h2v2_upsample; + } else if ((h_out_group % h_in_group) == 0 && + (v_out_group % v_in_group) == 0) { + /* Generic integral-factors upsampling method */ + upsample->methods[ci] = int_upsample; + upsample->h_expand[ci] = (UINT8) (h_out_group / h_in_group); + upsample->v_expand[ci] = (UINT8) (v_out_group / v_in_group); + } else + ERREXIT(cinfo, JERR_FRACT_SAMPLE_NOTIMPL); + if (need_buffer) { + upsample->color_buf[ci] = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (JDIMENSION) jround_up((long) cinfo->output_width, + (long) cinfo->max_h_samp_factor), + (JDIMENSION) cinfo->max_v_samp_factor); + } + } +} diff --git a/Utilities/ITK/Utilities/itkjpeg/jdscale.c b/Utilities/ITK/Utilities/itkjpeg/jdscale.c new file mode 100644 index 0000000000000000000000000000000000000000..9cdd9b7260ae5a360757647bbccf354ca81b7129 --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jdscale.c @@ -0,0 +1,120 @@ +/* + * jdscale.c + * + * Copyright (C) 1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains sample scaling for lossless JPEG. This is a + * combination of upscaling the undifferenced sample by 2^Pt and downscaling + * the sample to fit into JSAMPLE. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jlossls.h" /* Private declarations for lossless codec */ + + +#ifdef D_LOSSLESS_SUPPORTED + +/* + * Private scaler object for lossless decoding. + */ + +typedef struct { + int scale_factor; +} scaler; + +typedef scaler * scaler_ptr; + + +/* + * Scalers for packing sample differences into JSAMPLEs. + */ + +METHODDEF(void) +simple_upscale(j_decompress_ptr cinfo, + JDIFFROW diff_buf, JSAMPROW output_buf, + JDIMENSION width) +{ + j_lossless_d_ptr losslsd = (j_lossless_d_ptr) cinfo->codec; + scaler_ptr scaler = (scaler_ptr) losslsd->scaler_private; + int scale_factor = scaler->scale_factor; + unsigned int xindex; + + for (xindex = 0; xindex < width; xindex++) + output_buf[xindex] = (JSAMPLE) (diff_buf[xindex] << scale_factor); +} + +METHODDEF(void) +simple_downscale(j_decompress_ptr cinfo, + JDIFFROW diff_buf, JSAMPROW output_buf, + JDIMENSION width) +{ + j_lossless_d_ptr losslsd = (j_lossless_d_ptr) cinfo->codec; + scaler_ptr scaler = (scaler_ptr) losslsd->scaler_private; + int scale_factor = scaler->scale_factor; + unsigned int xindex; + SHIFT_TEMPS + + for (xindex = 0; xindex < width; xindex++) + output_buf[xindex] = (JSAMPLE) RIGHT_SHIFT(diff_buf[xindex], scale_factor); +} + +METHODDEF(void) +noscale(j_decompress_ptr cinfo, + JDIFFROW diff_buf, JSAMPROW output_buf, + JDIMENSION width) +{ + unsigned int xindex; + (void)cinfo; + + for (xindex = 0; xindex < width; xindex++) + output_buf[xindex] = (JSAMPLE) diff_buf[xindex]; +} + + +METHODDEF(void) +scaler_start_pass (j_decompress_ptr cinfo) +{ + j_lossless_d_ptr losslsd = (j_lossless_d_ptr) cinfo->codec; + scaler_ptr scaler = (scaler_ptr) losslsd->scaler_private; + int downscale; + + /* + * Downscale by the difference in the input vs. output precision. If the + * output precision >= input precision, then do not downscale. + */ + downscale = BITS_IN_JSAMPLE < cinfo->data_precision ? + cinfo->data_precision - BITS_IN_JSAMPLE : 0; + + scaler->scale_factor = cinfo->Al - downscale; + + /* Set scaler functions based on scale_factor (positive = left shift) */ + if (scaler->scale_factor > 0) + losslsd->scaler_scale = simple_upscale; + else if (scaler->scale_factor < 0) { + scaler->scale_factor = -scaler->scale_factor; + losslsd->scaler_scale = simple_downscale; + } + else + losslsd->scaler_scale = noscale; +} + + +GLOBAL(void) +jinit_d_scaler (j_decompress_ptr cinfo) +{ + j_lossless_d_ptr losslsd = (j_lossless_d_ptr) cinfo->codec; + scaler_ptr scaler; + + scaler = (scaler_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(scaler)); + losslsd->scaler_private = (void *) scaler; + losslsd->scaler_start_pass = scaler_start_pass; +} + +#endif /* D_LOSSLESS_SUPPORTED */ + diff --git a/Utilities/ITK/Utilities/itkjpeg/jdshuff.c b/Utilities/ITK/Utilities/itkjpeg/jdshuff.c new file mode 100644 index 0000000000000000000000000000000000000000..326220c478714e9ef0b66e072285073bd5a80c67 --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jdshuff.c @@ -0,0 +1,360 @@ +/* + * jdshuff.c + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains Huffman entropy decoding routines for sequential JPEG. + * + * Much of the complexity here has to do with supporting input suspension. + * If the data source module demands suspension, we want to be able to back + * up to the start of the current MCU. To do this, we copy state variables + * into local working storage, and update them back to the permanent + * storage only upon successful completion of an MCU. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jlossy.h" /* Private declarations for lossy codec */ +#include "jdhuff.h" /* Declarations shared with jd*huff.c */ + + +/* + * Private entropy decoder object for Huffman decoding. + * + * The savable_state subrecord contains fields that change within an MCU, + * but must not be updated permanently until we complete the MCU. + */ + +typedef struct { + int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */ +} savable_state; + +/* This macro is to work around compilers with missing or broken + * structure assignment. You'll need to fix this code if you have + * such a compiler and you change MAX_COMPS_IN_SCAN. + */ + +#ifndef NO_STRUCT_ASSIGN +#define ASSIGN_STATE(dest,src) ((dest) = (src)) +#else +#if MAX_COMPS_IN_SCAN == 4 +#define ASSIGN_STATE(dest,src) \ + ((dest).last_dc_val[0] = (src).last_dc_val[0], \ + (dest).last_dc_val[1] = (src).last_dc_val[1], \ + (dest).last_dc_val[2] = (src).last_dc_val[2], \ + (dest).last_dc_val[3] = (src).last_dc_val[3]) +#endif +#endif + + +typedef struct { + huffd_common_fields; /* Fields shared with other entropy decoders */ + + /* These fields are loaded into local variables at start of each MCU. + * In case of suspension, we exit WITHOUT updating them. + */ + savable_state saved; /* Other state at start of MCU */ + + /* These fields are NOT loaded into local working state. */ + unsigned int restarts_to_go; /* MCUs left in this restart interval */ + + /* Pointers to derived tables (these workspaces have image lifespan) */ + d_derived_tbl * dc_derived_tbls[NUM_HUFF_TBLS]; + d_derived_tbl * ac_derived_tbls[NUM_HUFF_TBLS]; + + /* Precalculated info set up by start_pass for use in decode_mcu: */ + + /* Pointers to derived tables to be used for each block within an MCU */ + d_derived_tbl * dc_cur_tbls[D_MAX_DATA_UNITS_IN_MCU]; + d_derived_tbl * ac_cur_tbls[D_MAX_DATA_UNITS_IN_MCU]; + /* Whether we care about the DC and AC coefficient values for each block */ + boolean dc_needed[D_MAX_DATA_UNITS_IN_MCU]; + boolean ac_needed[D_MAX_DATA_UNITS_IN_MCU]; +} shuff_entropy_decoder; + +typedef shuff_entropy_decoder * shuff_entropy_ptr; + + +/* + * Initialize for a Huffman-compressed scan. + */ + +METHODDEF(void) +start_pass_huff_decoder (j_decompress_ptr cinfo) +{ + j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; + shuff_entropy_ptr entropy = (shuff_entropy_ptr) lossyd->entropy_private; + int ci, blkn, dctbl, actbl; + jpeg_component_info * compptr; + + /* Check that the scan parameters Ss, Se, Ah/Al are OK for sequential JPEG. + * This ought to be an error condition, but we make it a warning because + * there are some baseline files out there with all zeroes in these bytes. + */ + if (cinfo->Ss != 0 || cinfo->Se != DCTSIZE2-1 || + cinfo->Ah != 0 || cinfo->Al != 0) + WARNMS(cinfo, JWRN_NOT_SEQUENTIAL); + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + dctbl = compptr->dc_tbl_no; + actbl = compptr->ac_tbl_no; + /* Compute derived values for Huffman tables */ + /* We may do this more than once for a table, but it's not expensive */ + jpeg_make_d_derived_tbl(cinfo, TRUE, dctbl, + & entropy->dc_derived_tbls[dctbl]); + jpeg_make_d_derived_tbl(cinfo, FALSE, actbl, + & entropy->ac_derived_tbls[actbl]); + /* Initialize DC predictions to 0 */ + entropy->saved.last_dc_val[ci] = 0; + } + + /* Precalculate decoding info for each block in an MCU of this scan */ + for (blkn = 0; blkn < cinfo->data_units_in_MCU; blkn++) { + ci = cinfo->MCU_membership[blkn]; + compptr = cinfo->cur_comp_info[ci]; + /* Precalculate which table to use for each block */ + entropy->dc_cur_tbls[blkn] = entropy->dc_derived_tbls[compptr->dc_tbl_no]; + entropy->ac_cur_tbls[blkn] = entropy->ac_derived_tbls[compptr->ac_tbl_no]; + /* Decide whether we really care about the coefficient values */ + if (compptr->component_needed) { + entropy->dc_needed[blkn] = TRUE; + /* we don't need the ACs if producing a 1/8th-size image */ + entropy->ac_needed[blkn] = (compptr->codec_data_unit > 1); + } else { + entropy->dc_needed[blkn] = entropy->ac_needed[blkn] = FALSE; + } + } + + /* Initialize bitread state variables */ + entropy->bitstate.bits_left = 0; + entropy->bitstate.get_buffer = 0; /* unnecessary, but keeps Purify quiet */ + entropy->insufficient_data = FALSE; + + /* Initialize restart counter */ + entropy->restarts_to_go = cinfo->restart_interval; +} + + +/* + * Figure F.12: extend sign bit. + * On some machines, a shift and add will be faster than a table lookup. + */ + +#ifdef AVOID_TABLES + +#define HUFF_EXTEND(x,s) ((x) < (1<<((s)-1)) ? (x) + (((-1)<<(s)) + 1) : (x)) + +#else + +#define HUFF_EXTEND(x,s) ((x) < extend_test[s] ? (x) + extend_offset[s] : (x)) + +static const int extend_test[16] = /* entry n is 2**(n-1) */ + { 0, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080, + 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000 }; + +static const int extend_offset[16] = /* entry n is (-1 << n) + 1 */ + { 0, ((-1)<<1) + 1, ((-1)<<2) + 1, ((-1)<<3) + 1, ((-1)<<4) + 1, + ((-1)<<5) + 1, ((-1)<<6) + 1, ((-1)<<7) + 1, ((-1)<<8) + 1, + ((-1)<<9) + 1, ((-1)<<10) + 1, ((-1)<<11) + 1, ((-1)<<12) + 1, + ((-1)<<13) + 1, ((-1)<<14) + 1, ((-1)<<15) + 1 }; + +#endif /* AVOID_TABLES */ + + +/* + * Check for a restart marker & resynchronize decoder. + * Returns FALSE if must suspend. + */ + +LOCAL(boolean) +process_restart (j_decompress_ptr cinfo) +{ + j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; + shuff_entropy_ptr entropy = (shuff_entropy_ptr) lossyd->entropy_private; + int ci; + + /* Throw away any unused bits remaining in bit buffer; */ + /* include any full bytes in next_marker's count of discarded bytes */ + cinfo->marker->discarded_bytes += entropy->bitstate.bits_left / 8; + entropy->bitstate.bits_left = 0; + + /* Advance past the RSTn marker */ + if (! (*cinfo->marker->read_restart_marker) (cinfo)) + return FALSE; + + /* Re-initialize DC predictions to 0 */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) + entropy->saved.last_dc_val[ci] = 0; + + /* Reset restart counter */ + entropy->restarts_to_go = cinfo->restart_interval; + + /* Reset out-of-data flag, unless read_restart_marker left us smack up + * against a marker. In that case we will end up treating the next data + * segment as empty, and we can avoid producing bogus output pixels by + * leaving the flag set. + */ + if (cinfo->unread_marker == 0) + entropy->insufficient_data = FALSE; + + return TRUE; +} + + +/* + * Decode and return one MCU's worth of Huffman-compressed coefficients. + * The coefficients are reordered from zigzag order into natural array order, + * but are not dequantized. + * + * The i'th block of the MCU is stored into the block pointed to by + * MCU_data[i]. WE ASSUME THIS AREA HAS BEEN ZEROED BY THE CALLER. + * (Wholesale zeroing is usually a little faster than retail...) + * + * Returns FALSE if data source requested suspension. In that case no + * changes have been made to permanent state. (Exception: some output + * coefficients may already have been assigned. This is harmless for + * this module, since we'll just re-assign them on the next call.) + */ + +METHODDEF(boolean) +decode_mcu (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) +{ + j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; + shuff_entropy_ptr entropy = (shuff_entropy_ptr) lossyd->entropy_private; + int blkn; + BITREAD_STATE_VARS; + savable_state state; + + /* Process restart marker if needed; may have to suspend */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) + if (! process_restart(cinfo)) + return FALSE; + } + + /* If we've run out of data, just leave the MCU set to zeroes. + * This way, we return uniform gray for the remainder of the segment. + */ + if (! entropy->insufficient_data) { + + /* Load up working state */ + BITREAD_LOAD_STATE(cinfo,entropy->bitstate); + ASSIGN_STATE(state, entropy->saved); + + /* Outer loop handles each block in the MCU */ + + for (blkn = 0; blkn < cinfo->data_units_in_MCU; blkn++) { + JBLOCKROW block = MCU_data[blkn]; + d_derived_tbl * dctbl = entropy->dc_cur_tbls[blkn]; + d_derived_tbl * actbl = entropy->ac_cur_tbls[blkn]; + register int s, k, r; + + /* Decode a single block's worth of coefficients */ + + /* Section F.2.2.1: decode the DC coefficient difference */ + HUFF_DECODE(s, br_state, dctbl, return FALSE, label1); + if (s) { + CHECK_BIT_BUFFER(br_state, s, return FALSE); + r = GET_BITS(s); + s = HUFF_EXTEND(r, s); + } + + if (entropy->dc_needed[blkn]) { + /* Convert DC difference to actual value, update last_dc_val */ + int ci = cinfo->MCU_membership[blkn]; + s += state.last_dc_val[ci]; + state.last_dc_val[ci] = s; + /* Output the DC coefficient (assumes jpeg_natural_order[0] = 0) */ + (*block)[0] = (JCOEF) s; + } + + if (entropy->ac_needed[blkn]) { + + /* Section F.2.2.2: decode the AC coefficients */ + /* Since zeroes are skipped, output area must be cleared beforehand */ + for (k = 1; k < DCTSIZE2; k++) { + HUFF_DECODE(s, br_state, actbl, return FALSE, label2); + + r = s >> 4; + s &= 15; + + if (s) { + k += r; + CHECK_BIT_BUFFER(br_state, s, return FALSE); + r = GET_BITS(s); + s = HUFF_EXTEND(r, s); + /* Output coefficient in natural (dezigzagged) order. + * Note: the extra entries in jpeg_natural_order[] will save us + * if k >= DCTSIZE2, which could happen if the data is corrupted. + */ + (*block)[jpeg_natural_order[k]] = (JCOEF) s; + } else { + if (r != 15) + break; + k += 15; + } + } + + } else { + + /* Section F.2.2.2: decode the AC coefficients */ + /* In this path we just discard the values */ + for (k = 1; k < DCTSIZE2; k++) { + HUFF_DECODE(s, br_state, actbl, return FALSE, label3); + + r = s >> 4; + s &= 15; + + if (s) { + k += r; + CHECK_BIT_BUFFER(br_state, s, return FALSE); + DROP_BITS(s); + } else { + if (r != 15) + break; + k += 15; + } + } + + } + } + + /* Completed MCU, so update state */ + BITREAD_SAVE_STATE(cinfo,entropy->bitstate); + ASSIGN_STATE(entropy->saved, state); + } + + /* Account for restart interval (no-op if not using restarts) */ + entropy->restarts_to_go--; + + return TRUE; +} + + +/* + * Module initialization routine for Huffman entropy decoding. + */ + +GLOBAL(void) +jinit_shuff_decoder (j_decompress_ptr cinfo) +{ + j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec; + shuff_entropy_ptr entropy; + int i; + + entropy = (shuff_entropy_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(shuff_entropy_decoder)); + lossyd->entropy_private = (void *) entropy; + lossyd->entropy_start_pass = start_pass_huff_decoder; + lossyd->entropy_decode_mcu = decode_mcu; + + /* Mark tables unallocated */ + for (i = 0; i < NUM_HUFF_TBLS; i++) { + entropy->dc_derived_tbls[i] = entropy->ac_derived_tbls[i] = NULL; + } +} diff --git a/Utilities/ITK/Utilities/itkjpeg/jdtrans.c b/Utilities/ITK/Utilities/itkjpeg/jdtrans.c new file mode 100644 index 0000000000000000000000000000000000000000..af35263c67a40c75caaf4c95460521626c9cffbb --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jdtrans.c @@ -0,0 +1,138 @@ +/* + * jdtrans.c + * + * Copyright (C) 1995-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains library routines for transcoding decompression, + * that is, reading raw DCT coefficient arrays from an input JPEG file. + * The routines in jdapimin.c will also be needed by a transcoder. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jlossy.h" + + +/* Forward declarations */ +LOCAL(void) transdecode_master_selection JPP((j_decompress_ptr cinfo)); + + +/* + * Read the coefficient arrays from a JPEG file. + * jpeg_read_header must be completed before calling this. + * + * The entire image is read into a set of virtual coefficient-block arrays, + * one per component. The return value is a pointer to the array of + * virtual-array descriptors. These can be manipulated directly via the + * JPEG memory manager, or handed off to jpeg_write_coefficients(). + * To release the memory occupied by the virtual arrays, call + * jpeg_finish_decompress() when done with the data. + * + * An alternative usage is to simply obtain access to the coefficient arrays + * during a buffered-image-mode decompression operation. This is allowed + * after any jpeg_finish_output() call. The arrays can be accessed until + * jpeg_finish_decompress() is called. (Note that any call to the library + * may reposition the arrays, so don't rely on access_virt_barray() results + * to stay valid across library calls.) + * + * Returns NULL if suspended. This case need be checked only if + * a suspending data source is used. + */ + +GLOBAL(jvirt_barray_ptr *) +jpeg_read_coefficients (j_decompress_ptr cinfo) +{ + /* j_lossy_d_ptr decomp; */ + + /* Can't read coefficients from lossless streams */ + if (cinfo->process == JPROC_LOSSLESS) { + ERREXIT(cinfo, JERR_CANT_TRANSCODE); + return NULL; + } + + if (cinfo->global_state == DSTATE_READY) { + /* First call: initialize active modules */ + transdecode_master_selection(cinfo); + cinfo->global_state = DSTATE_RDCOEFS; + } + if (cinfo->global_state == DSTATE_RDCOEFS) { + /* Absorb whole file into the coef buffer */ + for (;;) { + int retcode; + /* Call progress monitor hook if present */ + if (cinfo->progress != NULL) + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + /* Absorb some more input */ + retcode = (*cinfo->inputctl->consume_input) (cinfo); + if (retcode == JPEG_SUSPENDED) + return NULL; + if (retcode == JPEG_REACHED_EOI) + break; + /* Advance progress counter if appropriate */ + if (cinfo->progress != NULL && + (retcode == JPEG_ROW_COMPLETED || retcode == JPEG_REACHED_SOS)) { + if (++cinfo->progress->pass_counter >= cinfo->progress->pass_limit) { + /* startup underestimated number of scans; ratchet up one scan */ + cinfo->progress->pass_limit += (long) cinfo->total_iMCU_rows; + } + } + } + /* Set state so that jpeg_finish_decompress does the right thing */ + cinfo->global_state = DSTATE_STOPPING; + } + /* At this point we should be in state DSTATE_STOPPING if being used + * standalone, or in state DSTATE_BUFIMAGE if being invoked to get access + * to the coefficients during a full buffered-image-mode decompression. + */ + if ((cinfo->global_state == DSTATE_STOPPING || + cinfo->global_state == DSTATE_BUFIMAGE) && cinfo->buffered_image) { + return ((j_lossy_d_ptr) cinfo->codec)->coef_arrays; + } + /* Oops, improper usage */ + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + return NULL; /* keep compiler happy */ +} + + +/* + * Master selection of decompression modules for transcoding. + * This substitutes for jdmaster.c's initialization of the full decompressor. + */ + +LOCAL(void) +transdecode_master_selection (j_decompress_ptr cinfo) +{ + /* This is effectively a buffered-image operation. */ + cinfo->buffered_image = TRUE; + + /* Initialize decompression codec */ + jinit_d_codec(cinfo); + + /* We can now tell the memory manager to allocate virtual arrays. */ + (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo); + + /* Initialize input side of decompressor to consume first scan. */ + (*cinfo->inputctl->start_input_pass) (cinfo); + + /* Initialize progress monitoring. */ + if (cinfo->progress != NULL) { + int nscans; + /* Estimate number of scans to set pass_limit. */ + if (cinfo->process == JPROC_PROGRESSIVE) { + /* Arbitrarily estimate 2 interleaved DC scans + 3 AC scans/component. */ + nscans = 2 + 3 * cinfo->num_components; + } else if (cinfo->inputctl->has_multiple_scans) { + /* For a nonprogressive multiscan file, estimate 1 scan per component. */ + nscans = cinfo->num_components; + } else { + nscans = 1; + } + cinfo->progress->pass_counter = 0L; + cinfo->progress->pass_limit = (long) cinfo->total_iMCU_rows * nscans; + cinfo->progress->completed_passes = 0; + cinfo->progress->total_passes = 1; + } +} diff --git a/Utilities/ITK/Utilities/itkjpeg/jerror.c b/Utilities/ITK/Utilities/itkjpeg/jerror.c new file mode 100644 index 0000000000000000000000000000000000000000..4e6e2e3515488c58c644fbef1e9eb22d38d0e5c3 --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jerror.c @@ -0,0 +1,252 @@ +/* + * jerror.c + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains simple error-reporting and trace-message routines. + * These are suitable for Unix-like systems and others where writing to + * stderr is the right thing to do. Many applications will want to replace + * some or all of these routines. + * + * If you define USE_WINDOWS_MESSAGEBOX in jconfig.h or in the makefile, + * you get a Windows-specific hack to display error messages in a dialog box. + * It ain't much, but it beats dropping error messages into the bit bucket, + * which is what happens to output to stderr under most Windows C compilers. + * + * These routines are used by both the compression and decompression code. + */ + +/* this is not a core library module, so it doesn't define JPEG_INTERNALS */ +#include "jinclude.h" +#include "jpeglib.h" +#include "jversion.h" +#include "jerror.h" + +#ifdef USE_WINDOWS_MESSAGEBOX +#include <windows.h> +#endif + +#ifndef EXIT_FAILURE /* define exit() codes if not provided */ +#define EXIT_FAILURE 1 +#endif + + +/* + * Create the message string table. + * We do this from the master message list in jerror.h by re-reading + * jerror.h with a suitable definition for macro JMESSAGE. + * The message table is made an external symbol just in case any applications + * want to refer to it directly. + */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_std_message_table jMsgTable +#endif + +#define JMESSAGE(code,string) string , + +const char * const jpeg_std_message_table[] = { +#include "jerror.h" + NULL +}; + + +/* + * Error exit handler: must not return to caller. + * + * Applications may override this if they want to get control back after + * an error. Typically one would longjmp somewhere instead of exiting. + * The setjmp buffer can be made a private field within an expanded error + * handler object. Note that the info needed to generate an error message + * is stored in the error object, so you can generate the message now or + * later, at your convenience. + * You should make sure that the JPEG object is cleaned up (with jpeg_abort + * or jpeg_destroy) at some point. + */ + +METHODDEF(void) +error_exit (j_common_ptr cinfo) +{ + /* Always display the message */ + (*cinfo->err->output_message) (cinfo); + + /* Let the memory manager delete any temp files before we die */ + jpeg_destroy(cinfo); + + exit(EXIT_FAILURE); +} + + +/* + * Actual output of an error or trace message. + * Applications may override this method to send JPEG messages somewhere + * other than stderr. + * + * On Windows, printing to stderr is generally completely useless, + * so we provide optional code to produce an error-dialog popup. + * Most Windows applications will still prefer to override this routine, + * but if they don't, it'll do something at least marginally useful. + * + * NOTE: to use the library in an environment that doesn't support the + * C stdio library, you may have to delete the call to fprintf() entirely, + * not just not use this routine. + */ + +METHODDEF(void) +output_message (j_common_ptr cinfo) +{ + char buffer[JMSG_LENGTH_MAX]; + + /* Create the message */ + (*cinfo->err->format_message) (cinfo, buffer); + +#ifdef USE_WINDOWS_MESSAGEBOX + /* Display it in a message dialog box */ + MessageBox(GetActiveWindow(), buffer, "JPEG Library Error", + MB_OK | MB_ICONERROR); +#else + /* Send it to stderr, adding a newline */ + fprintf(stderr, "%s\n", buffer); +#endif +} + + +/* + * Decide whether to emit a trace or warning message. + * msg_level is one of: + * -1: recoverable corrupt-data warning, may want to abort. + * 0: important advisory messages (always display to user). + * 1: first level of tracing detail. + * 2,3,...: successively more detailed tracing messages. + * An application might override this method if it wanted to abort on warnings + * or change the policy about which messages to display. + */ + +METHODDEF(void) +emit_message (j_common_ptr cinfo, int msg_level) +{ + struct jpeg_error_mgr * err = cinfo->err; + + if (msg_level < 0) { + /* It's a warning message. Since corrupt files may generate many warnings, + * the policy implemented here is to show only the first warning, + * unless trace_level >= 3. + */ + if (err->num_warnings == 0 || err->trace_level >= 3) + (*err->output_message) (cinfo); + /* Always count warnings in num_warnings. */ + err->num_warnings++; + } else { + /* It's a trace message. Show it if trace_level >= msg_level. */ + if (err->trace_level >= msg_level) + (*err->output_message) (cinfo); + } +} + + +/* + * Format a message string for the most recent JPEG error or message. + * The message is stored into buffer, which should be at least JMSG_LENGTH_MAX + * characters. Note that no '\n' character is added to the string. + * Few applications should need to override this method. + */ + +METHODDEF(void) +format_message (j_common_ptr cinfo, char * buffer) +{ + struct jpeg_error_mgr * err = cinfo->err; + int msg_code = err->msg_code; + const char * msgtext = NULL; + const char * msgptr; + char ch; + boolean isstring; + + /* Look up message string in proper table */ + if (msg_code > 0 && msg_code <= err->last_jpeg_message) { + msgtext = err->jpeg_message_table[msg_code]; + } else if (err->addon_message_table != NULL && + msg_code >= err->first_addon_message && + msg_code <= err->last_addon_message) { + msgtext = err->addon_message_table[msg_code - err->first_addon_message]; + } + + /* Defend against bogus message number */ + if (msgtext == NULL) { + err->msg_parm.i[0] = msg_code; + msgtext = err->jpeg_message_table[0]; + } + + /* Check for string parameter, as indicated by %s in the message text */ + isstring = FALSE; + msgptr = msgtext; + while ((ch = *msgptr++) != '\0') { + if (ch == '%') { + if (*msgptr == 's') isstring = TRUE; + break; + } + } + + /* Format the message into the passed buffer */ + if (isstring) + sprintf(buffer, msgtext, err->msg_parm.s); + else + sprintf(buffer, msgtext, + err->msg_parm.i[0], err->msg_parm.i[1], + err->msg_parm.i[2], err->msg_parm.i[3], + err->msg_parm.i[4], err->msg_parm.i[5], + err->msg_parm.i[6], err->msg_parm.i[7]); +} + + +/* + * Reset error state variables at start of a new image. + * This is called during compression startup to reset trace/error + * processing to default state, without losing any application-specific + * method pointers. An application might possibly want to override + * this method if it has additional error processing state. + */ + +METHODDEF(void) +reset_error_mgr (j_common_ptr cinfo) +{ + cinfo->err->num_warnings = 0; + /* trace_level is not reset since it is an application-supplied parameter */ + cinfo->err->msg_code = 0; /* may be useful as a flag for "no error" */ +} + + +/* + * Fill in the standard error-handling methods in a jpeg_error_mgr object. + * Typical call is: + * struct jpeg_compress_struct cinfo; + * struct jpeg_error_mgr err; + * + * cinfo.err = jpeg_std_error(&err); + * after which the application may override some of the methods. + */ + +GLOBAL(struct jpeg_error_mgr *) +jpeg_std_error (struct jpeg_error_mgr * err) +{ + err->error_exit = error_exit; + err->emit_message = emit_message; + err->output_message = output_message; + err->format_message = format_message; + err->reset_error_mgr = reset_error_mgr; + + err->trace_level = 0; /* default = no tracing */ + err->num_warnings = 0; /* no warnings emitted yet */ + err->msg_code = 0; /* may be useful as a flag for "no error" */ + + /* Initialize message table pointers */ + err->jpeg_message_table = jpeg_std_message_table; + err->last_jpeg_message = (int) JMSG_LASTMSGCODE - 1; + + err->addon_message_table = NULL; + err->first_addon_message = 0; /* for safety */ + err->last_addon_message = 0; + + return err; +} diff --git a/Utilities/ITK/Utilities/itkjpeg/jerror.h b/Utilities/ITK/Utilities/itkjpeg/jerror.h new file mode 100644 index 0000000000000000000000000000000000000000..d48ccfad091abac941478777fa4f0e10efbace4d --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jerror.h @@ -0,0 +1,306 @@ +/* + * jerror.h + * + * Copyright (C) 1994-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file defines the error and message codes for the JPEG library. + * Edit this file to add new codes, or to translate the message strings to + * some other language. + * A set of error-reporting macros are defined too. Some applications using + * the JPEG library may wish to include this file to get the error codes + * and/or the macros. + */ + +/* + * To define the enum list of message codes, include this file without + * defining macro JMESSAGE. To create a message string table, include it + * again with a suitable JMESSAGE definition (see jerror.c for an example). + */ +#ifndef JMESSAGE +#ifndef JERROR_H +/* First time through, define the enum list */ +#define JMAKE_ENUM_LIST +#else +/* Repeated inclusions of this file are no-ops unless JMESSAGE is defined */ +#define JMESSAGE(code,string) +#endif /* JERROR_H */ +#endif /* JMESSAGE */ + +#ifdef JMAKE_ENUM_LIST + +typedef enum { + +#define JMESSAGE(code,string) code , + +#endif /* JMAKE_ENUM_LIST */ + +JMESSAGE(JMSG_NOMESSAGE, "Bogus message code %d") /* Must be first entry! */ + +/* For maintenance convenience, list is alphabetical by message code name */ +JMESSAGE(JERR_ARITH_NOTIMPL, + "Sorry, there are legal restrictions on arithmetic coding") +JMESSAGE(JERR_BAD_ALIGN_TYPE, "ALIGN_TYPE is wrong, please fix") +JMESSAGE(JERR_BAD_ALLOC_CHUNK, "MAX_ALLOC_CHUNK is wrong, please fix") +JMESSAGE(JERR_BAD_BUFFER_MODE, "Bogus buffer control mode") +JMESSAGE(JERR_BAD_COMPONENT_ID, "Invalid component ID %d in SOS") +JMESSAGE(JERR_BAD_DCT_COEF, "DCT coefficient out of range") +JMESSAGE(JERR_BAD_DCTSIZE, "IDCT output block size %d not supported") +JMESSAGE(JERR_BAD_DIFF, "spatial difference out of range") +JMESSAGE(JERR_BAD_HUFF_TABLE, "Bogus Huffman table definition") +JMESSAGE(JERR_BAD_IN_COLORSPACE, "Bogus input colorspace") +JMESSAGE(JERR_BAD_J_COLORSPACE, "Bogus JPEG colorspace") +JMESSAGE(JERR_BAD_LENGTH, "Bogus marker length") +JMESSAGE(JERR_BAD_LIB_VERSION, + "Wrong JPEG library version: library is %d, caller expects %d") +JMESSAGE(JERR_BAD_LOSSLESS, + "Invalid lossless parameters Ss=%d Se=%d Ah=%d Al=%d") +JMESSAGE(JERR_BAD_LOSSLESS_SCRIPT, + "Invalid lossless parameters at scan script entry %d") +JMESSAGE(JERR_BAD_MCU_SIZE, "Sampling factors too large for interleaved scan") +JMESSAGE(JERR_BAD_POOL_ID, "Invalid memory pool code %d") +JMESSAGE(JERR_BAD_PRECISION, "Unsupported JPEG data precision %d") +JMESSAGE(JERR_BAD_PROGRESSION, + "Invalid progressive parameters Ss=%d Se=%d Ah=%d Al=%d") +JMESSAGE(JERR_BAD_PROG_SCRIPT, + "Invalid progressive parameters at scan script entry %d") +JMESSAGE(JERR_BAD_RESTART, "Invalid restart interval: %d, must be an integer multiple of the number of MCUs in an MCU_row (%d)") +JMESSAGE(JERR_BAD_SAMPLING, "Bogus sampling factors") +JMESSAGE(JERR_BAD_SCAN_SCRIPT, "Invalid scan script at entry %d") +JMESSAGE(JERR_BAD_STATE, "Improper call to JPEG library in state %d") +JMESSAGE(JERR_BAD_STRUCT_SIZE, + "JPEG parameter struct mismatch: library thinks size is %u, caller expects %u") +JMESSAGE(JERR_BAD_VIRTUAL_ACCESS, "Bogus virtual array access") +JMESSAGE(JERR_BUFFER_SIZE, "Buffer passed to JPEG library is too small") +JMESSAGE(JERR_CANT_SUSPEND, "Suspension not allowed here") +JMESSAGE(JERR_CANT_TRANSCODE, + "Cannot transcode to/from lossless JPEG datastreams") +JMESSAGE(JERR_CCIR601_NOTIMPL, "CCIR601 sampling not implemented yet") +JMESSAGE(JERR_COMPONENT_COUNT, "Too many color components: %d, max %d") +JMESSAGE(JERR_CONVERSION_NOTIMPL, "Unsupported color conversion request") +JMESSAGE(JERR_DAC_INDEX, "Bogus DAC index %d") +JMESSAGE(JERR_DAC_VALUE, "Bogus DAC value 0x%x") +JMESSAGE(JERR_DHT_INDEX, "Bogus DHT index %d") +JMESSAGE(JERR_DQT_INDEX, "Bogus DQT index %d") +JMESSAGE(JERR_EMPTY_IMAGE, "Empty JPEG image (DNL not supported)") +JMESSAGE(JERR_EMS_READ, "Read from EMS failed") +JMESSAGE(JERR_EMS_WRITE, "Write to EMS failed") +JMESSAGE(JERR_EOI_EXPECTED, "Didn't expect more than one scan") +JMESSAGE(JERR_FILE_READ, "Input file read error") +JMESSAGE(JERR_FILE_WRITE, "Output file write error --- out of disk space?") +JMESSAGE(JERR_FRACT_SAMPLE_NOTIMPL, "Fractional sampling not implemented yet") +JMESSAGE(JERR_HUFF_CLEN_OVERFLOW, "Huffman code size table overflow") +JMESSAGE(JERR_HUFF_MISSING_CODE, "Missing Huffman code table entry") +JMESSAGE(JERR_IMAGE_TOO_BIG, "Maximum supported image dimension is %u pixels") +JMESSAGE(JERR_INPUT_EMPTY, "Empty input file") +JMESSAGE(JERR_INPUT_EOF, "Premature end of input file") +JMESSAGE(JERR_MISMATCHED_QUANT_TABLE, + "Cannot transcode due to multiple use of quantization table %d") +JMESSAGE(JERR_MISSING_DATA, "Scan script does not transmit all data") +JMESSAGE(JERR_MODE_CHANGE, "Invalid color quantization mode change") +JMESSAGE(JERR_NOTIMPL, "Not implemented yet") +JMESSAGE(JERR_NOT_COMPILED, "Requested feature was omitted at compile time") +JMESSAGE(JERR_NO_ARITH_TABLE, "Arithmetic table 0x%02x was not defined") +JMESSAGE(JERR_NO_BACKING_STORE, "Backing store not supported") +JMESSAGE(JERR_NO_HUFF_TABLE, "Huffman table 0x%02x was not defined") +JMESSAGE(JERR_NO_IMAGE, "JPEG datastream contains no image") +JMESSAGE(JERR_NO_LOSSLESS_SCRIPT, "Lossless encoding was requested but no scan script was supplied") +JMESSAGE(JERR_NO_QUANT_TABLE, "Quantization table 0x%02x was not defined") +JMESSAGE(JERR_NO_SOI, "Not a JPEG file: starts with 0x%02x 0x%02x") +JMESSAGE(JERR_OUT_OF_MEMORY, "Insufficient memory (case %d)") +JMESSAGE(JERR_QUANT_COMPONENTS, + "Cannot quantize more than %d color components") +JMESSAGE(JERR_QUANT_FEW_COLORS, "Cannot quantize to fewer than %d colors") +JMESSAGE(JERR_QUANT_MANY_COLORS, "Cannot quantize to more than %d colors") +JMESSAGE(JERR_SOF_DUPLICATE, "Invalid JPEG file structure: two SOF markers") +JMESSAGE(JERR_SOF_NO_SOS, "Invalid JPEG file structure: missing SOS marker") +JMESSAGE(JERR_SOF_UNSUPPORTED, "Unsupported JPEG process: SOF type 0x%02x") +JMESSAGE(JERR_SOI_DUPLICATE, "Invalid JPEG file structure: two SOI markers") +JMESSAGE(JERR_SOS_NO_SOF, "Invalid JPEG file structure: SOS before SOF") +JMESSAGE(JERR_TFILE_CREATE, "Failed to create temporary file %s") +JMESSAGE(JERR_TFILE_READ, "Read failed on temporary file") +JMESSAGE(JERR_TFILE_SEEK, "Seek failed on temporary file") +JMESSAGE(JERR_TFILE_WRITE, + "Write failed on temporary file --- out of disk space?") +JMESSAGE(JERR_TOO_LITTLE_DATA, "Application transferred too few scanlines") +JMESSAGE(JERR_UNKNOWN_MARKER, "Unsupported marker type 0x%02x") +JMESSAGE(JERR_VIRTUAL_BUG, "Virtual array controller messed up") +JMESSAGE(JERR_WIDTH_OVERFLOW, "Image too wide for this implementation") +JMESSAGE(JERR_XMS_READ, "Read from XMS failed") +JMESSAGE(JERR_XMS_WRITE, "Write to XMS failed") +JMESSAGE(JMSG_COPYRIGHT, JCOPYRIGHT) +JMESSAGE(JMSG_VERSION, JVERSION) +JMESSAGE(JTRC_16BIT_TABLES, + "Caution: quantization tables are too coarse for baseline JPEG") +JMESSAGE(JTRC_ADOBE, + "Adobe APP14 marker: version %d, flags 0x%04x 0x%04x, transform %d") +JMESSAGE(JTRC_APP0, "Unknown APP0 marker (not JFIF), length %u") +JMESSAGE(JTRC_APP14, "Unknown APP14 marker (not Adobe), length %u") +JMESSAGE(JTRC_DAC, "Define Arithmetic Table 0x%02x: 0x%02x") +JMESSAGE(JTRC_DHT, "Define Huffman Table 0x%02x") +JMESSAGE(JTRC_DQT, "Define Quantization Table %d precision %d") +JMESSAGE(JTRC_DRI, "Define Restart Interval %u") +JMESSAGE(JTRC_EMS_CLOSE, "Freed EMS handle %u") +JMESSAGE(JTRC_EMS_OPEN, "Obtained EMS handle %u") +JMESSAGE(JTRC_EOI, "End Of Image") +JMESSAGE(JTRC_HUFFBITS, " %3d %3d %3d %3d %3d %3d %3d %3d") +JMESSAGE(JTRC_JFIF, "JFIF APP0 marker: version %d.%02d, density %dx%d %d") +JMESSAGE(JTRC_JFIF_BADTHUMBNAILSIZE, + "Warning: thumbnail image size does not match data length %u") +JMESSAGE(JTRC_JFIF_EXTENSION, + "JFIF extension marker: type 0x%02x, length %u") +JMESSAGE(JTRC_JFIF_THUMBNAIL, " with %d x %d thumbnail image") +JMESSAGE(JTRC_MISC_MARKER, "Miscellaneous marker 0x%02x, length %u") +JMESSAGE(JTRC_PARMLESS_MARKER, "Unexpected marker 0x%02x") +JMESSAGE(JTRC_QUANTVALS, " %4u %4u %4u %4u %4u %4u %4u %4u") +JMESSAGE(JTRC_QUANT_3_NCOLORS, "Quantizing to %d = %d*%d*%d colors") +JMESSAGE(JTRC_QUANT_NCOLORS, "Quantizing to %d colors") +JMESSAGE(JTRC_QUANT_SELECTED, "Selected %d colors for quantization") +JMESSAGE(JTRC_RECOVERY_ACTION, "At marker 0x%02x, recovery action %d") +JMESSAGE(JTRC_RST, "RST%d") +JMESSAGE(JTRC_SMOOTH_NOTIMPL, + "Smoothing not supported with nonstandard sampling ratios") +JMESSAGE(JTRC_SOF, "Start Of Frame 0x%02x: width=%u, height=%u, components=%d") +JMESSAGE(JTRC_SOF_COMPONENT, " Component %d: %dhx%dv q=%d") +JMESSAGE(JTRC_SOI, "Start of Image") +JMESSAGE(JTRC_SOS, "Start Of Scan: %d components") +JMESSAGE(JTRC_SOS_COMPONENT, " Component %d: dc=%d ac=%d") +JMESSAGE(JTRC_SOS_PARAMS, " Ss=%d, Se=%d, Ah=%d, Al=%d") +JMESSAGE(JTRC_TFILE_CLOSE, "Closed temporary file %s") +JMESSAGE(JTRC_TFILE_OPEN, "Opened temporary file %s") +JMESSAGE(JTRC_THUMB_JPEG, + "JFIF extension marker: JPEG-compressed thumbnail image, length %u") +JMESSAGE(JTRC_THUMB_PALETTE, + "JFIF extension marker: palette thumbnail image, length %u") +JMESSAGE(JTRC_THUMB_RGB, + "JFIF extension marker: RGB thumbnail image, length %u") +JMESSAGE(JTRC_UNKNOWN_LOSSLESS_IDS, + "Unrecognized component IDs %d %d %d, assuming RGB") +JMESSAGE(JTRC_UNKNOWN_LOSSY_IDS, + "Unrecognized component IDs %d %d %d, assuming YCbCr") +JMESSAGE(JTRC_XMS_CLOSE, "Freed XMS handle %u") +JMESSAGE(JTRC_XMS_OPEN, "Obtained XMS handle %u") +JMESSAGE(JWRN_ADOBE_XFORM, "Unknown Adobe color transform code %d") +JMESSAGE(JWRN_ARITH_BAD_CODE, "Corrupt JPEG data: bad arithmetic code") +JMESSAGE(JWRN_BOGUS_PROGRESSION, + "Inconsistent progression sequence for component %d coefficient %d") +JMESSAGE(JWRN_EXTRANEOUS_DATA, + "Corrupt JPEG data: %u extraneous bytes before marker 0x%02x") +JMESSAGE(JWRN_HIT_MARKER, "Corrupt JPEG data: premature end of data segment") +JMESSAGE(JWRN_HUFF_BAD_CODE, "Corrupt JPEG data: bad Huffman code") +JMESSAGE(JWRN_JFIF_MAJOR, "Warning: unknown JFIF revision number %d.%02d") +JMESSAGE(JWRN_JPEG_EOF, "Premature end of JPEG file") +JMESSAGE(JWRN_MUST_DOWNSCALE, + "Must downscale data from %d bits to %d") +JMESSAGE(JWRN_MUST_RESYNC, + "Corrupt JPEG data: found marker 0x%02x instead of RST%d") +JMESSAGE(JWRN_NOT_SEQUENTIAL, "Invalid SOS parameters for sequential JPEG") +JMESSAGE(JWRN_TOO_MUCH_DATA, "Application transferred too many scanlines") + +#ifdef JMAKE_ENUM_LIST + + JMSG_LASTMSGCODE +} J_MESSAGE_CODE; + +#undef JMAKE_ENUM_LIST +#endif /* JMAKE_ENUM_LIST */ + +/* Zap JMESSAGE macro so that future re-inclusions do nothing by default */ +#undef JMESSAGE + + +#ifndef JERROR_H +#define JERROR_H + +/* Macros to simplify using the error and trace message stuff */ +/* The first parameter is either type of cinfo pointer */ + +/* Fatal errors (print message and exit) */ +#define ERREXIT(cinfo,code) \ + ((cinfo)->err->msg_code = (code), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXIT1(cinfo,code,p1) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXIT2(cinfo,code,p1,p2) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXIT3(cinfo,code,p1,p2,p3) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (cinfo)->err->msg_parm.i[2] = (p3), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXIT4(cinfo,code,p1,p2,p3,p4) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (cinfo)->err->msg_parm.i[2] = (p3), \ + (cinfo)->err->msg_parm.i[3] = (p4), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXITS(cinfo,code,str) \ + ((cinfo)->err->msg_code = (code), \ + strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) + +#define MAKESTMT(stuff) do { stuff } while (0) + +/* Nonfatal errors (we can keep going, but the data is probably corrupt) */ +#define WARNMS(cinfo,code) \ + ((cinfo)->err->msg_code = (code), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1)) +#define WARNMS1(cinfo,code,p1) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1)) +#define WARNMS2(cinfo,code,p1,p2) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1)) + +/* Informational/debugging messages */ +#define TRACEMS(cinfo,lvl,code) \ + ((cinfo)->err->msg_code = (code), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) +#define TRACEMS1(cinfo,lvl,code,p1) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) +#define TRACEMS2(cinfo,lvl,code,p1,p2) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) +#define TRACEMS3(cinfo,lvl,code,p1,p2,p3) \ + MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ + _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); \ + (cinfo)->err->msg_code = (code); \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) +#define TRACEMS4(cinfo,lvl,code,p1,p2,p3,p4) \ + MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ + _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \ + (cinfo)->err->msg_code = (code); \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) +#define TRACEMS5(cinfo,lvl,code,p1,p2,p3,p4,p5) \ + MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ + _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \ + _mp[4] = (p5); \ + (cinfo)->err->msg_code = (code); \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) +#define TRACEMS8(cinfo,lvl,code,p1,p2,p3,p4,p5,p6,p7,p8) \ + MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ + _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \ + _mp[4] = (p5); _mp[5] = (p6); _mp[6] = (p7); _mp[7] = (p8); \ + (cinfo)->err->msg_code = (code); \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) +#define TRACEMSS(cinfo,lvl,code,str) \ + ((cinfo)->err->msg_code = (code), \ + strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) + +#endif /* JERROR_H */ diff --git a/Utilities/ITK/Utilities/itkjpeg/jfdctflt.c b/Utilities/ITK/Utilities/itkjpeg/jfdctflt.c new file mode 100644 index 0000000000000000000000000000000000000000..f0297a2580ca118b6c8fc6c8e9d415f0306a7078 --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jfdctflt.c @@ -0,0 +1,168 @@ +/* + * jfdctflt.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains a floating-point implementation of the + * forward DCT (Discrete Cosine Transform). + * + * This implementation should be more accurate than either of the integer + * DCT implementations. However, it may not give the same results on all + * machines because of differences in roundoff behavior. Speed will depend + * on the hardware's floating point capacity. + * + * A 2-D DCT can be done by 1-D DCT on each row followed by 1-D DCT + * on each column. Direct algorithms are also available, but they are + * much more complex and seem not to be any faster when reduced to code. + * + * This implementation is based on Arai, Agui, and Nakajima's algorithm for + * scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in + * Japanese, but the algorithm is described in the Pennebaker & Mitchell + * JPEG textbook (see REFERENCES section in file README). The following code + * is based directly on figure 4-8 in P&M. + * While an 8-point DCT cannot be done in less than 11 multiplies, it is + * possible to arrange the computation so that many of the multiplies are + * simple scalings of the final outputs. These multiplies can then be + * folded into the multiplications or divisions by the JPEG quantization + * table entries. The AA&N method leaves only 5 multiplies and 29 adds + * to be done in the DCT itself. + * The primary disadvantage of this method is that with a fixed-point + * implementation, accuracy is lost due to imprecise representation of the + * scaled quantization values. However, that problem does not arise if + * we use floating point arithmetic. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdct.h" /* Private declarations for DCT subsystem */ + +#ifdef DCT_FLOAT_SUPPORTED + + +/* + * This module is specialized to the case DCTSIZE = 8. + */ + +#if DCTSIZE != 8 + Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */ +#endif + + +/* + * Perform the forward DCT on one block of samples. + */ + +GLOBAL(void) +jpeg_fdct_float (FAST_FLOAT * data) +{ + FAST_FLOAT tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + FAST_FLOAT tmp10, tmp11, tmp12, tmp13; + FAST_FLOAT z1, z2, z3, z4, z5, z11, z13; + FAST_FLOAT *dataptr; + int ctr; + + /* Pass 1: process rows. */ + + dataptr = data; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + tmp0 = dataptr[0] + dataptr[7]; + tmp7 = dataptr[0] - dataptr[7]; + tmp1 = dataptr[1] + dataptr[6]; + tmp6 = dataptr[1] - dataptr[6]; + tmp2 = dataptr[2] + dataptr[5]; + tmp5 = dataptr[2] - dataptr[5]; + tmp3 = dataptr[3] + dataptr[4]; + tmp4 = dataptr[3] - dataptr[4]; + + /* Even part */ + + tmp10 = tmp0 + tmp3; /* phase 2 */ + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + dataptr[0] = tmp10 + tmp11; /* phase 3 */ + dataptr[4] = tmp10 - tmp11; + + z1 = (tmp12 + tmp13) * ((FAST_FLOAT) 0.707106781); /* c4 */ + dataptr[2] = tmp13 + z1; /* phase 5 */ + dataptr[6] = tmp13 - z1; + + /* Odd part */ + + tmp10 = tmp4 + tmp5; /* phase 2 */ + tmp11 = tmp5 + tmp6; + tmp12 = tmp6 + tmp7; + + /* The rotator is modified from fig 4-8 to avoid extra negations. */ + z5 = (tmp10 - tmp12) * ((FAST_FLOAT) 0.382683433); /* c6 */ + z2 = ((FAST_FLOAT) 0.541196100) * tmp10 + z5; /* c2-c6 */ + z4 = ((FAST_FLOAT) 1.306562965) * tmp12 + z5; /* c2+c6 */ + z3 = tmp11 * ((FAST_FLOAT) 0.707106781); /* c4 */ + + z11 = tmp7 + z3; /* phase 5 */ + z13 = tmp7 - z3; + + dataptr[5] = z13 + z2; /* phase 6 */ + dataptr[3] = z13 - z2; + dataptr[1] = z11 + z4; + dataptr[7] = z11 - z4; + + dataptr += DCTSIZE; /* advance pointer to next row */ + } + + /* Pass 2: process columns. */ + + dataptr = data; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*7]; + tmp7 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*7]; + tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*6]; + tmp6 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*6]; + tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*5]; + tmp5 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*5]; + tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*4]; + tmp4 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*4]; + + /* Even part */ + + tmp10 = tmp0 + tmp3; /* phase 2 */ + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + dataptr[DCTSIZE*0] = tmp10 + tmp11; /* phase 3 */ + dataptr[DCTSIZE*4] = tmp10 - tmp11; + + z1 = (tmp12 + tmp13) * ((FAST_FLOAT) 0.707106781); /* c4 */ + dataptr[DCTSIZE*2] = tmp13 + z1; /* phase 5 */ + dataptr[DCTSIZE*6] = tmp13 - z1; + + /* Odd part */ + + tmp10 = tmp4 + tmp5; /* phase 2 */ + tmp11 = tmp5 + tmp6; + tmp12 = tmp6 + tmp7; + + /* The rotator is modified from fig 4-8 to avoid extra negations. */ + z5 = (tmp10 - tmp12) * ((FAST_FLOAT) 0.382683433); /* c6 */ + z2 = ((FAST_FLOAT) 0.541196100) * tmp10 + z5; /* c2-c6 */ + z4 = ((FAST_FLOAT) 1.306562965) * tmp12 + z5; /* c2+c6 */ + z3 = tmp11 * ((FAST_FLOAT) 0.707106781); /* c4 */ + + z11 = tmp7 + z3; /* phase 5 */ + z13 = tmp7 - z3; + + dataptr[DCTSIZE*5] = z13 + z2; /* phase 6 */ + dataptr[DCTSIZE*3] = z13 - z2; + dataptr[DCTSIZE*1] = z11 + z4; + dataptr[DCTSIZE*7] = z11 - z4; + + dataptr++; /* advance pointer to next column */ + } +} + +#endif /* DCT_FLOAT_SUPPORTED */ diff --git a/Utilities/ITK/Utilities/itkjpeg/jfdctfst.c b/Utilities/ITK/Utilities/itkjpeg/jfdctfst.c new file mode 100644 index 0000000000000000000000000000000000000000..5d51e3c177e9d587d2580cb889dabb6a6a0954e3 --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jfdctfst.c @@ -0,0 +1,224 @@ +/* + * jfdctfst.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains a fast, not so accurate integer implementation of the + * forward DCT (Discrete Cosine Transform). + * + * A 2-D DCT can be done by 1-D DCT on each row followed by 1-D DCT + * on each column. Direct algorithms are also available, but they are + * much more complex and seem not to be any faster when reduced to code. + * + * This implementation is based on Arai, Agui, and Nakajima's algorithm for + * scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in + * Japanese, but the algorithm is described in the Pennebaker & Mitchell + * JPEG textbook (see REFERENCES section in file README). The following code + * is based directly on figure 4-8 in P&M. + * While an 8-point DCT cannot be done in less than 11 multiplies, it is + * possible to arrange the computation so that many of the multiplies are + * simple scalings of the final outputs. These multiplies can then be + * folded into the multiplications or divisions by the JPEG quantization + * table entries. The AA&N method leaves only 5 multiplies and 29 adds + * to be done in the DCT itself. + * The primary disadvantage of this method is that with fixed-point math, + * accuracy is lost due to imprecise representation of the scaled + * quantization values. The smaller the quantization table entry, the less + * precise the scaled value, so this implementation does worse with high- + * quality-setting files than with low-quality ones. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdct.h" /* Private declarations for DCT subsystem */ + +#ifdef DCT_IFAST_SUPPORTED + + +/* + * This module is specialized to the case DCTSIZE = 8. + */ + +#if DCTSIZE != 8 + Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */ +#endif + + +/* Scaling decisions are generally the same as in the LL&M algorithm; + * see jfdctint.c for more details. However, we choose to descale + * (right shift) multiplication products as soon as they are formed, + * rather than carrying additional fractional bits into subsequent additions. + * This compromises accuracy slightly, but it lets us save a few shifts. + * More importantly, 16-bit arithmetic is then adequate (for 8-bit samples) + * everywhere except in the multiplications proper; this saves a good deal + * of work on 16-bit-int machines. + * + * Again to save a few shifts, the intermediate results between pass 1 and + * pass 2 are not upscaled, but are represented only to integral precision. + * + * A final compromise is to represent the multiplicative constants to only + * 8 fractional bits, rather than 13. This saves some shifting work on some + * machines, and may also reduce the cost of multiplication (since there + * are fewer one-bits in the constants). + */ + +#define CONST_BITS 8 + + +/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus + * causing a lot of useless floating-point operations at run time. + * To get around this we use the following pre-calculated constants. + * If you change CONST_BITS you may want to add appropriate values. + * (With a reasonable C compiler, you can just rely on the FIX() macro...) + */ + +#if CONST_BITS == 8 +#define FIX_0_382683433 ((INT32) 98) /* FIX(0.382683433) */ +#define FIX_0_541196100 ((INT32) 139) /* FIX(0.541196100) */ +#define FIX_0_707106781 ((INT32) 181) /* FIX(0.707106781) */ +#define FIX_1_306562965 ((INT32) 334) /* FIX(1.306562965) */ +#else +#define FIX_0_382683433 FIX(0.382683433) +#define FIX_0_541196100 FIX(0.541196100) +#define FIX_0_707106781 FIX(0.707106781) +#define FIX_1_306562965 FIX(1.306562965) +#endif + + +/* We can gain a little more speed, with a further compromise in accuracy, + * by omitting the addition in a descaling shift. This yields an incorrectly + * rounded result half the time... + */ + +#ifndef USE_ACCURATE_ROUNDING +#undef DESCALE +#define DESCALE(x,n) RIGHT_SHIFT(x, n) +#endif + + +/* Multiply a DCTELEM variable by an INT32 constant, and immediately + * descale to yield a DCTELEM result. + */ + +#define MULTIPLY(var,const) ((DCTELEM) DESCALE((var) * (const), CONST_BITS)) + + +/* + * Perform the forward DCT on one block of samples. + */ + +GLOBAL(void) +jpeg_fdct_ifast (DCTELEM * data) +{ + DCTELEM tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + DCTELEM tmp10, tmp11, tmp12, tmp13; + DCTELEM z1, z2, z3, z4, z5, z11, z13; + DCTELEM *dataptr; + int ctr; + SHIFT_TEMPS + + /* Pass 1: process rows. */ + + dataptr = data; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + tmp0 = dataptr[0] + dataptr[7]; + tmp7 = dataptr[0] - dataptr[7]; + tmp1 = dataptr[1] + dataptr[6]; + tmp6 = dataptr[1] - dataptr[6]; + tmp2 = dataptr[2] + dataptr[5]; + tmp5 = dataptr[2] - dataptr[5]; + tmp3 = dataptr[3] + dataptr[4]; + tmp4 = dataptr[3] - dataptr[4]; + + /* Even part */ + + tmp10 = tmp0 + tmp3; /* phase 2 */ + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + dataptr[0] = tmp10 + tmp11; /* phase 3 */ + dataptr[4] = tmp10 - tmp11; + + z1 = MULTIPLY(tmp12 + tmp13, FIX_0_707106781); /* c4 */ + dataptr[2] = tmp13 + z1; /* phase 5 */ + dataptr[6] = tmp13 - z1; + + /* Odd part */ + + tmp10 = tmp4 + tmp5; /* phase 2 */ + tmp11 = tmp5 + tmp6; + tmp12 = tmp6 + tmp7; + + /* The rotator is modified from fig 4-8 to avoid extra negations. */ + z5 = MULTIPLY(tmp10 - tmp12, FIX_0_382683433); /* c6 */ + z2 = MULTIPLY(tmp10, FIX_0_541196100) + z5; /* c2-c6 */ + z4 = MULTIPLY(tmp12, FIX_1_306562965) + z5; /* c2+c6 */ + z3 = MULTIPLY(tmp11, FIX_0_707106781); /* c4 */ + + z11 = tmp7 + z3; /* phase 5 */ + z13 = tmp7 - z3; + + dataptr[5] = z13 + z2; /* phase 6 */ + dataptr[3] = z13 - z2; + dataptr[1] = z11 + z4; + dataptr[7] = z11 - z4; + + dataptr += DCTSIZE; /* advance pointer to next row */ + } + + /* Pass 2: process columns. */ + + dataptr = data; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*7]; + tmp7 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*7]; + tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*6]; + tmp6 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*6]; + tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*5]; + tmp5 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*5]; + tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*4]; + tmp4 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*4]; + + /* Even part */ + + tmp10 = tmp0 + tmp3; /* phase 2 */ + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + dataptr[DCTSIZE*0] = tmp10 + tmp11; /* phase 3 */ + dataptr[DCTSIZE*4] = tmp10 - tmp11; + + z1 = MULTIPLY(tmp12 + tmp13, FIX_0_707106781); /* c4 */ + dataptr[DCTSIZE*2] = tmp13 + z1; /* phase 5 */ + dataptr[DCTSIZE*6] = tmp13 - z1; + + /* Odd part */ + + tmp10 = tmp4 + tmp5; /* phase 2 */ + tmp11 = tmp5 + tmp6; + tmp12 = tmp6 + tmp7; + + /* The rotator is modified from fig 4-8 to avoid extra negations. */ + z5 = MULTIPLY(tmp10 - tmp12, FIX_0_382683433); /* c6 */ + z2 = MULTIPLY(tmp10, FIX_0_541196100) + z5; /* c2-c6 */ + z4 = MULTIPLY(tmp12, FIX_1_306562965) + z5; /* c2+c6 */ + z3 = MULTIPLY(tmp11, FIX_0_707106781); /* c4 */ + + z11 = tmp7 + z3; /* phase 5 */ + z13 = tmp7 - z3; + + dataptr[DCTSIZE*5] = z13 + z2; /* phase 6 */ + dataptr[DCTSIZE*3] = z13 - z2; + dataptr[DCTSIZE*1] = z11 + z4; + dataptr[DCTSIZE*7] = z11 - z4; + + dataptr++; /* advance pointer to next column */ + } +} + +#endif /* DCT_IFAST_SUPPORTED */ diff --git a/Utilities/ITK/Utilities/itkjpeg/jfdctint.c b/Utilities/ITK/Utilities/itkjpeg/jfdctint.c new file mode 100644 index 0000000000000000000000000000000000000000..8f6c73db3b926e01469cd503fb950c84edc97eab --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jfdctint.c @@ -0,0 +1,283 @@ +/* + * jfdctint.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains a slow-but-accurate integer implementation of the + * forward DCT (Discrete Cosine Transform). + * + * A 2-D DCT can be done by 1-D DCT on each row followed by 1-D DCT + * on each column. Direct algorithms are also available, but they are + * much more complex and seem not to be any faster when reduced to code. + * + * This implementation is based on an algorithm described in + * C. Loeffler, A. Ligtenberg and G. Moschytz, "Practical Fast 1-D DCT + * Algorithms with 11 Multiplications", Proc. Int'l. Conf. on Acoustics, + * Speech, and Signal Processing 1989 (ICASSP '89), pp. 988-991. + * The primary algorithm described there uses 11 multiplies and 29 adds. + * We use their alternate method with 12 multiplies and 32 adds. + * The advantage of this method is that no data path contains more than one + * multiplication; this allows a very simple and accurate implementation in + * scaled fixed-point arithmetic, with a minimal number of shifts. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdct.h" /* Private declarations for DCT subsystem */ + +#ifdef DCT_ISLOW_SUPPORTED + + +/* + * This module is specialized to the case DCTSIZE = 8. + */ + +#if DCTSIZE != 8 + Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */ +#endif + + +/* + * The poop on this scaling stuff is as follows: + * + * Each 1-D DCT step produces outputs which are a factor of sqrt(N) + * larger than the true DCT outputs. The final outputs are therefore + * a factor of N larger than desired; since N=8 this can be cured by + * a simple right shift at the end of the algorithm. The advantage of + * this arrangement is that we save two multiplications per 1-D DCT, + * because the y0 and y4 outputs need not be divided by sqrt(N). + * In the IJG code, this factor of 8 is removed by the quantization step + * (in jcdctmgr.c), NOT in this module. + * + * We have to do addition and subtraction of the integer inputs, which + * is no problem, and multiplication by fractional constants, which is + * a problem to do in integer arithmetic. We multiply all the constants + * by CONST_SCALE and convert them to integer constants (thus retaining + * CONST_BITS bits of precision in the constants). After doing a + * multiplication we have to divide the product by CONST_SCALE, with proper + * rounding, to produce the correct output. This division can be done + * cheaply as a right shift of CONST_BITS bits. We postpone shifting + * as long as possible so that partial sums can be added together with + * full fractional precision. + * + * The outputs of the first pass are scaled up by PASS1_BITS bits so that + * they are represented to better-than-integral precision. These outputs + * require BITS_IN_JSAMPLE + PASS1_BITS + 3 bits; this fits in a 16-bit word + * with the recommended scaling. (For 12-bit sample data, the intermediate + * array is INT32 anyway.) + * + * To avoid overflow of the 32-bit intermediate results in pass 2, we must + * have BITS_IN_JSAMPLE + CONST_BITS + PASS1_BITS <= 26. Error analysis + * shows that the values given below are the most effective. + */ + +#if BITS_IN_JSAMPLE == 8 +#define CONST_BITS 13 +#define PASS1_BITS 2 +#else +#define CONST_BITS 13 +#define PASS1_BITS 1 /* lose a little precision to avoid overflow */ +#endif + +/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus + * causing a lot of useless floating-point operations at run time. + * To get around this we use the following pre-calculated constants. + * If you change CONST_BITS you may want to add appropriate values. + * (With a reasonable C compiler, you can just rely on the FIX() macro...) + */ + +#if CONST_BITS == 13 +#define FIX_0_298631336 ((INT32) 2446) /* FIX(0.298631336) */ +#define FIX_0_390180644 ((INT32) 3196) /* FIX(0.390180644) */ +#define FIX_0_541196100 ((INT32) 4433) /* FIX(0.541196100) */ +#define FIX_0_765366865 ((INT32) 6270) /* FIX(0.765366865) */ +#define FIX_0_899976223 ((INT32) 7373) /* FIX(0.899976223) */ +#define FIX_1_175875602 ((INT32) 9633) /* FIX(1.175875602) */ +#define FIX_1_501321110 ((INT32) 12299) /* FIX(1.501321110) */ +#define FIX_1_847759065 ((INT32) 15137) /* FIX(1.847759065) */ +#define FIX_1_961570560 ((INT32) 16069) /* FIX(1.961570560) */ +#define FIX_2_053119869 ((INT32) 16819) /* FIX(2.053119869) */ +#define FIX_2_562915447 ((INT32) 20995) /* FIX(2.562915447) */ +#define FIX_3_072711026 ((INT32) 25172) /* FIX(3.072711026) */ +#else +#define FIX_0_298631336 FIX(0.298631336) +#define FIX_0_390180644 FIX(0.390180644) +#define FIX_0_541196100 FIX(0.541196100) +#define FIX_0_765366865 FIX(0.765366865) +#define FIX_0_899976223 FIX(0.899976223) +#define FIX_1_175875602 FIX(1.175875602) +#define FIX_1_501321110 FIX(1.501321110) +#define FIX_1_847759065 FIX(1.847759065) +#define FIX_1_961570560 FIX(1.961570560) +#define FIX_2_053119869 FIX(2.053119869) +#define FIX_2_562915447 FIX(2.562915447) +#define FIX_3_072711026 FIX(3.072711026) +#endif + + +/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result. + * For 8-bit samples with the recommended scaling, all the variable + * and constant values involved are no more than 16 bits wide, so a + * 16x16->32 bit multiply can be used instead of a full 32x32 multiply. + * For 12-bit samples, a full 32-bit multiplication will be needed. + */ + +#if BITS_IN_JSAMPLE == 8 +#define MULTIPLY(var,const) MULTIPLY16C16(var,const) +#else +#define MULTIPLY(var,const) ((var) * (const)) +#endif + + +/* + * Perform the forward DCT on one block of samples. + */ + +GLOBAL(void) +jpeg_fdct_islow (DCTELEM * data) +{ + INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + INT32 tmp10, tmp11, tmp12, tmp13; + INT32 z1, z2, z3, z4, z5; + DCTELEM *dataptr; + int ctr; + SHIFT_TEMPS + + /* Pass 1: process rows. */ + /* Note results are scaled up by sqrt(8) compared to a true DCT; */ + /* furthermore, we scale the results by 2**PASS1_BITS. */ + + dataptr = data; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + tmp0 = dataptr[0] + dataptr[7]; + tmp7 = dataptr[0] - dataptr[7]; + tmp1 = dataptr[1] + dataptr[6]; + tmp6 = dataptr[1] - dataptr[6]; + tmp2 = dataptr[2] + dataptr[5]; + tmp5 = dataptr[2] - dataptr[5]; + tmp3 = dataptr[3] + dataptr[4]; + tmp4 = dataptr[3] - dataptr[4]; + + /* Even part per LL&M figure 1 --- note that published figure is faulty; + * rotator "sqrt(2)*c1" should be "sqrt(2)*c6". + */ + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + dataptr[0] = (DCTELEM) ((tmp10 + tmp11) << PASS1_BITS); + dataptr[4] = (DCTELEM) ((tmp10 - tmp11) << PASS1_BITS); + + z1 = MULTIPLY(tmp12 + tmp13, FIX_0_541196100); + dataptr[2] = (DCTELEM) DESCALE(z1 + MULTIPLY(tmp13, FIX_0_765366865), + CONST_BITS-PASS1_BITS); + dataptr[6] = (DCTELEM) DESCALE(z1 + MULTIPLY(tmp12, - FIX_1_847759065), + CONST_BITS-PASS1_BITS); + + /* Odd part per figure 8 --- note paper omits factor of sqrt(2). + * cK represents cos(K*pi/16). + * i0..i3 in the paper are tmp4..tmp7 here. + */ + + z1 = tmp4 + tmp7; + z2 = tmp5 + tmp6; + z3 = tmp4 + tmp6; + z4 = tmp5 + tmp7; + z5 = MULTIPLY(z3 + z4, FIX_1_175875602); /* sqrt(2) * c3 */ + + tmp4 = MULTIPLY(tmp4, FIX_0_298631336); /* sqrt(2) * (-c1+c3+c5-c7) */ + tmp5 = MULTIPLY(tmp5, FIX_2_053119869); /* sqrt(2) * ( c1+c3-c5+c7) */ + tmp6 = MULTIPLY(tmp6, FIX_3_072711026); /* sqrt(2) * ( c1+c3+c5-c7) */ + tmp7 = MULTIPLY(tmp7, FIX_1_501321110); /* sqrt(2) * ( c1+c3-c5-c7) */ + z1 = MULTIPLY(z1, - FIX_0_899976223); /* sqrt(2) * (c7-c3) */ + z2 = MULTIPLY(z2, - FIX_2_562915447); /* sqrt(2) * (-c1-c3) */ + z3 = MULTIPLY(z3, - FIX_1_961570560); /* sqrt(2) * (-c3-c5) */ + z4 = MULTIPLY(z4, - FIX_0_390180644); /* sqrt(2) * (c5-c3) */ + + z3 += z5; + z4 += z5; + + dataptr[7] = (DCTELEM) DESCALE(tmp4 + z1 + z3, CONST_BITS-PASS1_BITS); + dataptr[5] = (DCTELEM) DESCALE(tmp5 + z2 + z4, CONST_BITS-PASS1_BITS); + dataptr[3] = (DCTELEM) DESCALE(tmp6 + z2 + z3, CONST_BITS-PASS1_BITS); + dataptr[1] = (DCTELEM) DESCALE(tmp7 + z1 + z4, CONST_BITS-PASS1_BITS); + + dataptr += DCTSIZE; /* advance pointer to next row */ + } + + /* Pass 2: process columns. + * We remove the PASS1_BITS scaling, but leave the results scaled up + * by an overall factor of 8. + */ + + dataptr = data; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*7]; + tmp7 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*7]; + tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*6]; + tmp6 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*6]; + tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*5]; + tmp5 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*5]; + tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*4]; + tmp4 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*4]; + + /* Even part per LL&M figure 1 --- note that published figure is faulty; + * rotator "sqrt(2)*c1" should be "sqrt(2)*c6". + */ + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + dataptr[DCTSIZE*0] = (DCTELEM) DESCALE(tmp10 + tmp11, PASS1_BITS); + dataptr[DCTSIZE*4] = (DCTELEM) DESCALE(tmp10 - tmp11, PASS1_BITS); + + z1 = MULTIPLY(tmp12 + tmp13, FIX_0_541196100); + dataptr[DCTSIZE*2] = (DCTELEM) DESCALE(z1 + MULTIPLY(tmp13, FIX_0_765366865), + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*6] = (DCTELEM) DESCALE(z1 + MULTIPLY(tmp12, - FIX_1_847759065), + CONST_BITS+PASS1_BITS); + + /* Odd part per figure 8 --- note paper omits factor of sqrt(2). + * cK represents cos(K*pi/16). + * i0..i3 in the paper are tmp4..tmp7 here. + */ + + z1 = tmp4 + tmp7; + z2 = tmp5 + tmp6; + z3 = tmp4 + tmp6; + z4 = tmp5 + tmp7; + z5 = MULTIPLY(z3 + z4, FIX_1_175875602); /* sqrt(2) * c3 */ + + tmp4 = MULTIPLY(tmp4, FIX_0_298631336); /* sqrt(2) * (-c1+c3+c5-c7) */ + tmp5 = MULTIPLY(tmp5, FIX_2_053119869); /* sqrt(2) * ( c1+c3-c5+c7) */ + tmp6 = MULTIPLY(tmp6, FIX_3_072711026); /* sqrt(2) * ( c1+c3+c5-c7) */ + tmp7 = MULTIPLY(tmp7, FIX_1_501321110); /* sqrt(2) * ( c1+c3-c5-c7) */ + z1 = MULTIPLY(z1, - FIX_0_899976223); /* sqrt(2) * (c7-c3) */ + z2 = MULTIPLY(z2, - FIX_2_562915447); /* sqrt(2) * (-c1-c3) */ + z3 = MULTIPLY(z3, - FIX_1_961570560); /* sqrt(2) * (-c3-c5) */ + z4 = MULTIPLY(z4, - FIX_0_390180644); /* sqrt(2) * (c5-c3) */ + + z3 += z5; + z4 += z5; + + dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp4 + z1 + z3, + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp5 + z2 + z4, + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp6 + z2 + z3, + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp7 + z1 + z4, + CONST_BITS+PASS1_BITS); + + dataptr++; /* advance pointer to next column */ + } +} + +#endif /* DCT_ISLOW_SUPPORTED */ diff --git a/Utilities/ITK/Utilities/itkjpeg/jidctflt.c b/Utilities/ITK/Utilities/itkjpeg/jidctflt.c new file mode 100644 index 0000000000000000000000000000000000000000..0d72de891b8a1bad1d589f997c423aa045fcc5ca --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jidctflt.c @@ -0,0 +1,242 @@ +/* + * jidctflt.c + * + * Copyright (C) 1994-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains a floating-point implementation of the + * inverse DCT (Discrete Cosine Transform). In the IJG code, this routine + * must also perform dequantization of the input coefficients. + * + * This implementation should be more accurate than either of the integer + * IDCT implementations. However, it may not give the same results on all + * machines because of differences in roundoff behavior. Speed will depend + * on the hardware's floating point capacity. + * + * A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT + * on each row (or vice versa, but it's more convenient to emit a row at + * a time). Direct algorithms are also available, but they are much more + * complex and seem not to be any faster when reduced to code. + * + * This implementation is based on Arai, Agui, and Nakajima's algorithm for + * scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in + * Japanese, but the algorithm is described in the Pennebaker & Mitchell + * JPEG textbook (see REFERENCES section in file README). The following code + * is based directly on figure 4-8 in P&M. + * While an 8-point DCT cannot be done in less than 11 multiplies, it is + * possible to arrange the computation so that many of the multiplies are + * simple scalings of the final outputs. These multiplies can then be + * folded into the multiplications or divisions by the JPEG quantization + * table entries. The AA&N method leaves only 5 multiplies and 29 adds + * to be done in the DCT itself. + * The primary disadvantage of this method is that with a fixed-point + * implementation, accuracy is lost due to imprecise representation of the + * scaled quantization values. However, that problem does not arise if + * we use floating point arithmetic. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdct.h" /* Private declarations for DCT subsystem */ + +#ifdef DCT_FLOAT_SUPPORTED + + +/* + * This module is specialized to the case DCTSIZE = 8. + */ + +#if DCTSIZE != 8 + Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */ +#endif + + +/* Dequantize a coefficient by multiplying it by the multiplier-table + * entry; produce a float result. + */ + +#define DEQUANTIZE(coef,quantval) (((FAST_FLOAT) (coef)) * (quantval)) + + +/* + * Perform dequantization and inverse DCT on one block of coefficients. + */ + +GLOBAL(void) +jpeg_idct_float (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + FAST_FLOAT tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + FAST_FLOAT tmp10, tmp11, tmp12, tmp13; + FAST_FLOAT z5, z10, z11, z12, z13; + JCOEFPTR inptr; + FLOAT_MULT_TYPE * quantptr; + FAST_FLOAT * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + FAST_FLOAT workspace[DCTSIZE2]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. */ + + inptr = coef_block; + quantptr = (FLOAT_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = DCTSIZE; ctr > 0; ctr--) { + /* Due to quantization, we will usually find that many of the input + * coefficients are zero, especially the AC terms. We can exploit this + * by short-circuiting the IDCT calculation for any column in which all + * the AC terms are zero. In that case each output is equal to the + * DC coefficient (with scale factor as needed). + * With typical images and quantization tables, half or more of the + * column DCT calculations can be simplified this way. + */ + + if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 && + inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*4] == 0 && + inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 && + inptr[DCTSIZE*7] == 0) { + /* AC terms all zero */ + FAST_FLOAT dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + + wsptr[DCTSIZE*0] = dcval; + wsptr[DCTSIZE*1] = dcval; + wsptr[DCTSIZE*2] = dcval; + wsptr[DCTSIZE*3] = dcval; + wsptr[DCTSIZE*4] = dcval; + wsptr[DCTSIZE*5] = dcval; + wsptr[DCTSIZE*6] = dcval; + wsptr[DCTSIZE*7] = dcval; + + inptr++; /* advance pointers to next column */ + quantptr++; + wsptr++; + continue; + } + + /* Even part */ + + tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + tmp1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + tmp2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + tmp3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + + tmp10 = tmp0 + tmp2; /* phase 3 */ + tmp11 = tmp0 - tmp2; + + tmp13 = tmp1 + tmp3; /* phases 5-3 */ + tmp12 = (tmp1 - tmp3) * ((FAST_FLOAT) 1.414213562) - tmp13; /* 2*c4 */ + + tmp0 = tmp10 + tmp13; /* phase 2 */ + tmp3 = tmp10 - tmp13; + tmp1 = tmp11 + tmp12; + tmp2 = tmp11 - tmp12; + + /* Odd part */ + + tmp4 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + tmp5 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + tmp6 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + tmp7 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + + z13 = tmp6 + tmp5; /* phase 6 */ + z10 = tmp6 - tmp5; + z11 = tmp4 + tmp7; + z12 = tmp4 - tmp7; + + tmp7 = z11 + z13; /* phase 5 */ + tmp11 = (z11 - z13) * ((FAST_FLOAT) 1.414213562); /* 2*c4 */ + + z5 = (z10 + z12) * ((FAST_FLOAT) 1.847759065); /* 2*c2 */ + tmp10 = ((FAST_FLOAT) 1.082392200) * z12 - z5; /* 2*(c2-c6) */ + tmp12 = ((FAST_FLOAT) -2.613125930) * z10 + z5; /* -2*(c2+c6) */ + + tmp6 = tmp12 - tmp7; /* phase 2 */ + tmp5 = tmp11 - tmp6; + tmp4 = tmp10 + tmp5; + + wsptr[DCTSIZE*0] = tmp0 + tmp7; + wsptr[DCTSIZE*7] = tmp0 - tmp7; + wsptr[DCTSIZE*1] = tmp1 + tmp6; + wsptr[DCTSIZE*6] = tmp1 - tmp6; + wsptr[DCTSIZE*2] = tmp2 + tmp5; + wsptr[DCTSIZE*5] = tmp2 - tmp5; + wsptr[DCTSIZE*4] = tmp3 + tmp4; + wsptr[DCTSIZE*3] = tmp3 - tmp4; + + inptr++; /* advance pointers to next column */ + quantptr++; + wsptr++; + } + + /* Pass 2: process rows from work array, store into output array. */ + /* Note that we must descale the results by a factor of 8 == 2**3. */ + + wsptr = workspace; + for (ctr = 0; ctr < DCTSIZE; ctr++) { + outptr = output_buf[ctr] + output_col; + /* Rows of zeroes can be exploited in the same way as we did with columns. + * However, the column calculation has created many nonzero AC terms, so + * the simplification applies less often (typically 5% to 10% of the time). + * And testing floats for zero is relatively expensive, so we don't bother. + */ + + /* Even part */ + + tmp10 = wsptr[0] + wsptr[4]; + tmp11 = wsptr[0] - wsptr[4]; + + tmp13 = wsptr[2] + wsptr[6]; + tmp12 = (wsptr[2] - wsptr[6]) * ((FAST_FLOAT) 1.414213562) - tmp13; + + tmp0 = tmp10 + tmp13; + tmp3 = tmp10 - tmp13; + tmp1 = tmp11 + tmp12; + tmp2 = tmp11 - tmp12; + + /* Odd part */ + + z13 = wsptr[5] + wsptr[3]; + z10 = wsptr[5] - wsptr[3]; + z11 = wsptr[1] + wsptr[7]; + z12 = wsptr[1] - wsptr[7]; + + tmp7 = z11 + z13; + tmp11 = (z11 - z13) * ((FAST_FLOAT) 1.414213562); + + z5 = (z10 + z12) * ((FAST_FLOAT) 1.847759065); /* 2*c2 */ + tmp10 = ((FAST_FLOAT) 1.082392200) * z12 - z5; /* 2*(c2-c6) */ + tmp12 = ((FAST_FLOAT) -2.613125930) * z10 + z5; /* -2*(c2+c6) */ + + tmp6 = tmp12 - tmp7; + tmp5 = tmp11 - tmp6; + tmp4 = tmp10 + tmp5; + + /* Final output stage: scale down by a factor of 8 and range-limit */ + + outptr[0] = range_limit[(int) DESCALE((INT32) (tmp0 + tmp7), 3) + & RANGE_MASK]; + outptr[7] = range_limit[(int) DESCALE((INT32) (tmp0 - tmp7), 3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) DESCALE((INT32) (tmp1 + tmp6), 3) + & RANGE_MASK]; + outptr[6] = range_limit[(int) DESCALE((INT32) (tmp1 - tmp6), 3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) DESCALE((INT32) (tmp2 + tmp5), 3) + & RANGE_MASK]; + outptr[5] = range_limit[(int) DESCALE((INT32) (tmp2 - tmp5), 3) + & RANGE_MASK]; + outptr[4] = range_limit[(int) DESCALE((INT32) (tmp3 + tmp4), 3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) DESCALE((INT32) (tmp3 - tmp4), 3) + & RANGE_MASK]; + + wsptr += DCTSIZE; /* advance pointer to next row */ + } +} + +#endif /* DCT_FLOAT_SUPPORTED */ diff --git a/Utilities/ITK/Utilities/itkjpeg/jidctfst.c b/Utilities/ITK/Utilities/itkjpeg/jidctfst.c new file mode 100644 index 0000000000000000000000000000000000000000..3245decc45fd1418b5862cab566070b28a3d5613 --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jidctfst.c @@ -0,0 +1,368 @@ +/* + * jidctfst.c + * + * Copyright (C) 1994-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains a fast, not so accurate integer implementation of the + * inverse DCT (Discrete Cosine Transform). In the IJG code, this routine + * must also perform dequantization of the input coefficients. + * + * A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT + * on each row (or vice versa, but it's more convenient to emit a row at + * a time). Direct algorithms are also available, but they are much more + * complex and seem not to be any faster when reduced to code. + * + * This implementation is based on Arai, Agui, and Nakajima's algorithm for + * scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in + * Japanese, but the algorithm is described in the Pennebaker & Mitchell + * JPEG textbook (see REFERENCES section in file README). The following code + * is based directly on figure 4-8 in P&M. + * While an 8-point DCT cannot be done in less than 11 multiplies, it is + * possible to arrange the computation so that many of the multiplies are + * simple scalings of the final outputs. These multiplies can then be + * folded into the multiplications or divisions by the JPEG quantization + * table entries. The AA&N method leaves only 5 multiplies and 29 adds + * to be done in the DCT itself. + * The primary disadvantage of this method is that with fixed-point math, + * accuracy is lost due to imprecise representation of the scaled + * quantization values. The smaller the quantization table entry, the less + * precise the scaled value, so this implementation does worse with high- + * quality-setting files than with low-quality ones. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdct.h" /* Private declarations for DCT subsystem */ + +#ifdef DCT_IFAST_SUPPORTED + + +/* + * This module is specialized to the case DCTSIZE = 8. + */ + +#if DCTSIZE != 8 + Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */ +#endif + + +/* Scaling decisions are generally the same as in the LL&M algorithm; + * see jidctint.c for more details. However, we choose to descale + * (right shift) multiplication products as soon as they are formed, + * rather than carrying additional fractional bits into subsequent additions. + * This compromises accuracy slightly, but it lets us save a few shifts. + * More importantly, 16-bit arithmetic is then adequate (for 8-bit samples) + * everywhere except in the multiplications proper; this saves a good deal + * of work on 16-bit-int machines. + * + * The dequantized coefficients are not integers because the AA&N scaling + * factors have been incorporated. We represent them scaled up by PASS1_BITS, + * so that the first and second IDCT rounds have the same input scaling. + * For 8-bit JSAMPLEs, we choose IFAST_SCALE_BITS = PASS1_BITS so as to + * avoid a descaling shift; this compromises accuracy rather drastically + * for small quantization table entries, but it saves a lot of shifts. + * For 12-bit JSAMPLEs, there's no hope of using 16x16 multiplies anyway, + * so we use a much larger scaling factor to preserve accuracy. + * + * A final compromise is to represent the multiplicative constants to only + * 8 fractional bits, rather than 13. This saves some shifting work on some + * machines, and may also reduce the cost of multiplication (since there + * are fewer one-bits in the constants). + */ + +#if BITS_IN_JSAMPLE == 8 +#define CONST_BITS 8 +#define PASS1_BITS 2 +#else +#define CONST_BITS 8 +#define PASS1_BITS 1 /* lose a little precision to avoid overflow */ +#endif + +/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus + * causing a lot of useless floating-point operations at run time. + * To get around this we use the following pre-calculated constants. + * If you change CONST_BITS you may want to add appropriate values. + * (With a reasonable C compiler, you can just rely on the FIX() macro...) + */ + +#if CONST_BITS == 8 +#define FIX_1_082392200 ((INT32) 277) /* FIX(1.082392200) */ +#define FIX_1_414213562 ((INT32) 362) /* FIX(1.414213562) */ +#define FIX_1_847759065 ((INT32) 473) /* FIX(1.847759065) */ +#define FIX_2_613125930 ((INT32) 669) /* FIX(2.613125930) */ +#else +#define FIX_1_082392200 FIX(1.082392200) +#define FIX_1_414213562 FIX(1.414213562) +#define FIX_1_847759065 FIX(1.847759065) +#define FIX_2_613125930 FIX(2.613125930) +#endif + + +/* We can gain a little more speed, with a further compromise in accuracy, + * by omitting the addition in a descaling shift. This yields an incorrectly + * rounded result half the time... + */ + +#ifndef USE_ACCURATE_ROUNDING +#undef DESCALE +#define DESCALE(x,n) RIGHT_SHIFT(x, n) +#endif + + +/* Multiply a DCTELEM variable by an INT32 constant, and immediately + * descale to yield a DCTELEM result. + */ + +#define MULTIPLY(var,const) ((DCTELEM) DESCALE((var) * (const), CONST_BITS)) + + +/* Dequantize a coefficient by multiplying it by the multiplier-table + * entry; produce a DCTELEM result. For 8-bit data a 16x16->16 + * multiplication will do. For 12-bit data, the multiplier table is + * declared INT32, so a 32-bit multiply will be used. + */ + +#if BITS_IN_JSAMPLE == 8 +#define DEQUANTIZE(coef,quantval) (((IFAST_MULT_TYPE) (coef)) * (quantval)) +#else +#define DEQUANTIZE(coef,quantval) \ + DESCALE((coef)*(quantval), IFAST_SCALE_BITS-PASS1_BITS) +#endif + + +/* Like DESCALE, but applies to a DCTELEM and produces an int. + * We assume that int right shift is unsigned if INT32 right shift is. + */ + +#ifdef RIGHT_SHIFT_IS_UNSIGNED +#define ISHIFT_TEMPS DCTELEM ishift_temp; +#if BITS_IN_JSAMPLE == 8 +#define DCTELEMBITS 16 /* DCTELEM may be 16 or 32 bits */ +#else +#define DCTELEMBITS 32 /* DCTELEM must be 32 bits */ +#endif +#define IRIGHT_SHIFT(x,shft) \ + ((ishift_temp = (x)) < 0 ? \ + (ishift_temp >> (shft)) | ((~((DCTELEM) 0)) << (DCTELEMBITS-(shft))) : \ + (ishift_temp >> (shft))) +#else +#define ISHIFT_TEMPS +#define IRIGHT_SHIFT(x,shft) ((x) >> (shft)) +#endif + +#ifdef USE_ACCURATE_ROUNDING +#define IDESCALE(x,n) ((int) IRIGHT_SHIFT((x) + (1 << ((n)-1)), n)) +#else +#define IDESCALE(x,n) ((int) IRIGHT_SHIFT(x, n)) +#endif + + +/* + * Perform dequantization and inverse DCT on one block of coefficients. + */ + +GLOBAL(void) +jpeg_idct_ifast (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + DCTELEM tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + DCTELEM tmp10, tmp11, tmp12, tmp13; + DCTELEM z5, z10, z11, z12, z13; + JCOEFPTR inptr; + IFAST_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[DCTSIZE2]; /* buffers data between passes */ + SHIFT_TEMPS /* for DESCALE */ + ISHIFT_TEMPS /* for IDESCALE */ + + /* Pass 1: process columns from input, store into work array. */ + + inptr = coef_block; + quantptr = (IFAST_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = DCTSIZE; ctr > 0; ctr--) { + /* Due to quantization, we will usually find that many of the input + * coefficients are zero, especially the AC terms. We can exploit this + * by short-circuiting the IDCT calculation for any column in which all + * the AC terms are zero. In that case each output is equal to the + * DC coefficient (with scale factor as needed). + * With typical images and quantization tables, half or more of the + * column DCT calculations can be simplified this way. + */ + + if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 && + inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*4] == 0 && + inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 && + inptr[DCTSIZE*7] == 0) { + /* AC terms all zero */ + int dcval = (int) DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + + wsptr[DCTSIZE*0] = dcval; + wsptr[DCTSIZE*1] = dcval; + wsptr[DCTSIZE*2] = dcval; + wsptr[DCTSIZE*3] = dcval; + wsptr[DCTSIZE*4] = dcval; + wsptr[DCTSIZE*5] = dcval; + wsptr[DCTSIZE*6] = dcval; + wsptr[DCTSIZE*7] = dcval; + + inptr++; /* advance pointers to next column */ + quantptr++; + wsptr++; + continue; + } + + /* Even part */ + + tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + tmp1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + tmp2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + tmp3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + + tmp10 = tmp0 + tmp2; /* phase 3 */ + tmp11 = tmp0 - tmp2; + + tmp13 = tmp1 + tmp3; /* phases 5-3 */ + tmp12 = MULTIPLY(tmp1 - tmp3, FIX_1_414213562) - tmp13; /* 2*c4 */ + + tmp0 = tmp10 + tmp13; /* phase 2 */ + tmp3 = tmp10 - tmp13; + tmp1 = tmp11 + tmp12; + tmp2 = tmp11 - tmp12; + + /* Odd part */ + + tmp4 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + tmp5 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + tmp6 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + tmp7 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + + z13 = tmp6 + tmp5; /* phase 6 */ + z10 = tmp6 - tmp5; + z11 = tmp4 + tmp7; + z12 = tmp4 - tmp7; + + tmp7 = z11 + z13; /* phase 5 */ + tmp11 = MULTIPLY(z11 - z13, FIX_1_414213562); /* 2*c4 */ + + z5 = MULTIPLY(z10 + z12, FIX_1_847759065); /* 2*c2 */ + tmp10 = MULTIPLY(z12, FIX_1_082392200) - z5; /* 2*(c2-c6) */ + tmp12 = MULTIPLY(z10, - FIX_2_613125930) + z5; /* -2*(c2+c6) */ + + tmp6 = tmp12 - tmp7; /* phase 2 */ + tmp5 = tmp11 - tmp6; + tmp4 = tmp10 + tmp5; + + wsptr[DCTSIZE*0] = (int) (tmp0 + tmp7); + wsptr[DCTSIZE*7] = (int) (tmp0 - tmp7); + wsptr[DCTSIZE*1] = (int) (tmp1 + tmp6); + wsptr[DCTSIZE*6] = (int) (tmp1 - tmp6); + wsptr[DCTSIZE*2] = (int) (tmp2 + tmp5); + wsptr[DCTSIZE*5] = (int) (tmp2 - tmp5); + wsptr[DCTSIZE*4] = (int) (tmp3 + tmp4); + wsptr[DCTSIZE*3] = (int) (tmp3 - tmp4); + + inptr++; /* advance pointers to next column */ + quantptr++; + wsptr++; + } + + /* Pass 2: process rows from work array, store into output array. */ + /* Note that we must descale the results by a factor of 8 == 2**3, */ + /* and also undo the PASS1_BITS scaling. */ + + wsptr = workspace; + for (ctr = 0; ctr < DCTSIZE; ctr++) { + outptr = output_buf[ctr] + output_col; + /* Rows of zeroes can be exploited in the same way as we did with columns. + * However, the column calculation has created many nonzero AC terms, so + * the simplification applies less often (typically 5% to 10% of the time). + * On machines with very fast multiplication, it's possible that the + * test takes more time than it's worth. In that case this section + * may be commented out. + */ + +#ifndef NO_ZERO_ROW_TEST + if (wsptr[1] == 0 && wsptr[2] == 0 && wsptr[3] == 0 && wsptr[4] == 0 && + wsptr[5] == 0 && wsptr[6] == 0 && wsptr[7] == 0) { + /* AC terms all zero */ + JSAMPLE dcval = range_limit[IDESCALE(wsptr[0], PASS1_BITS+3) + & RANGE_MASK]; + + outptr[0] = dcval; + outptr[1] = dcval; + outptr[2] = dcval; + outptr[3] = dcval; + outptr[4] = dcval; + outptr[5] = dcval; + outptr[6] = dcval; + outptr[7] = dcval; + + wsptr += DCTSIZE; /* advance pointer to next row */ + continue; + } +#endif + + /* Even part */ + + tmp10 = ((DCTELEM) wsptr[0] + (DCTELEM) wsptr[4]); + tmp11 = ((DCTELEM) wsptr[0] - (DCTELEM) wsptr[4]); + + tmp13 = ((DCTELEM) wsptr[2] + (DCTELEM) wsptr[6]); + tmp12 = MULTIPLY((DCTELEM) wsptr[2] - (DCTELEM) wsptr[6], FIX_1_414213562) + - tmp13; + + tmp0 = tmp10 + tmp13; + tmp3 = tmp10 - tmp13; + tmp1 = tmp11 + tmp12; + tmp2 = tmp11 - tmp12; + + /* Odd part */ + + z13 = (DCTELEM) wsptr[5] + (DCTELEM) wsptr[3]; + z10 = (DCTELEM) wsptr[5] - (DCTELEM) wsptr[3]; + z11 = (DCTELEM) wsptr[1] + (DCTELEM) wsptr[7]; + z12 = (DCTELEM) wsptr[1] - (DCTELEM) wsptr[7]; + + tmp7 = z11 + z13; /* phase 5 */ + tmp11 = MULTIPLY(z11 - z13, FIX_1_414213562); /* 2*c4 */ + + z5 = MULTIPLY(z10 + z12, FIX_1_847759065); /* 2*c2 */ + tmp10 = MULTIPLY(z12, FIX_1_082392200) - z5; /* 2*(c2-c6) */ + tmp12 = MULTIPLY(z10, - FIX_2_613125930) + z5; /* -2*(c2+c6) */ + + tmp6 = tmp12 - tmp7; /* phase 2 */ + tmp5 = tmp11 - tmp6; + tmp4 = tmp10 + tmp5; + + /* Final output stage: scale down by a factor of 8 and range-limit */ + + outptr[0] = range_limit[IDESCALE(tmp0 + tmp7, PASS1_BITS+3) + & RANGE_MASK]; + outptr[7] = range_limit[IDESCALE(tmp0 - tmp7, PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[IDESCALE(tmp1 + tmp6, PASS1_BITS+3) + & RANGE_MASK]; + outptr[6] = range_limit[IDESCALE(tmp1 - tmp6, PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[IDESCALE(tmp2 + tmp5, PASS1_BITS+3) + & RANGE_MASK]; + outptr[5] = range_limit[IDESCALE(tmp2 - tmp5, PASS1_BITS+3) + & RANGE_MASK]; + outptr[4] = range_limit[IDESCALE(tmp3 + tmp4, PASS1_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[IDESCALE(tmp3 - tmp4, PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += DCTSIZE; /* advance pointer to next row */ + } +} + +#endif /* DCT_IFAST_SUPPORTED */ diff --git a/Utilities/ITK/Utilities/itkjpeg/jidctint.c b/Utilities/ITK/Utilities/itkjpeg/jidctint.c new file mode 100644 index 0000000000000000000000000000000000000000..e8a8b7af5707e465c85d7044e9b85e69ea058e9b --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jidctint.c @@ -0,0 +1,389 @@ +/* + * jidctint.c + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains a slow-but-accurate integer implementation of the + * inverse DCT (Discrete Cosine Transform). In the IJG code, this routine + * must also perform dequantization of the input coefficients. + * + * A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT + * on each row (or vice versa, but it's more convenient to emit a row at + * a time). Direct algorithms are also available, but they are much more + * complex and seem not to be any faster when reduced to code. + * + * This implementation is based on an algorithm described in + * C. Loeffler, A. Ligtenberg and G. Moschytz, "Practical Fast 1-D DCT + * Algorithms with 11 Multiplications", Proc. Int'l. Conf. on Acoustics, + * Speech, and Signal Processing 1989 (ICASSP '89), pp. 988-991. + * The primary algorithm described there uses 11 multiplies and 29 adds. + * We use their alternate method with 12 multiplies and 32 adds. + * The advantage of this method is that no data path contains more than one + * multiplication; this allows a very simple and accurate implementation in + * scaled fixed-point arithmetic, with a minimal number of shifts. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdct.h" /* Private declarations for DCT subsystem */ + +#ifdef DCT_ISLOW_SUPPORTED + + +/* + * This module is specialized to the case DCTSIZE = 8. + */ + +#if DCTSIZE != 8 + Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */ +#endif + + +/* + * The poop on this scaling stuff is as follows: + * + * Each 1-D IDCT step produces outputs which are a factor of sqrt(N) + * larger than the true IDCT outputs. The final outputs are therefore + * a factor of N larger than desired; since N=8 this can be cured by + * a simple right shift at the end of the algorithm. The advantage of + * this arrangement is that we save two multiplications per 1-D IDCT, + * because the y0 and y4 inputs need not be divided by sqrt(N). + * + * We have to do addition and subtraction of the integer inputs, which + * is no problem, and multiplication by fractional constants, which is + * a problem to do in integer arithmetic. We multiply all the constants + * by CONST_SCALE and convert them to integer constants (thus retaining + * CONST_BITS bits of precision in the constants). After doing a + * multiplication we have to divide the product by CONST_SCALE, with proper + * rounding, to produce the correct output. This division can be done + * cheaply as a right shift of CONST_BITS bits. We postpone shifting + * as long as possible so that partial sums can be added together with + * full fractional precision. + * + * The outputs of the first pass are scaled up by PASS1_BITS bits so that + * they are represented to better-than-integral precision. These outputs + * require BITS_IN_JSAMPLE + PASS1_BITS + 3 bits; this fits in a 16-bit word + * with the recommended scaling. (To scale up 12-bit sample data further, an + * intermediate INT32 array would be needed.) + * + * To avoid overflow of the 32-bit intermediate results in pass 2, we must + * have BITS_IN_JSAMPLE + CONST_BITS + PASS1_BITS <= 26. Error analysis + * shows that the values given below are the most effective. + */ + +#if BITS_IN_JSAMPLE == 8 +#define CONST_BITS 13 +#define PASS1_BITS 2 +#else +#define CONST_BITS 13 +#define PASS1_BITS 1 /* lose a little precision to avoid overflow */ +#endif + +/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus + * causing a lot of useless floating-point operations at run time. + * To get around this we use the following pre-calculated constants. + * If you change CONST_BITS you may want to add appropriate values. + * (With a reasonable C compiler, you can just rely on the FIX() macro...) + */ + +#if CONST_BITS == 13 +#define FIX_0_298631336 ((INT32) 2446) /* FIX(0.298631336) */ +#define FIX_0_390180644 ((INT32) 3196) /* FIX(0.390180644) */ +#define FIX_0_541196100 ((INT32) 4433) /* FIX(0.541196100) */ +#define FIX_0_765366865 ((INT32) 6270) /* FIX(0.765366865) */ +#define FIX_0_899976223 ((INT32) 7373) /* FIX(0.899976223) */ +#define FIX_1_175875602 ((INT32) 9633) /* FIX(1.175875602) */ +#define FIX_1_501321110 ((INT32) 12299) /* FIX(1.501321110) */ +#define FIX_1_847759065 ((INT32) 15137) /* FIX(1.847759065) */ +#define FIX_1_961570560 ((INT32) 16069) /* FIX(1.961570560) */ +#define FIX_2_053119869 ((INT32) 16819) /* FIX(2.053119869) */ +#define FIX_2_562915447 ((INT32) 20995) /* FIX(2.562915447) */ +#define FIX_3_072711026 ((INT32) 25172) /* FIX(3.072711026) */ +#else +#define FIX_0_298631336 FIX(0.298631336) +#define FIX_0_390180644 FIX(0.390180644) +#define FIX_0_541196100 FIX(0.541196100) +#define FIX_0_765366865 FIX(0.765366865) +#define FIX_0_899976223 FIX(0.899976223) +#define FIX_1_175875602 FIX(1.175875602) +#define FIX_1_501321110 FIX(1.501321110) +#define FIX_1_847759065 FIX(1.847759065) +#define FIX_1_961570560 FIX(1.961570560) +#define FIX_2_053119869 FIX(2.053119869) +#define FIX_2_562915447 FIX(2.562915447) +#define FIX_3_072711026 FIX(3.072711026) +#endif + + +/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result. + * For 8-bit samples with the recommended scaling, all the variable + * and constant values involved are no more than 16 bits wide, so a + * 16x16->32 bit multiply can be used instead of a full 32x32 multiply. + * For 12-bit samples, a full 32-bit multiplication will be needed. + */ + +#if BITS_IN_JSAMPLE == 8 +#define MULTIPLY(var,const) MULTIPLY16C16(var,const) +#else +#define MULTIPLY(var,const) ((var) * (const)) +#endif + + +/* Dequantize a coefficient by multiplying it by the multiplier-table + * entry; produce an int result. In this module, both inputs and result + * are 16 bits or less, so either int or short multiply will work. + */ + +#define DEQUANTIZE(coef,quantval) (((ISLOW_MULT_TYPE) (coef)) * (quantval)) + + +/* + * Perform dequantization and inverse DCT on one block of coefficients. + */ + +GLOBAL(void) +jpeg_idct_islow (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3; + INT32 tmp10, tmp11, tmp12, tmp13; + INT32 z1, z2, z3, z4, z5; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[DCTSIZE2]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. */ + /* Note results are scaled up by sqrt(8) compared to a true IDCT; */ + /* furthermore, we scale the results by 2**PASS1_BITS. */ + + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = DCTSIZE; ctr > 0; ctr--) { + /* Due to quantization, we will usually find that many of the input + * coefficients are zero, especially the AC terms. We can exploit this + * by short-circuiting the IDCT calculation for any column in which all + * the AC terms are zero. In that case each output is equal to the + * DC coefficient (with scale factor as needed). + * With typical images and quantization tables, half or more of the + * column DCT calculations can be simplified this way. + */ + + if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 && + inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*4] == 0 && + inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 && + inptr[DCTSIZE*7] == 0) { + /* AC terms all zero */ + int dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]) << PASS1_BITS; + + wsptr[DCTSIZE*0] = dcval; + wsptr[DCTSIZE*1] = dcval; + wsptr[DCTSIZE*2] = dcval; + wsptr[DCTSIZE*3] = dcval; + wsptr[DCTSIZE*4] = dcval; + wsptr[DCTSIZE*5] = dcval; + wsptr[DCTSIZE*6] = dcval; + wsptr[DCTSIZE*7] = dcval; + + inptr++; /* advance pointers to next column */ + quantptr++; + wsptr++; + continue; + } + + /* Even part: reverse the even part of the forward DCT. */ + /* The rotator is sqrt(2)*c(-6). */ + + z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + + z1 = MULTIPLY(z2 + z3, FIX_0_541196100); + tmp2 = z1 + MULTIPLY(z3, - FIX_1_847759065); + tmp3 = z1 + MULTIPLY(z2, FIX_0_765366865); + + z2 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + z3 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + + tmp0 = (z2 + z3) << CONST_BITS; + tmp1 = (z2 - z3) << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + /* Odd part per figure 8; the matrix is unitary and hence its + * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively. + */ + + tmp0 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + tmp1 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + tmp2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + tmp3 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + + z1 = tmp0 + tmp3; + z2 = tmp1 + tmp2; + z3 = tmp0 + tmp2; + z4 = tmp1 + tmp3; + z5 = MULTIPLY(z3 + z4, FIX_1_175875602); /* sqrt(2) * c3 */ + + tmp0 = MULTIPLY(tmp0, FIX_0_298631336); /* sqrt(2) * (-c1+c3+c5-c7) */ + tmp1 = MULTIPLY(tmp1, FIX_2_053119869); /* sqrt(2) * ( c1+c3-c5+c7) */ + tmp2 = MULTIPLY(tmp2, FIX_3_072711026); /* sqrt(2) * ( c1+c3+c5-c7) */ + tmp3 = MULTIPLY(tmp3, FIX_1_501321110); /* sqrt(2) * ( c1+c3-c5-c7) */ + z1 = MULTIPLY(z1, - FIX_0_899976223); /* sqrt(2) * (c7-c3) */ + z2 = MULTIPLY(z2, - FIX_2_562915447); /* sqrt(2) * (-c1-c3) */ + z3 = MULTIPLY(z3, - FIX_1_961570560); /* sqrt(2) * (-c3-c5) */ + z4 = MULTIPLY(z4, - FIX_0_390180644); /* sqrt(2) * (c5-c3) */ + + z3 += z5; + z4 += z5; + + tmp0 += z1 + z3; + tmp1 += z2 + z4; + tmp2 += z2 + z3; + tmp3 += z1 + z4; + + /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */ + + wsptr[DCTSIZE*0] = (int) DESCALE(tmp10 + tmp3, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*7] = (int) DESCALE(tmp10 - tmp3, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*1] = (int) DESCALE(tmp11 + tmp2, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*6] = (int) DESCALE(tmp11 - tmp2, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*2] = (int) DESCALE(tmp12 + tmp1, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*5] = (int) DESCALE(tmp12 - tmp1, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*3] = (int) DESCALE(tmp13 + tmp0, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*4] = (int) DESCALE(tmp13 - tmp0, CONST_BITS-PASS1_BITS); + + inptr++; /* advance pointers to next column */ + quantptr++; + wsptr++; + } + + /* Pass 2: process rows from work array, store into output array. */ + /* Note that we must descale the results by a factor of 8 == 2**3, */ + /* and also undo the PASS1_BITS scaling. */ + + wsptr = workspace; + for (ctr = 0; ctr < DCTSIZE; ctr++) { + outptr = output_buf[ctr] + output_col; + /* Rows of zeroes can be exploited in the same way as we did with columns. + * However, the column calculation has created many nonzero AC terms, so + * the simplification applies less often (typically 5% to 10% of the time). + * On machines with very fast multiplication, it's possible that the + * test takes more time than it's worth. In that case this section + * may be commented out. + */ + +#ifndef NO_ZERO_ROW_TEST + if (wsptr[1] == 0 && wsptr[2] == 0 && wsptr[3] == 0 && wsptr[4] == 0 && + wsptr[5] == 0 && wsptr[6] == 0 && wsptr[7] == 0) { + /* AC terms all zero */ + JSAMPLE dcval = range_limit[(int) DESCALE((INT32) wsptr[0], PASS1_BITS+3) + & RANGE_MASK]; + + outptr[0] = dcval; + outptr[1] = dcval; + outptr[2] = dcval; + outptr[3] = dcval; + outptr[4] = dcval; + outptr[5] = dcval; + outptr[6] = dcval; + outptr[7] = dcval; + + wsptr += DCTSIZE; /* advance pointer to next row */ + continue; + } +#endif + + /* Even part: reverse the even part of the forward DCT. */ + /* The rotator is sqrt(2)*c(-6). */ + + z2 = (INT32) wsptr[2]; + z3 = (INT32) wsptr[6]; + + z1 = MULTIPLY(z2 + z3, FIX_0_541196100); + tmp2 = z1 + MULTIPLY(z3, - FIX_1_847759065); + tmp3 = z1 + MULTIPLY(z2, FIX_0_765366865); + + tmp0 = ((INT32) wsptr[0] + (INT32) wsptr[4]) << CONST_BITS; + tmp1 = ((INT32) wsptr[0] - (INT32) wsptr[4]) << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + /* Odd part per figure 8; the matrix is unitary and hence its + * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively. + */ + + tmp0 = (INT32) wsptr[7]; + tmp1 = (INT32) wsptr[5]; + tmp2 = (INT32) wsptr[3]; + tmp3 = (INT32) wsptr[1]; + + z1 = tmp0 + tmp3; + z2 = tmp1 + tmp2; + z3 = tmp0 + tmp2; + z4 = tmp1 + tmp3; + z5 = MULTIPLY(z3 + z4, FIX_1_175875602); /* sqrt(2) * c3 */ + + tmp0 = MULTIPLY(tmp0, FIX_0_298631336); /* sqrt(2) * (-c1+c3+c5-c7) */ + tmp1 = MULTIPLY(tmp1, FIX_2_053119869); /* sqrt(2) * ( c1+c3-c5+c7) */ + tmp2 = MULTIPLY(tmp2, FIX_3_072711026); /* sqrt(2) * ( c1+c3+c5-c7) */ + tmp3 = MULTIPLY(tmp3, FIX_1_501321110); /* sqrt(2) * ( c1+c3-c5-c7) */ + z1 = MULTIPLY(z1, - FIX_0_899976223); /* sqrt(2) * (c7-c3) */ + z2 = MULTIPLY(z2, - FIX_2_562915447); /* sqrt(2) * (-c1-c3) */ + z3 = MULTIPLY(z3, - FIX_1_961570560); /* sqrt(2) * (-c3-c5) */ + z4 = MULTIPLY(z4, - FIX_0_390180644); /* sqrt(2) * (c5-c3) */ + + z3 += z5; + z4 += z5; + + tmp0 += z1 + z3; + tmp1 += z2 + z4; + tmp2 += z2 + z3; + tmp3 += z1 + z4; + + /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */ + + outptr[0] = range_limit[(int) DESCALE(tmp10 + tmp3, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[7] = range_limit[(int) DESCALE(tmp10 - tmp3, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) DESCALE(tmp11 + tmp2, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[6] = range_limit[(int) DESCALE(tmp11 - tmp2, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) DESCALE(tmp12 + tmp1, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[5] = range_limit[(int) DESCALE(tmp12 - tmp1, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) DESCALE(tmp13 + tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[4] = range_limit[(int) DESCALE(tmp13 - tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += DCTSIZE; /* advance pointer to next row */ + } +} + +#endif /* DCT_ISLOW_SUPPORTED */ diff --git a/Utilities/ITK/Utilities/itkjpeg/jidctred.c b/Utilities/ITK/Utilities/itkjpeg/jidctred.c new file mode 100644 index 0000000000000000000000000000000000000000..5df040c16daeab27505e90d0614546af4a06d698 --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jidctred.c @@ -0,0 +1,398 @@ +/* + * jidctred.c + * + * Copyright (C) 1994-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains inverse-DCT routines that produce reduced-size output: + * either 4x4, 2x2, or 1x1 pixels from an 8x8 DCT block. + * + * The implementation is based on the Loeffler, Ligtenberg and Moschytz (LL&M) + * algorithm used in jidctint.c. We simply replace each 8-to-8 1-D IDCT step + * with an 8-to-4 step that produces the four averages of two adjacent outputs + * (or an 8-to-2 step producing two averages of four outputs, for 2x2 output). + * These steps were derived by computing the corresponding values at the end + * of the normal LL&M code, then simplifying as much as possible. + * + * 1x1 is trivial: just take the DC coefficient divided by 8. + * + * See jidctint.c for additional comments. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdct.h" /* Private declarations for DCT subsystem */ + +#ifdef IDCT_SCALING_SUPPORTED + + +/* + * This module is specialized to the case DCTSIZE = 8. + */ + +#if DCTSIZE != 8 + Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */ +#endif + + +/* Scaling is the same as in jidctint.c. */ + +#if BITS_IN_JSAMPLE == 8 +#define CONST_BITS 13 +#define PASS1_BITS 2 +#else +#define CONST_BITS 13 +#define PASS1_BITS 1 /* lose a little precision to avoid overflow */ +#endif + +/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus + * causing a lot of useless floating-point operations at run time. + * To get around this we use the following pre-calculated constants. + * If you change CONST_BITS you may want to add appropriate values. + * (With a reasonable C compiler, you can just rely on the FIX() macro...) + */ + +#if CONST_BITS == 13 +#define FIX_0_211164243 ((INT32) 1730) /* FIX(0.211164243) */ +#define FIX_0_509795579 ((INT32) 4176) /* FIX(0.509795579) */ +#define FIX_0_601344887 ((INT32) 4926) /* FIX(0.601344887) */ +#define FIX_0_720959822 ((INT32) 5906) /* FIX(0.720959822) */ +#define FIX_0_765366865 ((INT32) 6270) /* FIX(0.765366865) */ +#define FIX_0_850430095 ((INT32) 6967) /* FIX(0.850430095) */ +#define FIX_0_899976223 ((INT32) 7373) /* FIX(0.899976223) */ +#define FIX_1_061594337 ((INT32) 8697) /* FIX(1.061594337) */ +#define FIX_1_272758580 ((INT32) 10426) /* FIX(1.272758580) */ +#define FIX_1_451774981 ((INT32) 11893) /* FIX(1.451774981) */ +#define FIX_1_847759065 ((INT32) 15137) /* FIX(1.847759065) */ +#define FIX_2_172734803 ((INT32) 17799) /* FIX(2.172734803) */ +#define FIX_2_562915447 ((INT32) 20995) /* FIX(2.562915447) */ +#define FIX_3_624509785 ((INT32) 29692) /* FIX(3.624509785) */ +#else +#define FIX_0_211164243 FIX(0.211164243) +#define FIX_0_509795579 FIX(0.509795579) +#define FIX_0_601344887 FIX(0.601344887) +#define FIX_0_720959822 FIX(0.720959822) +#define FIX_0_765366865 FIX(0.765366865) +#define FIX_0_850430095 FIX(0.850430095) +#define FIX_0_899976223 FIX(0.899976223) +#define FIX_1_061594337 FIX(1.061594337) +#define FIX_1_272758580 FIX(1.272758580) +#define FIX_1_451774981 FIX(1.451774981) +#define FIX_1_847759065 FIX(1.847759065) +#define FIX_2_172734803 FIX(2.172734803) +#define FIX_2_562915447 FIX(2.562915447) +#define FIX_3_624509785 FIX(3.624509785) +#endif + + +/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result. + * For 8-bit samples with the recommended scaling, all the variable + * and constant values involved are no more than 16 bits wide, so a + * 16x16->32 bit multiply can be used instead of a full 32x32 multiply. + * For 12-bit samples, a full 32-bit multiplication will be needed. + */ + +#if BITS_IN_JSAMPLE == 8 +#define MULTIPLY(var,const) MULTIPLY16C16(var,const) +#else +#define MULTIPLY(var,const) ((var) * (const)) +#endif + + +/* Dequantize a coefficient by multiplying it by the multiplier-table + * entry; produce an int result. In this module, both inputs and result + * are 16 bits or less, so either int or short multiply will work. + */ + +#define DEQUANTIZE(coef,quantval) (((ISLOW_MULT_TYPE) (coef)) * (quantval)) + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a reduced-size 4x4 output block. + */ + +GLOBAL(void) +jpeg_idct_4x4 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp0, tmp2, tmp10, tmp12; + INT32 z1, z2, z3, z4; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[DCTSIZE*4]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. */ + + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = DCTSIZE; ctr > 0; inptr++, quantptr++, wsptr++, ctr--) { + /* Don't bother to process column 4, because second pass won't use it */ + if (ctr == DCTSIZE-4) + continue; + if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 && + inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*5] == 0 && + inptr[DCTSIZE*6] == 0 && inptr[DCTSIZE*7] == 0) { + /* AC terms all zero; we need not examine term 4 for 4x4 output */ + int dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]) << PASS1_BITS; + + wsptr[DCTSIZE*0] = dcval; + wsptr[DCTSIZE*1] = dcval; + wsptr[DCTSIZE*2] = dcval; + wsptr[DCTSIZE*3] = dcval; + + continue; + } + + /* Even part */ + + tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + tmp0 <<= (CONST_BITS+1); + + z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + + tmp2 = MULTIPLY(z2, FIX_1_847759065) + MULTIPLY(z3, - FIX_0_765366865); + + tmp10 = tmp0 + tmp2; + tmp12 = tmp0 - tmp2; + + /* Odd part */ + + z1 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + z2 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + z3 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + z4 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + + tmp0 = MULTIPLY(z1, - FIX_0_211164243) /* sqrt(2) * (c3-c1) */ + + MULTIPLY(z2, FIX_1_451774981) /* sqrt(2) * (c3+c7) */ + + MULTIPLY(z3, - FIX_2_172734803) /* sqrt(2) * (-c1-c5) */ + + MULTIPLY(z4, FIX_1_061594337); /* sqrt(2) * (c5+c7) */ + + tmp2 = MULTIPLY(z1, - FIX_0_509795579) /* sqrt(2) * (c7-c5) */ + + MULTIPLY(z2, - FIX_0_601344887) /* sqrt(2) * (c5-c1) */ + + MULTIPLY(z3, FIX_0_899976223) /* sqrt(2) * (c3-c7) */ + + MULTIPLY(z4, FIX_2_562915447); /* sqrt(2) * (c1+c3) */ + + /* Final output stage */ + + wsptr[DCTSIZE*0] = (int) DESCALE(tmp10 + tmp2, CONST_BITS-PASS1_BITS+1); + wsptr[DCTSIZE*3] = (int) DESCALE(tmp10 - tmp2, CONST_BITS-PASS1_BITS+1); + wsptr[DCTSIZE*1] = (int) DESCALE(tmp12 + tmp0, CONST_BITS-PASS1_BITS+1); + wsptr[DCTSIZE*2] = (int) DESCALE(tmp12 - tmp0, CONST_BITS-PASS1_BITS+1); + } + + /* Pass 2: process 4 rows from work array, store into output array. */ + + wsptr = workspace; + for (ctr = 0; ctr < 4; ctr++) { + outptr = output_buf[ctr] + output_col; + /* It's not clear whether a zero row test is worthwhile here ... */ + +#ifndef NO_ZERO_ROW_TEST + if (wsptr[1] == 0 && wsptr[2] == 0 && wsptr[3] == 0 && + wsptr[5] == 0 && wsptr[6] == 0 && wsptr[7] == 0) { + /* AC terms all zero */ + JSAMPLE dcval = range_limit[(int) DESCALE((INT32) wsptr[0], PASS1_BITS+3) + & RANGE_MASK]; + + outptr[0] = dcval; + outptr[1] = dcval; + outptr[2] = dcval; + outptr[3] = dcval; + + wsptr += DCTSIZE; /* advance pointer to next row */ + continue; + } +#endif + + /* Even part */ + + tmp0 = ((INT32) wsptr[0]) << (CONST_BITS+1); + + tmp2 = MULTIPLY((INT32) wsptr[2], FIX_1_847759065) + + MULTIPLY((INT32) wsptr[6], - FIX_0_765366865); + + tmp10 = tmp0 + tmp2; + tmp12 = tmp0 - tmp2; + + /* Odd part */ + + z1 = (INT32) wsptr[7]; + z2 = (INT32) wsptr[5]; + z3 = (INT32) wsptr[3]; + z4 = (INT32) wsptr[1]; + + tmp0 = MULTIPLY(z1, - FIX_0_211164243) /* sqrt(2) * (c3-c1) */ + + MULTIPLY(z2, FIX_1_451774981) /* sqrt(2) * (c3+c7) */ + + MULTIPLY(z3, - FIX_2_172734803) /* sqrt(2) * (-c1-c5) */ + + MULTIPLY(z4, FIX_1_061594337); /* sqrt(2) * (c5+c7) */ + + tmp2 = MULTIPLY(z1, - FIX_0_509795579) /* sqrt(2) * (c7-c5) */ + + MULTIPLY(z2, - FIX_0_601344887) /* sqrt(2) * (c5-c1) */ + + MULTIPLY(z3, FIX_0_899976223) /* sqrt(2) * (c3-c7) */ + + MULTIPLY(z4, FIX_2_562915447); /* sqrt(2) * (c1+c3) */ + + /* Final output stage */ + + outptr[0] = range_limit[(int) DESCALE(tmp10 + tmp2, + CONST_BITS+PASS1_BITS+3+1) + & RANGE_MASK]; + outptr[3] = range_limit[(int) DESCALE(tmp10 - tmp2, + CONST_BITS+PASS1_BITS+3+1) + & RANGE_MASK]; + outptr[1] = range_limit[(int) DESCALE(tmp12 + tmp0, + CONST_BITS+PASS1_BITS+3+1) + & RANGE_MASK]; + outptr[2] = range_limit[(int) DESCALE(tmp12 - tmp0, + CONST_BITS+PASS1_BITS+3+1) + & RANGE_MASK]; + + wsptr += DCTSIZE; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a reduced-size 2x2 output block. + */ + +GLOBAL(void) +jpeg_idct_2x2 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp0, tmp10, z1; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[DCTSIZE*2]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. */ + + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = DCTSIZE; ctr > 0; inptr++, quantptr++, wsptr++, ctr--) { + /* Don't bother to process columns 2,4,6 */ + if (ctr == DCTSIZE-2 || ctr == DCTSIZE-4 || ctr == DCTSIZE-6) + continue; + if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*3] == 0 && + inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*7] == 0) { + /* AC terms all zero; we need not examine terms 2,4,6 for 2x2 output */ + int dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]) << PASS1_BITS; + + wsptr[DCTSIZE*0] = dcval; + wsptr[DCTSIZE*1] = dcval; + + continue; + } + + /* Even part */ + + z1 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + tmp10 = z1 << (CONST_BITS+2); + + /* Odd part */ + + z1 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + tmp0 = MULTIPLY(z1, - FIX_0_720959822); /* sqrt(2) * (c7-c5+c3-c1) */ + z1 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + tmp0 += MULTIPLY(z1, FIX_0_850430095); /* sqrt(2) * (-c1+c3+c5+c7) */ + z1 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + tmp0 += MULTIPLY(z1, - FIX_1_272758580); /* sqrt(2) * (-c1+c3-c5-c7) */ + z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + tmp0 += MULTIPLY(z1, FIX_3_624509785); /* sqrt(2) * (c1+c3+c5+c7) */ + + /* Final output stage */ + + wsptr[DCTSIZE*0] = (int) DESCALE(tmp10 + tmp0, CONST_BITS-PASS1_BITS+2); + wsptr[DCTSIZE*1] = (int) DESCALE(tmp10 - tmp0, CONST_BITS-PASS1_BITS+2); + } + + /* Pass 2: process 2 rows from work array, store into output array. */ + + wsptr = workspace; + for (ctr = 0; ctr < 2; ctr++) { + outptr = output_buf[ctr] + output_col; + /* It's not clear whether a zero row test is worthwhile here ... */ + +#ifndef NO_ZERO_ROW_TEST + if (wsptr[1] == 0 && wsptr[3] == 0 && wsptr[5] == 0 && wsptr[7] == 0) { + /* AC terms all zero */ + JSAMPLE dcval = range_limit[(int) DESCALE((INT32) wsptr[0], PASS1_BITS+3) + & RANGE_MASK]; + + outptr[0] = dcval; + outptr[1] = dcval; + + wsptr += DCTSIZE; /* advance pointer to next row */ + continue; + } +#endif + + /* Even part */ + + tmp10 = ((INT32) wsptr[0]) << (CONST_BITS+2); + + /* Odd part */ + + tmp0 = MULTIPLY((INT32) wsptr[7], - FIX_0_720959822) /* sqrt(2) * (c7-c5+c3-c1) */ + + MULTIPLY((INT32) wsptr[5], FIX_0_850430095) /* sqrt(2) * (-c1+c3+c5+c7) */ + + MULTIPLY((INT32) wsptr[3], - FIX_1_272758580) /* sqrt(2) * (-c1+c3-c5-c7) */ + + MULTIPLY((INT32) wsptr[1], FIX_3_624509785); /* sqrt(2) * (c1+c3+c5+c7) */ + + /* Final output stage */ + + outptr[0] = range_limit[(int) DESCALE(tmp10 + tmp0, + CONST_BITS+PASS1_BITS+3+2) + & RANGE_MASK]; + outptr[1] = range_limit[(int) DESCALE(tmp10 - tmp0, + CONST_BITS+PASS1_BITS+3+2) + & RANGE_MASK]; + + wsptr += DCTSIZE; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a reduced-size 1x1 output block. + */ + +GLOBAL(void) +jpeg_idct_1x1 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + int dcval; + ISLOW_MULT_TYPE * quantptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + SHIFT_TEMPS + + /* We hardly need an inverse DCT routine for this: just take the + * average pixel value, which is one-eighth of the DC coefficient. + */ + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + dcval = DEQUANTIZE(coef_block[0], quantptr[0]); + dcval = (int) DESCALE((INT32) dcval, 3); + + output_buf[0][output_col] = range_limit[dcval & RANGE_MASK]; +} + +#endif /* IDCT_SCALING_SUPPORTED */ diff --git a/Utilities/ITK/Utilities/itkjpeg/jinclude.h b/Utilities/ITK/Utilities/itkjpeg/jinclude.h new file mode 100644 index 0000000000000000000000000000000000000000..5d554f373c6782b53840aa572b27221ef008fb80 --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jinclude.h @@ -0,0 +1,91 @@ +/* + * jinclude.h + * + * Copyright (C) 1991-1994, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file exists to provide a single place to fix any problems with + * including the wrong system include files. (Common problems are taken + * care of by the standard jconfig symbols, but on really weird systems + * you may have to edit this file.) + * + * NOTE: this file is NOT intended to be included by applications using the + * JPEG library. Most applications need only include jpeglib.h. + */ + + +/* Include auto-config file to find out which system include files we need. */ + +#include "jconfig.h" /* auto configuration options */ +#define JCONFIG_INCLUDED /* so that jpeglib.h doesn't do it again */ + +/* + * We need the NULL macro and size_t typedef. + * On an ANSI-conforming system it is sufficient to include <stddef.h>. + * Otherwise, we get them from <stdlib.h> or <stdio.h>; we may have to + * pull in <sys/types.h> as well. + * Note that the core JPEG library does not require <stdio.h>; + * only the default error handler and data source/destination modules do. + * But we must pull it in because of the references to FILE in jpeglib.h. + * You can remove those references if you want to compile without <stdio.h>. + */ + +#ifdef HAVE_STDDEF_H +#include <stddef.h> +#endif + +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif + +#ifdef NEED_SYS_TYPES_H +#include <sys/types.h> +#endif + +#include <stdio.h> + +/* + * We need memory copying and zeroing functions, plus strncpy(). + * ANSI and System V implementations declare these in <string.h>. + * BSD doesn't have the mem() functions, but it does have bcopy()/bzero(). + * Some systems may declare memset and memcpy in <memory.h>. + * + * NOTE: we assume the size parameters to these functions are of type size_t. + * Change the casts in these macros if not! + */ + +#ifdef NEED_BSD_STRINGS + +#include <strings.h> +#define MEMZERO(target,size) bzero((void *)(target), (size_t)(size)) +#define MEMCOPY(dest,src,size) bcopy((const void *)(src), (void *)(dest), (size_t)(size)) + +#else /* not BSD, assume ANSI/SysV string lib */ + +#include <string.h> +#define MEMZERO(target,size) memset((void *)(target), 0, (size_t)(size)) +#define MEMCOPY(dest,src,size) memcpy((void *)(dest), (const void *)(src), (size_t)(size)) + +#endif + +/* + * In ANSI C, and indeed any rational implementation, size_t is also the + * type returned by sizeof(). However, it seems there are some irrational + * implementations out there, in which sizeof() returns an int even though + * size_t is defined as long or unsigned long. To ensure consistent results + * we always use this SIZEOF() macro in place of using sizeof() directly. + */ + +#define SIZEOF(object) ((size_t) sizeof(object)) + +/* + * The modules that use fread() and fwrite() always invoke them through + * these macros. On some systems you may need to twiddle the argument casts. + * CAUTION: argument order is different from underlying functions! + */ + +#define JFREAD(file,buf,sizeofbuf) \ + ((size_t) fread((void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file))) +#define JFWRITE(file,buf,sizeofbuf) \ + ((size_t) fwrite((const void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file))) diff --git a/Utilities/ITK/Utilities/itkjpeg/jlossls.h b/Utilities/ITK/Utilities/itkjpeg/jlossls.h new file mode 100644 index 0000000000000000000000000000000000000000..2feccd6d73f850b98d36a32196b74db0cc752d1f --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jlossls.h @@ -0,0 +1,151 @@ +/* + * jlossls.h + * + * Copyright (C) 1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This include file contains common declarations for the lossless JPEG + * codec modules. + */ + +#ifndef JLOSSLS_H +#define JLOSSLS_H + + +/* + * Table H.1: Predictors for lossless coding. + */ + +#define PREDICTOR1 Ra +#define PREDICTOR2 Rb +#define PREDICTOR3 Rc +#define PREDICTOR4 (int) ((INT32) Ra + (INT32) Rb - (INT32) Rc) +#define PREDICTOR5 (int) ((INT32) Ra + RIGHT_SHIFT((INT32) Rb - (INT32) Rc, 1)) +#define PREDICTOR6 (int) ((INT32) Rb + RIGHT_SHIFT((INT32) Ra - (INT32) Rc, 1)) +#define PREDICTOR7 (int) RIGHT_SHIFT((INT32) Ra + (INT32) Rb, 1) + + +typedef JMETHOD(void, predict_difference_method_ptr, + (j_compress_ptr cinfo, int ci, + JSAMPROW input_buf, JSAMPROW prev_row, + JDIFFROW diff_buf, JDIMENSION width)); + +typedef JMETHOD(void, scaler_method_ptr, + (j_compress_ptr cinfo, int ci, + JSAMPROW input_buf, JSAMPROW output_buf, + JDIMENSION width)); + +/* Lossless-specific compression codec (compressor proper) */ +typedef struct { + struct jpeg_c_codec pub; /* public fields */ + + + /* Difference buffer control */ + JMETHOD(void, diff_start_pass, (j_compress_ptr cinfo, + J_BUF_MODE pass_mode)); + + /* Pointer to data which is private to diff controller */ + void *diff_private; + + + /* Entropy encoding */ + JMETHOD(JDIMENSION, entropy_encode_mcus, (j_compress_ptr cinfo, + JDIFFIMAGE diff_buf, + JDIMENSION MCU_row_num, + JDIMENSION MCU_col_num, + JDIMENSION nMCU)); + + /* Pointer to data which is private to entropy module */ + void *entropy_private; + + + /* Prediction, differencing */ + JMETHOD(void, predict_start_pass, (j_compress_ptr cinfo)); + + /* It is useful to allow each component to have a separate diff method. */ + predict_difference_method_ptr predict_difference[MAX_COMPONENTS]; + + /* Pointer to data which is private to predictor module */ + void *pred_private; + + /* Sample scaling */ + JMETHOD(void, scaler_start_pass, (j_compress_ptr cinfo)); + JMETHOD(void, scaler_scale, (j_compress_ptr cinfo, + JSAMPROW input_buf, JSAMPROW output_buf, + JDIMENSION width)); + + /* Pointer to data which is private to scaler module */ + void *scaler_private; + +} jpeg_lossless_c_codec; + +typedef jpeg_lossless_c_codec * j_lossless_c_ptr; + + +typedef JMETHOD(void, predict_undifference_method_ptr, + (j_decompress_ptr cinfo, int comp_index, + JDIFFROW diff_buf, JDIFFROW prev_row, + JDIFFROW undiff_buf, JDIMENSION width)); + +/* Lossless-specific decompression codec (decompressor proper) */ +typedef struct { + struct jpeg_d_codec pub; /* public fields */ + + + /* Difference buffer control */ + JMETHOD(void, diff_start_input_pass, (j_decompress_ptr cinfo)); + + /* Pointer to data which is private to diff controller */ + void *diff_private; + + + /* Entropy decoding */ + JMETHOD(void, entropy_start_pass, (j_decompress_ptr cinfo)); + JMETHOD(boolean, entropy_process_restart, (j_decompress_ptr cinfo)); + JMETHOD(JDIMENSION, entropy_decode_mcus, (j_decompress_ptr cinfo, + JDIFFIMAGE diff_buf, + JDIMENSION MCU_row_num, + JDIMENSION MCU_col_num, + JDIMENSION nMCU)); + + /* Pointer to data which is private to entropy module */ + void *entropy_private; + + + /* Prediction, undifferencing */ + JMETHOD(void, predict_start_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, predict_process_restart, (j_decompress_ptr cinfo)); + + /* It is useful to allow each component to have a separate undiff method. */ + predict_undifference_method_ptr predict_undifference[MAX_COMPONENTS]; + + /* Pointer to data which is private to predictor module */ + void *pred_private; + + /* Sample scaling */ + JMETHOD(void, scaler_start_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, scaler_scale, (j_decompress_ptr cinfo, + JDIFFROW diff_buf, JSAMPROW output_buf, + JDIMENSION width)); + + /* Pointer to data which is private to scaler module */ + void *scaler_private; + +} jpeg_lossless_d_codec; + +typedef jpeg_lossless_d_codec * j_lossless_d_ptr; + + +/* Compression module initialization routines */ +EXTERN(void) jinit_lossless_c_codec JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_lhuff_encoder JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_differencer JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_c_scaler JPP((j_compress_ptr cinfo)); +/* Decompression module initialization routines */ +EXTERN(void) jinit_lossless_d_codec JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_lhuff_decoder JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_undifferencer JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_d_scaler JPP((j_decompress_ptr cinfo)); + +#endif /* JLOSSLS_H */ diff --git a/Utilities/ITK/Utilities/itkjpeg/jlossy.h b/Utilities/ITK/Utilities/itkjpeg/jlossy.h new file mode 100644 index 0000000000000000000000000000000000000000..83c43f04ef4cb7191ac9abef316a250331487f5e --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jlossy.h @@ -0,0 +1,120 @@ +/* + * jlossy.h + * + * Copyright (C) 1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This include file contains common declarations for the lossy (DCT-based) + * JPEG codec modules. + */ + +#ifndef JLOSSY_H +#define JLOSSY_H + + +/* Lossy-specific compression codec (compressor proper) */ +typedef struct { + struct jpeg_c_codec pub; /* public fields */ + + + /* Coefficient buffer control */ + JMETHOD(void, coef_start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); + /* JMETHOD(boolean, coef_compress_data, (j_compress_ptr cinfo, + JSAMPIMAGE input_buf));*/ + + /* Pointer to data which is private to coef module */ + void *coef_private; + + + /* Forward DCT (also controls coefficient quantization) */ + JMETHOD(void, fdct_start_pass, (j_compress_ptr cinfo)); + /* perhaps this should be an array??? */ + JMETHOD(void, fdct_forward_DCT, (j_compress_ptr cinfo, + jpeg_component_info * compptr, + JSAMPARRAY sample_data, JBLOCKROW coef_blocks, + JDIMENSION start_row, JDIMENSION start_col, + JDIMENSION num_blocks)); + + /* Pointer to data which is private to fdct module */ + void *fdct_private; + + + /* Entropy encoding */ + JMETHOD(boolean, entropy_encode_mcu, (j_compress_ptr cinfo, + JBLOCKROW *MCU_data)); + + /* Pointer to data which is private to entropy module */ + void *entropy_private; + +} jpeg_lossy_c_codec; + +typedef jpeg_lossy_c_codec * j_lossy_c_ptr; + + + +typedef JMETHOD(void, inverse_DCT_method_ptr, + (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col)); + +/* Lossy-specific decompression codec (decompressor proper) */ +typedef struct { + struct jpeg_d_codec pub; /* public fields */ + + + /* Coefficient buffer control */ + JMETHOD(void, coef_start_input_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, coef_start_output_pass, (j_decompress_ptr cinfo)); + + /* Pointer to array of coefficient virtual arrays, or NULL if none */ + jvirt_barray_ptr *coef_arrays; + + /* Pointer to data which is private to coef module */ + void *coef_private; + + + /* Entropy decoding */ + JMETHOD(void, entropy_start_pass, (j_decompress_ptr cinfo)); + JMETHOD(boolean, entropy_decode_mcu, (j_decompress_ptr cinfo, + JBLOCKROW *MCU_data)); + + /* This is here to share code between baseline and progressive decoders; */ + /* other modules probably should not use it */ + boolean entropy_insufficient_data; /* set TRUE after emitting warning */ + + /* Pointer to data which is private to entropy module */ + void *entropy_private; + + + /* Inverse DCT (also performs dequantization) */ + JMETHOD(void, idct_start_pass, (j_decompress_ptr cinfo)); + + /* It is useful to allow each component to have a separate IDCT method. */ + inverse_DCT_method_ptr inverse_DCT[MAX_COMPONENTS]; + + /* Pointer to data which is private to idct module */ + void *idct_private; + +} jpeg_lossy_d_codec; + +typedef jpeg_lossy_d_codec * j_lossy_d_ptr; + + +/* Compression module initialization routines */ +EXTERN(void) jinit_lossy_c_codec JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_c_coef_controller JPP((j_compress_ptr cinfo, + boolean need_full_buffer)); +EXTERN(void) jinit_forward_dct JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_shuff_encoder JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_phuff_encoder JPP((j_compress_ptr cinfo)); + +/* Decompression module initialization routines */ +EXTERN(void) jinit_lossy_d_codec JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_d_coef_controller JPP((j_decompress_ptr cinfo, + boolean need_full_buffer)); +EXTERN(void) jinit_shuff_decoder JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_phuff_decoder JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_inverse_dct JPP((j_decompress_ptr cinfo)); + +#endif /* JLOSSY_H */ diff --git a/Utilities/ITK/Utilities/itkjpeg/jmemmgr.c b/Utilities/ITK/Utilities/itkjpeg/jmemmgr.c new file mode 100644 index 0000000000000000000000000000000000000000..7e2db9d9e1aea9a006cde91ffacabda8149d0c17 --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jmemmgr.c @@ -0,0 +1,1174 @@ +/* + * jmemmgr.c + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the JPEG system-independent memory management + * routines. This code is usable across a wide variety of machines; most + * of the system dependencies have been isolated in a separate file. + * The major functions provided here are: + * * pool-based allocation and freeing of memory; + * * policy decisions about how to divide available memory among the + * virtual arrays; + * * control logic for swapping virtual arrays between main memory and + * backing storage. + * The separate system-dependent file provides the actual backing-storage + * access code, and it contains the policy decision about how much total + * main memory to use. + * This file is system-dependent in the sense that some of its functions + * are unnecessary in some systems. For example, if there is enough virtual + * memory so that backing storage will never be used, much of the virtual + * array control logic could be removed. (Of course, if you have that much + * memory then you shouldn't care about a little bit of unused code...) + */ + +#define JPEG_INTERNALS +#define AM_MEMORY_MANAGER /* we define jvirt_Xarray_control structs */ +#include "jinclude.h" +#include "jpeglib.h" +#include "jmemsys.h" /* import the system-dependent declarations */ + +#ifndef NO_GETENV +#ifndef HAVE_STDLIB_H /* <stdlib.h> should declare getenv() */ +extern char * getenv JPP((const char * name)); +#endif +#endif + + +/* + * Some important notes: + * The allocation routines provided here must never return NULL. + * They should exit to error_exit if unsuccessful. + * + * It's not a good idea to try to merge the sarray, barray and darray + * routines, even though they are textually almost the same, because + * samples are usually stored as bytes while coefficients and differenced + * are shorts or ints. Thus, in machines where byte pointers have a + * different representation from word pointers, the resulting machine + * code could not be the same. + */ + + +/* + * Many machines require storage alignment: longs must start on 4-byte + * boundaries, doubles on 8-byte boundaries, etc. On such machines, malloc() + * always returns pointers that are multiples of the worst-case alignment + * requirement, and we had better do so too. + * There isn't any really portable way to determine the worst-case alignment + * requirement. This module assumes that the alignment requirement is + * multiples of sizeof(ALIGN_TYPE). + * By default, we define ALIGN_TYPE as double. This is necessary on some + * workstations (where doubles really do need 8-byte alignment) and will work + * fine on nearly everything. If your machine has lesser alignment needs, + * you can save a few bytes by making ALIGN_TYPE smaller. + * The only place I know of where this will NOT work is certain Macintosh + * 680x0 compilers that define double as a 10-byte IEEE extended float. + * Doing 10-byte alignment is counterproductive because longwords won't be + * aligned well. Put "#define ALIGN_TYPE long" in jconfig.h if you have + * such a compiler. + */ + +#ifndef ALIGN_TYPE /* so can override from jconfig.h */ +#define ALIGN_TYPE double +#endif + + +/* + * We allocate objects from "pools", where each pool is gotten with a single + * request to jpeg_get_small() or jpeg_get_large(). There is no per-object + * overhead within a pool, except for alignment padding. Each pool has a + * header with a link to the next pool of the same class. + * Small and large pool headers are identical except that the latter's + * link pointer must be FAR on 80x86 machines. + * Notice that the "real" header fields are union'ed with a dummy ALIGN_TYPE + * field. This forces the compiler to make SIZEOF(small_pool_hdr) a multiple + * of the alignment requirement of ALIGN_TYPE. + */ + +typedef union small_pool_struct * small_pool_ptr; + +typedef union small_pool_struct { + struct { + small_pool_ptr next; /* next in list of pools */ + size_t bytes_used; /* how many bytes already used within pool */ + size_t bytes_left; /* bytes still available in this pool */ + } hdr; + ALIGN_TYPE dummy; /* included in union to ensure alignment */ +} small_pool_hdr; + +typedef union large_pool_struct FAR * large_pool_ptr; + +typedef union large_pool_struct { + struct { + large_pool_ptr next; /* next in list of pools */ + size_t bytes_used; /* how many bytes already used within pool */ + size_t bytes_left; /* bytes still available in this pool */ + } hdr; + ALIGN_TYPE dummy; /* included in union to ensure alignment */ +} large_pool_hdr; + + +/* + * Here is the full definition of a memory manager object. + */ + +typedef struct { + struct jpeg_memory_mgr pub; /* public fields */ + + /* Each pool identifier (lifetime class) names a linked list of pools. */ + small_pool_ptr small_list[JPOOL_NUMPOOLS]; + large_pool_ptr large_list[JPOOL_NUMPOOLS]; + + /* Since we only have one lifetime class of virtual arrays, only one + * linked list is necessary (for each datatype). Note that the virtual + * array control blocks being linked together are actually stored somewhere + * in the small-pool list. + */ + jvirt_sarray_ptr virt_sarray_list; + jvirt_barray_ptr virt_barray_list; + + /* This counts total space obtained from jpeg_get_small/large */ + long total_space_allocated; + + /* alloc_sarray and alloc_barray set this value for use by virtual + * array routines. + */ + JDIMENSION last_rowsperchunk; /* from most recent alloc_sarray/barray */ +} my_memory_mgr; + +typedef my_memory_mgr * my_mem_ptr; + + +/* + * The control blocks for virtual arrays. + * Note that these blocks are allocated in the "small" pool area. + * System-dependent info for the associated backing store (if any) is hidden + * inside the backing_store_info struct. + */ + +struct jvirt_sarray_control { + JSAMPARRAY mem_buffer; /* => the in-memory buffer */ + JDIMENSION rows_in_array; /* total virtual array height */ + JDIMENSION samplesperrow; /* width of array (and of memory buffer) */ + JDIMENSION maxaccess; /* max rows accessed by access_virt_sarray */ + JDIMENSION rows_in_mem; /* height of memory buffer */ + JDIMENSION rowsperchunk; /* allocation chunk size in mem_buffer */ + JDIMENSION cur_start_row; /* first logical row # in the buffer */ + JDIMENSION first_undef_row; /* row # of first uninitialized row */ + boolean pre_zero; /* pre-zero mode requested? */ + boolean dirty; /* do current buffer contents need written? */ + boolean b_s_open; /* is backing-store data valid? */ + jvirt_sarray_ptr next; /* link to next virtual sarray control block */ + backing_store_info b_s_info; /* System-dependent control info */ +}; + +struct jvirt_barray_control { + JBLOCKARRAY mem_buffer; /* => the in-memory buffer */ + JDIMENSION rows_in_array; /* total virtual array height */ + JDIMENSION blocksperrow; /* width of array (and of memory buffer) */ + JDIMENSION maxaccess; /* max rows accessed by access_virt_barray */ + JDIMENSION rows_in_mem; /* height of memory buffer */ + JDIMENSION rowsperchunk; /* allocation chunk size in mem_buffer */ + JDIMENSION cur_start_row; /* first logical row # in the buffer */ + JDIMENSION first_undef_row; /* row # of first uninitialized row */ + boolean pre_zero; /* pre-zero mode requested? */ + boolean dirty; /* do current buffer contents need written? */ + boolean b_s_open; /* is backing-store data valid? */ + jvirt_barray_ptr next; /* link to next virtual barray control block */ + backing_store_info b_s_info; /* System-dependent control info */ +}; + + +#ifdef MEM_STATS /* optional extra stuff for statistics */ + +LOCAL(void) +print_mem_stats (j_common_ptr cinfo, int pool_id) +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + small_pool_ptr shdr_ptr; + large_pool_ptr lhdr_ptr; + + /* Since this is only a debugging stub, we can cheat a little by using + * fprintf directly rather than going through the trace message code. + * This is helpful because message parm array can't handle longs. + */ + fprintf(stderr, "Freeing pool %d, total space = %ld\n", + pool_id, mem->total_space_allocated); + + for (lhdr_ptr = mem->large_list[pool_id]; lhdr_ptr != NULL; + lhdr_ptr = lhdr_ptr->hdr.next) { + fprintf(stderr, " Large chunk used %ld\n", + (long) lhdr_ptr->hdr.bytes_used); + } + + for (shdr_ptr = mem->small_list[pool_id]; shdr_ptr != NULL; + shdr_ptr = shdr_ptr->hdr.next) { + fprintf(stderr, " Small chunk used %ld free %ld\n", + (long) shdr_ptr->hdr.bytes_used, + (long) shdr_ptr->hdr.bytes_left); + } +} + +#endif /* MEM_STATS */ + + +LOCAL(void) +out_of_memory (j_common_ptr cinfo, int which) +/* Report an out-of-memory error and stop execution */ +/* If we compiled MEM_STATS support, report alloc requests before dying */ +{ +#ifdef MEM_STATS + cinfo->err->trace_level = 2; /* force self_destruct to report stats */ +#endif + ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, which); +} + + +/* + * Allocation of "small" objects. + * + * For these, we use pooled storage. When a new pool must be created, + * we try to get enough space for the current request plus a "slop" factor, + * where the slop will be the amount of leftover space in the new pool. + * The speed vs. space tradeoff is largely determined by the slop values. + * A different slop value is provided for each pool class (lifetime), + * and we also distinguish the first pool of a class from later ones. + * NOTE: the values given work fairly well on both 16- and 32-bit-int + * machines, but may be too small if longs are 64 bits or more. + */ + +static const size_t first_pool_slop[JPOOL_NUMPOOLS] = +{ + 1600, /* first PERMANENT pool */ + 16000 /* first IMAGE pool */ +}; + +static const size_t extra_pool_slop[JPOOL_NUMPOOLS] = +{ + 0, /* additional PERMANENT pools */ + 5000 /* additional IMAGE pools */ +}; + +#define MIN_SLOP 50 /* greater than 0 to avoid futile looping */ + + +METHODDEF(void *) +alloc_small (j_common_ptr cinfo, int pool_id, size_t sizeofobject) +/* Allocate a "small" object */ +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + small_pool_ptr hdr_ptr, prev_hdr_ptr; + char * data_ptr; + size_t odd_bytes, min_request, slop; + + /* Check for unsatisfiable request (do now to ensure no overflow below) */ + if (sizeofobject > (size_t) (MAX_ALLOC_CHUNK-SIZEOF(small_pool_hdr))) + out_of_memory(cinfo, 1); /* request exceeds malloc's ability */ + + /* Round up the requested size to a multiple of SIZEOF(ALIGN_TYPE) */ + odd_bytes = sizeofobject % SIZEOF(ALIGN_TYPE); + if (odd_bytes > 0) + sizeofobject += SIZEOF(ALIGN_TYPE) - odd_bytes; + + /* See if space is available in any existing pool */ + if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS) + ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */ + prev_hdr_ptr = NULL; + hdr_ptr = mem->small_list[pool_id]; + while (hdr_ptr != NULL) { + if (hdr_ptr->hdr.bytes_left >= sizeofobject) + break; /* found pool with enough space */ + prev_hdr_ptr = hdr_ptr; + hdr_ptr = hdr_ptr->hdr.next; + } + + /* Time to make a new pool? */ + if (hdr_ptr == NULL) { + /* min_request is what we need now, slop is what will be leftover */ + min_request = sizeofobject + SIZEOF(small_pool_hdr); + if (prev_hdr_ptr == NULL) /* first pool in class? */ + slop = first_pool_slop[pool_id]; + else + slop = extra_pool_slop[pool_id]; + /* Don't ask for more than MAX_ALLOC_CHUNK */ + if (slop > (size_t) (MAX_ALLOC_CHUNK-min_request)) + slop = (size_t) (MAX_ALLOC_CHUNK-min_request); + /* Try to get space, if fail reduce slop and try again */ + for (;;) { + hdr_ptr = (small_pool_ptr) jpeg_get_small(cinfo, min_request + slop); + if (hdr_ptr != NULL) + break; + slop /= 2; + if (slop < MIN_SLOP) /* give up when it gets real small */ + out_of_memory(cinfo, 2); /* jpeg_get_small failed */ + } + mem->total_space_allocated += min_request + slop; + /* Success, initialize the new pool header and add to end of list */ + hdr_ptr->hdr.next = NULL; + hdr_ptr->hdr.bytes_used = 0; + hdr_ptr->hdr.bytes_left = sizeofobject + slop; + if (prev_hdr_ptr == NULL) /* first pool in class? */ + mem->small_list[pool_id] = hdr_ptr; + else + prev_hdr_ptr->hdr.next = hdr_ptr; + } + + /* OK, allocate the object from the current pool */ + data_ptr = (char *) (hdr_ptr + 1); /* point to first data byte in pool */ + data_ptr += hdr_ptr->hdr.bytes_used; /* point to place for object */ + hdr_ptr->hdr.bytes_used += sizeofobject; + hdr_ptr->hdr.bytes_left -= sizeofobject; + + return (void *) data_ptr; +} + + +/* + * Allocation of "large" objects. + * + * The external semantics of these are the same as "small" objects, + * except that FAR pointers are used on 80x86. However the pool + * management heuristics are quite different. We assume that each + * request is large enough that it may as well be passed directly to + * jpeg_get_large; the pool management just links everything together + * so that we can free it all on demand. + * Note: the major use of "large" objects is in JSAMPARRAY and JBLOCKARRAY + * structures. The routines that create these structures (see below) + * deliberately bunch rows together to ensure a large request size. + */ + +METHODDEF(void FAR *) +alloc_large (j_common_ptr cinfo, int pool_id, size_t sizeofobject) +/* Allocate a "large" object */ +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + large_pool_ptr hdr_ptr; + size_t odd_bytes; + + /* Check for unsatisfiable request (do now to ensure no overflow below) */ + if (sizeofobject > (size_t) (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr))) + out_of_memory(cinfo, 3); /* request exceeds malloc's ability */ + + /* Round up the requested size to a multiple of SIZEOF(ALIGN_TYPE) */ + odd_bytes = sizeofobject % SIZEOF(ALIGN_TYPE); + if (odd_bytes > 0) + sizeofobject += SIZEOF(ALIGN_TYPE) - odd_bytes; + + /* Always make a new pool */ + if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS) + ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */ + + hdr_ptr = (large_pool_ptr) jpeg_get_large(cinfo, sizeofobject + + SIZEOF(large_pool_hdr)); + if (hdr_ptr == NULL) + out_of_memory(cinfo, 4); /* jpeg_get_large failed */ + mem->total_space_allocated += sizeofobject + SIZEOF(large_pool_hdr); + + /* Success, initialize the new pool header and add to list */ + hdr_ptr->hdr.next = mem->large_list[pool_id]; + /* We maintain space counts in each pool header for statistical purposes, + * even though they are not needed for allocation. + */ + hdr_ptr->hdr.bytes_used = sizeofobject; + hdr_ptr->hdr.bytes_left = 0; + mem->large_list[pool_id] = hdr_ptr; + + return (void FAR *) (hdr_ptr + 1); /* point to first data byte in pool */ +} + + +/* + * Creation of 2-D sample arrays. + * The pointers are in near heap, the samples themselves in FAR heap. + * + * To minimize allocation overhead and to allow I/O of large contiguous + * blocks, we allocate the sample rows in groups of as many rows as possible + * without exceeding MAX_ALLOC_CHUNK total bytes per allocation request. + * NB: the virtual array control routines, later in this file, know about + * this chunking of rows. The rowsperchunk value is left in the mem manager + * object so that it can be saved away if this sarray is the workspace for + * a virtual array. + */ + +METHODDEF(JSAMPARRAY) +alloc_sarray (j_common_ptr cinfo, int pool_id, + JDIMENSION samplesperrow, JDIMENSION numrows) +/* Allocate a 2-D sample array */ +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + JSAMPARRAY result; + JSAMPROW workspace; + JDIMENSION rowsperchunk, currow, i; + long ltemp; + + /* Calculate max # of rows allowed in one allocation chunk */ + ltemp = (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr)) / + ((long) samplesperrow * SIZEOF(JSAMPLE)); + if (ltemp <= 0) + ERREXIT(cinfo, JERR_WIDTH_OVERFLOW); + if (ltemp < (long) numrows) + rowsperchunk = (JDIMENSION) ltemp; + else + rowsperchunk = numrows; + mem->last_rowsperchunk = rowsperchunk; + + /* Get space for row pointers (small object) */ + result = (JSAMPARRAY) alloc_small(cinfo, pool_id, + (size_t) (numrows * SIZEOF(JSAMPROW))); + + /* Get the rows themselves (large objects) */ + currow = 0; + while (currow < numrows) { + rowsperchunk = MIN(rowsperchunk, numrows - currow); + workspace = (JSAMPROW) alloc_large(cinfo, pool_id, + (size_t) ((size_t) rowsperchunk * (size_t) samplesperrow + * SIZEOF(JSAMPLE))); + for (i = rowsperchunk; i > 0; i--) { + result[currow++] = workspace; + workspace += samplesperrow; + } + } + + return result; +} + + +/* + * Creation of 2-D coefficient-block arrays. + * This is essentially the same as the code for sample arrays, above. + */ + +METHODDEF(JBLOCKARRAY) +alloc_barray (j_common_ptr cinfo, int pool_id, + JDIMENSION blocksperrow, JDIMENSION numrows) +/* Allocate a 2-D coefficient-block array */ +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + JBLOCKARRAY result; + JBLOCKROW workspace; + JDIMENSION rowsperchunk, currow, i; + long ltemp; + + /* Calculate max # of rows allowed in one allocation chunk */ + ltemp = (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr)) / + ((long) blocksperrow * SIZEOF(JBLOCK)); + if (ltemp <= 0) + ERREXIT(cinfo, JERR_WIDTH_OVERFLOW); + if (ltemp < (long) numrows) + rowsperchunk = (JDIMENSION) ltemp; + else + rowsperchunk = numrows; + mem->last_rowsperchunk = rowsperchunk; + + /* Get space for row pointers (small object) */ + result = (JBLOCKARRAY) alloc_small(cinfo, pool_id, + (size_t) (numrows * SIZEOF(JBLOCKROW))); + + /* Get the rows themselves (large objects) */ + currow = 0; + while (currow < numrows) { + rowsperchunk = MIN(rowsperchunk, numrows - currow); + workspace = (JBLOCKROW) alloc_large(cinfo, pool_id, + (size_t) ((size_t) rowsperchunk * (size_t) blocksperrow + * SIZEOF(JBLOCK))); + for (i = rowsperchunk; i > 0; i--) { + result[currow++] = workspace; + workspace += blocksperrow; + } + } + + return result; +} + + +#ifdef NEED_DARRAY + +/* + * Creation of 2-D difference arrays. + * This is essentially the same as the code for sample arrays, above. + */ + +METHODDEF(JDIFFARRAY) +alloc_darray (j_common_ptr cinfo, int pool_id, + JDIMENSION diffsperrow, JDIMENSION numrows) +/* Allocate a 2-D difference array */ +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + JDIFFARRAY result; + JDIFFROW workspace; + JDIMENSION rowsperchunk, currow, i; + long ltemp; + + /* Calculate max # of rows allowed in one allocation chunk */ + ltemp = (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr)) / + ((long) diffsperrow * SIZEOF(JDIFF)); + if (ltemp <= 0) + ERREXIT(cinfo, JERR_WIDTH_OVERFLOW); + if (ltemp < (long) numrows) + rowsperchunk = (JDIMENSION) ltemp; + else + rowsperchunk = numrows; + mem->last_rowsperchunk = rowsperchunk; + + /* Get space for row pointers (small object) */ + result = (JDIFFARRAY) alloc_small(cinfo, pool_id, + (size_t) (numrows * SIZEOF(JDIFFROW))); + + /* Get the rows themselves (large objects) */ + currow = 0; + while (currow < numrows) { + rowsperchunk = MIN(rowsperchunk, numrows - currow); + workspace = (JDIFFROW) alloc_large(cinfo, pool_id, + (size_t) ((size_t) rowsperchunk * (size_t) diffsperrow + * SIZEOF(JDIFF))); + for (i = rowsperchunk; i > 0; i--) { + result[currow++] = workspace; + workspace += diffsperrow; + } + } + + return result; +} + +#endif + + +/* + * About virtual array management: + * + * The above "normal" array routines are only used to allocate strip buffers + * (as wide as the image, but just a few rows high). Full-image-sized buffers + * are handled as "virtual" arrays. The array is still accessed a strip at a + * time, but the memory manager must save the whole array for repeated + * accesses. The intended implementation is that there is a strip buffer in + * memory (as high as is possible given the desired memory limit), plus a + * backing file that holds the rest of the array. + * + * The request_virt_array routines are told the total size of the image and + * the maximum number of rows that will be accessed at once. The in-memory + * buffer must be at least as large as the maxaccess value. + * + * The request routines create control blocks but not the in-memory buffers. + * That is postponed until realize_virt_arrays is called. At that time the + * total amount of space needed is known (approximately, anyway), so free + * memory can be divided up fairly. + * + * The access_virt_array routines are responsible for making a specific strip + * area accessible (after reading or writing the backing file, if necessary). + * Note that the access routines are told whether the caller intends to modify + * the accessed strip; during a read-only pass this saves having to rewrite + * data to disk. The access routines are also responsible for pre-zeroing + * any newly accessed rows, if pre-zeroing was requested. + * + * In current usage, the access requests are usually for nonoverlapping + * strips; that is, successive access start_row numbers differ by exactly + * num_rows = maxaccess. This means we can get good performance with simple + * buffer dump/reload logic, by making the in-memory buffer be a multiple + * of the access height; then there will never be accesses across bufferload + * boundaries. The code will still work with overlapping access requests, + * but it doesn't handle bufferload overlaps very efficiently. + */ + + +METHODDEF(jvirt_sarray_ptr) +request_virt_sarray (j_common_ptr cinfo, int pool_id, boolean pre_zero, + JDIMENSION samplesperrow, JDIMENSION numrows, + JDIMENSION maxaccess) +/* Request a virtual 2-D sample array */ +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + jvirt_sarray_ptr result; + + /* Only IMAGE-lifetime virtual arrays are currently supported */ + if (pool_id != JPOOL_IMAGE) + ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */ + + /* get control block */ + result = (jvirt_sarray_ptr) alloc_small(cinfo, pool_id, + SIZEOF(struct jvirt_sarray_control)); + + result->mem_buffer = NULL; /* marks array not yet realized */ + result->rows_in_array = numrows; + result->samplesperrow = samplesperrow; + result->maxaccess = maxaccess; + result->pre_zero = pre_zero; + result->b_s_open = FALSE; /* no associated backing-store object */ + result->next = mem->virt_sarray_list; /* add to list of virtual arrays */ + mem->virt_sarray_list = result; + + return result; +} + + +METHODDEF(jvirt_barray_ptr) +request_virt_barray (j_common_ptr cinfo, int pool_id, boolean pre_zero, + JDIMENSION blocksperrow, JDIMENSION numrows, + JDIMENSION maxaccess) +/* Request a virtual 2-D coefficient-block array */ +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + jvirt_barray_ptr result; + + /* Only IMAGE-lifetime virtual arrays are currently supported */ + if (pool_id != JPOOL_IMAGE) + ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */ + + /* get control block */ + result = (jvirt_barray_ptr) alloc_small(cinfo, pool_id, + SIZEOF(struct jvirt_barray_control)); + + result->mem_buffer = NULL; /* marks array not yet realized */ + result->rows_in_array = numrows; + result->blocksperrow = blocksperrow; + result->maxaccess = maxaccess; + result->pre_zero = pre_zero; + result->b_s_open = FALSE; /* no associated backing-store object */ + result->next = mem->virt_barray_list; /* add to list of virtual arrays */ + mem->virt_barray_list = result; + + return result; +} + + +METHODDEF(void) +realize_virt_arrays (j_common_ptr cinfo) +/* Allocate the in-memory buffers for any unrealized virtual arrays */ +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + long space_per_minheight, maximum_space, avail_mem; + long minheights, max_minheights; + jvirt_sarray_ptr sptr; + jvirt_barray_ptr bptr; + + /* Compute the minimum space needed (maxaccess rows in each buffer) + * and the maximum space needed (full image height in each buffer). + * These may be of use to the system-dependent jpeg_mem_available routine. + */ + space_per_minheight = 0; + maximum_space = 0; + for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) { + if (sptr->mem_buffer == NULL) { /* if not realized yet */ + space_per_minheight += (long) sptr->maxaccess * + (long) sptr->samplesperrow * SIZEOF(JSAMPLE); + maximum_space += (long) sptr->rows_in_array * + (long) sptr->samplesperrow * SIZEOF(JSAMPLE); + } + } + for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) { + if (bptr->mem_buffer == NULL) { /* if not realized yet */ + space_per_minheight += (long) bptr->maxaccess * + (long) bptr->blocksperrow * SIZEOF(JBLOCK); + maximum_space += (long) bptr->rows_in_array * + (long) bptr->blocksperrow * SIZEOF(JBLOCK); + } + } + + if (space_per_minheight <= 0) + return; /* no unrealized arrays, no work */ + + /* Determine amount of memory to actually use; this is system-dependent. */ + avail_mem = jpeg_mem_available(cinfo, space_per_minheight, maximum_space, + mem->total_space_allocated); + + /* If the maximum space needed is available, make all the buffers full + * height; otherwise parcel it out with the same number of minheights + * in each buffer. + */ + if (avail_mem >= maximum_space) + max_minheights = 1000000000L; + else { + max_minheights = avail_mem / space_per_minheight; + /* If there doesn't seem to be enough space, try to get the minimum + * anyway. This allows a "stub" implementation of jpeg_mem_available(). + */ + if (max_minheights <= 0) + max_minheights = 1; + } + + /* Allocate the in-memory buffers and initialize backing store as needed. */ + + for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) { + if (sptr->mem_buffer == NULL) { /* if not realized yet */ + minheights = ((long) sptr->rows_in_array - 1L) / sptr->maxaccess + 1L; + if (minheights <= max_minheights) { + /* This buffer fits in memory */ + sptr->rows_in_mem = sptr->rows_in_array; + } else { + /* It doesn't fit in memory, create backing store. */ + sptr->rows_in_mem = (JDIMENSION) (max_minheights * sptr->maxaccess); + jpeg_open_backing_store(cinfo, & sptr->b_s_info, + (long) sptr->rows_in_array * + (long) sptr->samplesperrow * + (long) SIZEOF(JSAMPLE)); + sptr->b_s_open = TRUE; + } + sptr->mem_buffer = alloc_sarray(cinfo, JPOOL_IMAGE, + sptr->samplesperrow, sptr->rows_in_mem); + sptr->rowsperchunk = mem->last_rowsperchunk; + sptr->cur_start_row = 0; + sptr->first_undef_row = 0; + sptr->dirty = FALSE; + } + } + + for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) { + if (bptr->mem_buffer == NULL) { /* if not realized yet */ + minheights = ((long) bptr->rows_in_array - 1L) / bptr->maxaccess + 1L; + if (minheights <= max_minheights) { + /* This buffer fits in memory */ + bptr->rows_in_mem = bptr->rows_in_array; + } else { + /* It doesn't fit in memory, create backing store. */ + bptr->rows_in_mem = (JDIMENSION) (max_minheights * bptr->maxaccess); + jpeg_open_backing_store(cinfo, & bptr->b_s_info, + (long) bptr->rows_in_array * + (long) bptr->blocksperrow * + (long) SIZEOF(JBLOCK)); + bptr->b_s_open = TRUE; + } + bptr->mem_buffer = alloc_barray(cinfo, JPOOL_IMAGE, + bptr->blocksperrow, bptr->rows_in_mem); + bptr->rowsperchunk = mem->last_rowsperchunk; + bptr->cur_start_row = 0; + bptr->first_undef_row = 0; + bptr->dirty = FALSE; + } + } +} + + +LOCAL(void) +do_sarray_io (j_common_ptr cinfo, jvirt_sarray_ptr ptr, boolean writing) +/* Do backing store read or write of a virtual sample array */ +{ + long bytesperrow, file_offset, byte_count, rows, thisrow, i; + + bytesperrow = (long) ptr->samplesperrow * SIZEOF(JSAMPLE); + file_offset = ptr->cur_start_row * bytesperrow; + /* Loop to read or write each allocation chunk in mem_buffer */ + for (i = 0; i < (long) ptr->rows_in_mem; i += ptr->rowsperchunk) { + /* One chunk, but check for short chunk at end of buffer */ + rows = MIN((long) ptr->rowsperchunk, (long) ptr->rows_in_mem - i); + /* Transfer no more than is currently defined */ + thisrow = (long) ptr->cur_start_row + i; + rows = MIN(rows, (long) ptr->first_undef_row - thisrow); + /* Transfer no more than fits in file */ + rows = MIN(rows, (long) ptr->rows_in_array - thisrow); + if (rows <= 0) /* this chunk might be past end of file! */ + break; + byte_count = rows * bytesperrow; + if (writing) + (*ptr->b_s_info.write_backing_store) (cinfo, & ptr->b_s_info, + (void FAR *) ptr->mem_buffer[i], + file_offset, byte_count); + else + (*ptr->b_s_info.read_backing_store) (cinfo, & ptr->b_s_info, + (void FAR *) ptr->mem_buffer[i], + file_offset, byte_count); + file_offset += byte_count; + } +} + + +LOCAL(void) +do_barray_io (j_common_ptr cinfo, jvirt_barray_ptr ptr, boolean writing) +/* Do backing store read or write of a virtual coefficient-block array */ +{ + long bytesperrow, file_offset, byte_count, rows, thisrow, i; + + bytesperrow = (long) ptr->blocksperrow * SIZEOF(JBLOCK); + file_offset = ptr->cur_start_row * bytesperrow; + /* Loop to read or write each allocation chunk in mem_buffer */ + for (i = 0; i < (long) ptr->rows_in_mem; i += ptr->rowsperchunk) { + /* One chunk, but check for short chunk at end of buffer */ + rows = MIN((long) ptr->rowsperchunk, (long) ptr->rows_in_mem - i); + /* Transfer no more than is currently defined */ + thisrow = (long) ptr->cur_start_row + i; + rows = MIN(rows, (long) ptr->first_undef_row - thisrow); + /* Transfer no more than fits in file */ + rows = MIN(rows, (long) ptr->rows_in_array - thisrow); + if (rows <= 0) /* this chunk might be past end of file! */ + break; + byte_count = rows * bytesperrow; + if (writing) + (*ptr->b_s_info.write_backing_store) (cinfo, & ptr->b_s_info, + (void FAR *) ptr->mem_buffer[i], + file_offset, byte_count); + else + (*ptr->b_s_info.read_backing_store) (cinfo, & ptr->b_s_info, + (void FAR *) ptr->mem_buffer[i], + file_offset, byte_count); + file_offset += byte_count; + } +} + + +METHODDEF(JSAMPARRAY) +access_virt_sarray (j_common_ptr cinfo, jvirt_sarray_ptr ptr, + JDIMENSION start_row, JDIMENSION num_rows, + boolean writable) +/* Access the part of a virtual sample array starting at start_row */ +/* and extending for num_rows rows. writable is true if */ +/* caller intends to modify the accessed area. */ +{ + JDIMENSION end_row = start_row + num_rows; + JDIMENSION undef_row; + + /* debugging check */ + if (end_row > ptr->rows_in_array || num_rows > ptr->maxaccess || + ptr->mem_buffer == NULL) + ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); + + /* Make the desired part of the virtual array accessible */ + if (start_row < ptr->cur_start_row || + end_row > ptr->cur_start_row+ptr->rows_in_mem) { + if (! ptr->b_s_open) + ERREXIT(cinfo, JERR_VIRTUAL_BUG); + /* Flush old buffer contents if necessary */ + if (ptr->dirty) { + do_sarray_io(cinfo, ptr, TRUE); + ptr->dirty = FALSE; + } + /* Decide what part of virtual array to access. + * Algorithm: if target address > current window, assume forward scan, + * load starting at target address. If target address < current window, + * assume backward scan, load so that target area is top of window. + * Note that when switching from forward write to forward read, will have + * start_row = 0, so the limiting case applies and we load from 0 anyway. + */ + if (start_row > ptr->cur_start_row) { + ptr->cur_start_row = start_row; + } else { + /* use long arithmetic here to avoid overflow & unsigned problems */ + long ltemp; + + ltemp = (long) end_row - (long) ptr->rows_in_mem; + if (ltemp < 0) + ltemp = 0; /* don't fall off front end of file */ + ptr->cur_start_row = (JDIMENSION) ltemp; + } + /* Read in the selected part of the array. + * During the initial write pass, we will do no actual read + * because the selected part is all undefined. + */ + do_sarray_io(cinfo, ptr, FALSE); + } + /* Ensure the accessed part of the array is defined; prezero if needed. + * To improve locality of access, we only prezero the part of the array + * that the caller is about to access, not the entire in-memory array. + */ + if (ptr->first_undef_row < end_row) { + if (ptr->first_undef_row < start_row) { + if (writable) /* writer skipped over a section of array */ + ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); + undef_row = start_row; /* but reader is allowed to read ahead */ + } else { + undef_row = ptr->first_undef_row; + } + if (writable) + ptr->first_undef_row = end_row; + if (ptr->pre_zero) { + size_t bytesperrow = (size_t) ptr->samplesperrow * SIZEOF(JSAMPLE); + undef_row -= ptr->cur_start_row; /* make indexes relative to buffer */ + end_row -= ptr->cur_start_row; + while (undef_row < end_row) { + jzero_far((void FAR *) ptr->mem_buffer[undef_row], bytesperrow); + undef_row++; + } + } else { + if (! writable) /* reader looking at undefined data */ + ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); + } + } + /* Flag the buffer dirty if caller will write in it */ + if (writable) + ptr->dirty = TRUE; + /* Return address of proper part of the buffer */ + return ptr->mem_buffer + (start_row - ptr->cur_start_row); +} + + +METHODDEF(JBLOCKARRAY) +access_virt_barray (j_common_ptr cinfo, jvirt_barray_ptr ptr, + JDIMENSION start_row, JDIMENSION num_rows, + boolean writable) +/* Access the part of a virtual block array starting at start_row */ +/* and extending for num_rows rows. writable is true if */ +/* caller intends to modify the accessed area. */ +{ + JDIMENSION end_row = start_row + num_rows; + JDIMENSION undef_row; + + /* debugging check */ + if (end_row > ptr->rows_in_array || num_rows > ptr->maxaccess || + ptr->mem_buffer == NULL) + ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); + + /* Make the desired part of the virtual array accessible */ + if (start_row < ptr->cur_start_row || + end_row > ptr->cur_start_row+ptr->rows_in_mem) { + if (! ptr->b_s_open) + ERREXIT(cinfo, JERR_VIRTUAL_BUG); + /* Flush old buffer contents if necessary */ + if (ptr->dirty) { + do_barray_io(cinfo, ptr, TRUE); + ptr->dirty = FALSE; + } + /* Decide what part of virtual array to access. + * Algorithm: if target address > current window, assume forward scan, + * load starting at target address. If target address < current window, + * assume backward scan, load so that target area is top of window. + * Note that when switching from forward write to forward read, will have + * start_row = 0, so the limiting case applies and we load from 0 anyway. + */ + if (start_row > ptr->cur_start_row) { + ptr->cur_start_row = start_row; + } else { + /* use long arithmetic here to avoid overflow & unsigned problems */ + long ltemp; + + ltemp = (long) end_row - (long) ptr->rows_in_mem; + if (ltemp < 0) + ltemp = 0; /* don't fall off front end of file */ + ptr->cur_start_row = (JDIMENSION) ltemp; + } + /* Read in the selected part of the array. + * During the initial write pass, we will do no actual read + * because the selected part is all undefined. + */ + do_barray_io(cinfo, ptr, FALSE); + } + /* Ensure the accessed part of the array is defined; prezero if needed. + * To improve locality of access, we only prezero the part of the array + * that the caller is about to access, not the entire in-memory array. + */ + if (ptr->first_undef_row < end_row) { + if (ptr->first_undef_row < start_row) { + if (writable) /* writer skipped over a section of array */ + ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); + undef_row = start_row; /* but reader is allowed to read ahead */ + } else { + undef_row = ptr->first_undef_row; + } + if (writable) + ptr->first_undef_row = end_row; + if (ptr->pre_zero) { + size_t bytesperrow = (size_t) ptr->blocksperrow * SIZEOF(JBLOCK); + undef_row -= ptr->cur_start_row; /* make indexes relative to buffer */ + end_row -= ptr->cur_start_row; + while (undef_row < end_row) { + jzero_far((void FAR *) ptr->mem_buffer[undef_row], bytesperrow); + undef_row++; + } + } else { + if (! writable) /* reader looking at undefined data */ + ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); + } + } + /* Flag the buffer dirty if caller will write in it */ + if (writable) + ptr->dirty = TRUE; + /* Return address of proper part of the buffer */ + return ptr->mem_buffer + (start_row - ptr->cur_start_row); +} + + +/* + * Release all objects belonging to a specified pool. + */ + +METHODDEF(void) +free_pool (j_common_ptr cinfo, int pool_id) +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + small_pool_ptr shdr_ptr; + large_pool_ptr lhdr_ptr; + size_t space_freed; + + if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS) + ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */ + +#ifdef MEM_STATS + if (cinfo->err->trace_level > 1) + print_mem_stats(cinfo, pool_id); /* print pool's memory usage statistics */ +#endif + + /* If freeing IMAGE pool, close any virtual arrays first */ + if (pool_id == JPOOL_IMAGE) { + jvirt_sarray_ptr sptr; + jvirt_barray_ptr bptr; + + for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) { + if (sptr->b_s_open) { /* there may be no backing store */ + sptr->b_s_open = FALSE; /* prevent recursive close if error */ + (*sptr->b_s_info.close_backing_store) (cinfo, & sptr->b_s_info); + } + } + mem->virt_sarray_list = NULL; + for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) { + if (bptr->b_s_open) { /* there may be no backing store */ + bptr->b_s_open = FALSE; /* prevent recursive close if error */ + (*bptr->b_s_info.close_backing_store) (cinfo, & bptr->b_s_info); + } + } + mem->virt_barray_list = NULL; + } + + /* Release large objects */ + lhdr_ptr = mem->large_list[pool_id]; + mem->large_list[pool_id] = NULL; + + while (lhdr_ptr != NULL) { + large_pool_ptr next_lhdr_ptr = lhdr_ptr->hdr.next; + space_freed = lhdr_ptr->hdr.bytes_used + + lhdr_ptr->hdr.bytes_left + + SIZEOF(large_pool_hdr); + jpeg_free_large(cinfo, (void FAR *) lhdr_ptr, space_freed); + mem->total_space_allocated -= space_freed; + lhdr_ptr = next_lhdr_ptr; + } + + /* Release small objects */ + shdr_ptr = mem->small_list[pool_id]; + mem->small_list[pool_id] = NULL; + + while (shdr_ptr != NULL) { + small_pool_ptr next_shdr_ptr = shdr_ptr->hdr.next; + space_freed = shdr_ptr->hdr.bytes_used + + shdr_ptr->hdr.bytes_left + + SIZEOF(small_pool_hdr); + jpeg_free_small(cinfo, (void *) shdr_ptr, space_freed); + mem->total_space_allocated -= space_freed; + shdr_ptr = next_shdr_ptr; + } +} + + +/* + * Close up shop entirely. + * Note that this cannot be called unless cinfo->mem is non-NULL. + */ + +METHODDEF(void) +self_destruct (j_common_ptr cinfo) +{ + int pool; + + /* Close all backing store, release all memory. + * Releasing pools in reverse order might help avoid fragmentation + * with some (brain-damaged) malloc libraries. + */ + for (pool = JPOOL_NUMPOOLS-1; pool >= JPOOL_PERMANENT; pool--) { + free_pool(cinfo, pool); + } + + /* Release the memory manager control block too. */ + jpeg_free_small(cinfo, (void *) cinfo->mem, SIZEOF(my_memory_mgr)); + cinfo->mem = NULL; /* ensures I will be called only once */ + + jpeg_mem_term(cinfo); /* system-dependent cleanup */ +} + + +/* + * Memory manager initialization. + * When this is called, only the error manager pointer is valid in cinfo! + */ + +GLOBAL(void) +jinit_memory_mgr (j_common_ptr cinfo) +{ + my_mem_ptr mem; + long max_to_use; + int pool; + size_t test_mac; + + cinfo->mem = NULL; /* for safety if init fails */ + + /* Check for configuration errors. + * SIZEOF(ALIGN_TYPE) should be a power of 2; otherwise, it probably + * doesn't reflect any real hardware alignment requirement. + * The test is a little tricky: for X>0, X and X-1 have no one-bits + * in common if and only if X is a power of 2, ie has only one one-bit. + * Some compilers may give an "unreachable code" warning here; ignore it. + */ + if ((SIZEOF(ALIGN_TYPE) & (SIZEOF(ALIGN_TYPE)-1)) != 0) + ERREXIT(cinfo, JERR_BAD_ALIGN_TYPE); + /* MAX_ALLOC_CHUNK must be representable as type size_t, and must be + * a multiple of SIZEOF(ALIGN_TYPE). + * Again, an "unreachable code" warning may be ignored here. + * But a "constant too large" warning means you need to fix MAX_ALLOC_CHUNK. + */ + test_mac = (size_t) MAX_ALLOC_CHUNK; + if ((long) test_mac != MAX_ALLOC_CHUNK || + (MAX_ALLOC_CHUNK % SIZEOF(ALIGN_TYPE)) != 0) + ERREXIT(cinfo, JERR_BAD_ALLOC_CHUNK); + + max_to_use = jpeg_mem_init(cinfo); /* system-dependent initialization */ + + /* Attempt to allocate memory manager's control block */ + mem = (my_mem_ptr) jpeg_get_small(cinfo, SIZEOF(my_memory_mgr)); + + if (mem == NULL) { + jpeg_mem_term(cinfo); /* system-dependent cleanup */ + ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 0); + } + + /* OK, fill in the method pointers */ + mem->pub.alloc_small = alloc_small; + mem->pub.alloc_large = alloc_large; + mem->pub.alloc_sarray = alloc_sarray; + mem->pub.alloc_barray = alloc_barray; +#ifdef NEED_DARRAY + mem->pub.alloc_darray = alloc_darray; +#endif + mem->pub.request_virt_sarray = request_virt_sarray; + mem->pub.request_virt_barray = request_virt_barray; + mem->pub.realize_virt_arrays = realize_virt_arrays; + mem->pub.access_virt_sarray = access_virt_sarray; + mem->pub.access_virt_barray = access_virt_barray; + mem->pub.free_pool = free_pool; + mem->pub.self_destruct = self_destruct; + + /* Make MAX_ALLOC_CHUNK accessible to other modules */ + mem->pub.max_alloc_chunk = MAX_ALLOC_CHUNK; + + /* Initialize working state */ + mem->pub.max_memory_to_use = max_to_use; + + for (pool = JPOOL_NUMPOOLS-1; pool >= JPOOL_PERMANENT; pool--) { + mem->small_list[pool] = NULL; + mem->large_list[pool] = NULL; + } + mem->virt_sarray_list = NULL; + mem->virt_barray_list = NULL; + + mem->total_space_allocated = SIZEOF(my_memory_mgr); + + /* Declare ourselves open for business */ + cinfo->mem = & mem->pub; + + /* Check for an environment variable JPEGMEM; if found, override the + * default max_memory setting from jpeg_mem_init. Note that the + * surrounding application may again override this value. + * If your system doesn't support getenv(), define NO_GETENV to disable + * this feature. + */ +#ifndef NO_GETENV + { char * memenv; + + if ((memenv = getenv("JPEGMEM")) != NULL) { + char ch = 'x'; + + if (sscanf(memenv, "%ld%c", &max_to_use, &ch) > 0) { + if (ch == 'm' || ch == 'M') + max_to_use *= 1000L; + mem->pub.max_memory_to_use = max_to_use * 1000L; + } + } + } +#endif + +} diff --git a/Utilities/ITK/Utilities/itkjpeg/jmemnobs.c b/Utilities/ITK/Utilities/itkjpeg/jmemnobs.c new file mode 100644 index 0000000000000000000000000000000000000000..6757d4b3c21960e809b6c4c1b420c71a4c81363d --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jmemnobs.c @@ -0,0 +1,117 @@ +/* + * jmemnobs.c + * + * Copyright (C) 1992-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file provides a really simple implementation of the system- + * dependent portion of the JPEG memory manager. This implementation + * assumes that no backing-store files are needed: all required space + * can be obtained from malloc(). + * This is very portable in the sense that it'll compile on almost anything, + * but you'd better have lots of main memory (or virtual memory) if you want + * to process big images. + * Note that the max_memory_to_use option is ignored by this implementation. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jmemsys.h" /* import the system-dependent declarations */ + +#ifndef HAVE_STDLIB_H /* <stdlib.h> should declare malloc(),free() */ +extern void * malloc JPP((size_t size)); +extern void free JPP((void *ptr)); +#endif + + +/* + * Memory allocation and freeing are controlled by the regular library + * routines malloc() and free(). + */ + +GLOBAL(void *) +jpeg_get_small (j_common_ptr cinfo, size_t sizeofobject) +{ + (void)cinfo; + return (void *) malloc(sizeofobject); +} + +GLOBAL(void) +jpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject) +{ + (void)cinfo;(void)sizeofobject; + free(object); +} + + +/* + * "Large" objects are treated the same as "small" ones. + * NB: although we include FAR keywords in the routine declarations, + * this file won't actually work in 80x86 small/medium model; at least, + * you probably won't be able to process useful-size images in only 64KB. + */ + +GLOBAL(void FAR *) +jpeg_get_large (j_common_ptr cinfo, size_t sizeofobject) +{ + (void)cinfo; + return (void FAR *) malloc(sizeofobject); +} + +GLOBAL(void) +jpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject) +{ + (void)cinfo;(void)sizeofobject; + free(object); +} + + +/* + * This routine computes the total memory space available for allocation. + * Here we always say, "we got all you want bud!" + */ + +GLOBAL(long) +jpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed, + long max_bytes_needed, long already_allocated) +{ + (void)cinfo;(void)min_bytes_needed;(void)already_allocated; + return max_bytes_needed; +} + + +/* + * Backing store (temporary file) management. + * Since jpeg_mem_available always promised the moon, + * this should never be called and we can just error out. + */ + +GLOBAL(void) +jpeg_open_backing_store (j_common_ptr cinfo, backing_store_ptr info, + long total_bytes_needed) +{ + (void)info;(void)total_bytes_needed; + ERREXIT(cinfo, JERR_NO_BACKING_STORE); +} + + +/* + * These routines take care of any system-dependent initialization and + * cleanup required. Here, there isn't any. + */ + +GLOBAL(long) +jpeg_mem_init (j_common_ptr cinfo) +{ + (void)cinfo; + return 0; /* just set max_memory_to_use to 0 */ +} + +GLOBAL(void) +jpeg_mem_term (j_common_ptr cinfo) +{ + (void)cinfo; + /* no work */ +} diff --git a/Utilities/ITK/Utilities/itkjpeg/jmemsys.h b/Utilities/ITK/Utilities/itkjpeg/jmemsys.h new file mode 100644 index 0000000000000000000000000000000000000000..2e8ee7ee2f4faf3063721770956ee757b95a702a --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jmemsys.h @@ -0,0 +1,198 @@ +/* + * jmemsys.h + * + * Copyright (C) 1992-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This include file defines the interface between the system-independent + * and system-dependent portions of the JPEG memory manager. No other + * modules need include it. (The system-independent portion is jmemmgr.c; + * there are several different versions of the system-dependent portion.) + * + * This file works as-is for the system-dependent memory managers supplied + * in the IJG distribution. You may need to modify it if you write a + * custom memory manager. If system-dependent changes are needed in + * this file, the best method is to #ifdef them based on a configuration + * symbol supplied in jconfig.h, as we have done with USE_MSDOS_MEMMGR + * and USE_MAC_MEMMGR. + */ + + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_get_small jGetSmall +#define jpeg_free_small jFreeSmall +#define jpeg_get_large jGetLarge +#define jpeg_free_large jFreeLarge +#define jpeg_mem_available jMemAvail +#define jpeg_open_backing_store jOpenBackStore +#define jpeg_mem_init jMemInit +#define jpeg_mem_term jMemTerm +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + +/* + * These two functions are used to allocate and release small chunks of + * memory. (Typically the total amount requested through jpeg_get_small is + * no more than 20K or so; this will be requested in chunks of a few K each.) + * Behavior should be the same as for the standard library functions malloc + * and free; in particular, jpeg_get_small must return NULL on failure. + * On most systems, these ARE malloc and free. jpeg_free_small is passed the + * size of the object being freed, just in case it's needed. + * On an 80x86 machine using small-data memory model, these manage near heap. + */ + +EXTERN(void *) jpeg_get_small JPP((j_common_ptr cinfo, size_t sizeofobject)); +EXTERN(void) jpeg_free_small JPP((j_common_ptr cinfo, void * object, + size_t sizeofobject)); + +/* + * These two functions are used to allocate and release large chunks of + * memory (up to the total free space designated by jpeg_mem_available). + * The interface is the same as above, except that on an 80x86 machine, + * far pointers are used. On most other machines these are identical to + * the jpeg_get/free_small routines; but we keep them separate anyway, + * in case a different allocation strategy is desirable for large chunks. + */ + +EXTERN(void FAR *) jpeg_get_large JPP((j_common_ptr cinfo, + size_t sizeofobject)); +EXTERN(void) jpeg_free_large JPP((j_common_ptr cinfo, void FAR * object, + size_t sizeofobject)); + +/* + * The macro MAX_ALLOC_CHUNK designates the maximum number of bytes that may + * be requested in a single call to jpeg_get_large (and jpeg_get_small for that + * matter, but that case should never come into play). This macro is needed + * to model the 64Kb-segment-size limit of far addressing on 80x86 machines. + * On those machines, we expect that jconfig.h will provide a proper value. + * On machines with 32-bit flat address spaces, any large constant may be used. + * + * NB: jmemmgr.c expects that MAX_ALLOC_CHUNK will be representable as type + * size_t and will be a multiple of sizeof(align_type). + */ + +#ifndef MAX_ALLOC_CHUNK /* may be overridden in jconfig.h */ +#define MAX_ALLOC_CHUNK 1000000000L +#endif + +/* + * This routine computes the total space still available for allocation by + * jpeg_get_large. If more space than this is needed, backing store will be + * used. NOTE: any memory already allocated must not be counted. + * + * There is a minimum space requirement, corresponding to the minimum + * feasible buffer sizes; jmemmgr.c will request that much space even if + * jpeg_mem_available returns zero. The maximum space needed, enough to hold + * all working storage in memory, is also passed in case it is useful. + * Finally, the total space already allocated is passed. If no better + * method is available, cinfo->mem->max_memory_to_use - already_allocated + * is often a suitable calculation. + * + * It is OK for jpeg_mem_available to underestimate the space available + * (that'll just lead to more backing-store access than is really necessary). + * However, an overestimate will lead to failure. Hence it's wise to subtract + * a slop factor from the true available space. 5% should be enough. + * + * On machines with lots of virtual memory, any large constant may be returned. + * Conversely, zero may be returned to always use the minimum amount of memory. + */ + +EXTERN(long) jpeg_mem_available JPP((j_common_ptr cinfo, + long min_bytes_needed, + long max_bytes_needed, + long already_allocated)); + + +/* + * This structure holds whatever state is needed to access a single + * backing-store object. The read/write/close method pointers are called + * by jmemmgr.c to manipulate the backing-store object; all other fields + * are private to the system-dependent backing store routines. + */ + +#define TEMP_NAME_LENGTH 64 /* max length of a temporary file's name */ + + +#ifdef USE_MSDOS_MEMMGR /* DOS-specific junk */ + +typedef unsigned short XMSH; /* type of extended-memory handles */ +typedef unsigned short EMSH; /* type of expanded-memory handles */ + +typedef union { + short file_handle; /* DOS file handle if it's a temp file */ + XMSH xms_handle; /* handle if it's a chunk of XMS */ + EMSH ems_handle; /* handle if it's a chunk of EMS */ +} handle_union; + +#endif /* USE_MSDOS_MEMMGR */ + +#ifdef USE_MAC_MEMMGR /* Mac-specific junk */ +#include <Files.h> +#endif /* USE_MAC_MEMMGR */ + + +typedef struct backing_store_struct * backing_store_ptr; + +typedef struct backing_store_struct { + /* Methods for reading/writing/closing this backing-store object */ + JMETHOD(void, read_backing_store, (j_common_ptr cinfo, + backing_store_ptr info, + void FAR * buffer_address, + long file_offset, long byte_count)); + JMETHOD(void, write_backing_store, (j_common_ptr cinfo, + backing_store_ptr info, + void FAR * buffer_address, + long file_offset, long byte_count)); + JMETHOD(void, close_backing_store, (j_common_ptr cinfo, + backing_store_ptr info)); + + /* Private fields for system-dependent backing-store management */ +#ifdef USE_MSDOS_MEMMGR + /* For the MS-DOS manager (jmemdos.c), we need: */ + handle_union handle; /* reference to backing-store storage object */ + char temp_name[TEMP_NAME_LENGTH]; /* name if it's a file */ +#else +#ifdef USE_MAC_MEMMGR + /* For the Mac manager (jmemmac.c), we need: */ + short temp_file; /* file reference number to temp file */ + FSSpec tempSpec; /* the FSSpec for the temp file */ + char temp_name[TEMP_NAME_LENGTH]; /* name if it's a file */ +#else + /* For a typical implementation with temp files, we need: */ + FILE * temp_file; /* stdio reference to temp file */ + char temp_name[TEMP_NAME_LENGTH]; /* name of temp file */ +#endif +#endif +} backing_store_info; + + +/* + * Initial opening of a backing-store object. This must fill in the + * read/write/close pointers in the object. The read/write routines + * may take an error exit if the specified maximum file size is exceeded. + * (If jpeg_mem_available always returns a large value, this routine can + * just take an error exit.) + */ + +EXTERN(void) jpeg_open_backing_store JPP((j_common_ptr cinfo, + backing_store_ptr info, + long total_bytes_needed)); + + +/* + * These routines take care of any system-dependent initialization and + * cleanup required. jpeg_mem_init will be called before anything is + * allocated (and, therefore, nothing in cinfo is of use except the error + * manager pointer). It should return a suitable default value for + * max_memory_to_use; this may subsequently be overridden by the surrounding + * application. (Note that max_memory_to_use is only important if + * jpeg_mem_available chooses to consult it ... no one else will.) + * jpeg_mem_term may assume that all requested memory has been freed and that + * all opened backing-store objects have been closed. + */ + +EXTERN(long) jpeg_mem_init JPP((j_common_ptr cinfo)); +EXTERN(void) jpeg_mem_term JPP((j_common_ptr cinfo)); diff --git a/Utilities/ITK/Utilities/itkjpeg/jmorecfg.h.in b/Utilities/ITK/Utilities/itkjpeg/jmorecfg.h.in new file mode 100644 index 0000000000000000000000000000000000000000..60fb42b3c9414ef053f465ecd1b2f1b7aec5996b --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jmorecfg.h.in @@ -0,0 +1,437 @@ +/* + * jmorecfg.h + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains additional configuration options that customize the + * JPEG software for special applications or support machine-dependent + * optimizations. Most users will not need to touch this file. + */ + +#include "itkjpeg/jpegDllConfig.h" + +/* + * Define BITS_IN_JSAMPLE as either + * 8 for 8-bit sample values (the usual setting) + * 12 for 12-bit sample values + * Only 8 and 12 are legal data precisions for lossy JPEG according to the + * JPEG standard, and the IJG code does not support anything else! + * We do not support run-time selection of data precision, sorry. + */ + +/*#define BITS_IN_JSAMPLE 8*//* use 8 or 12 (or 16 only for lossless) */ +#define BITS_IN_JSAMPLE @CMAKE_BITS_IN_JSAMPLE@ + +/* + * Maximum number of components (color channels) allowed in JPEG image. + * To meet the letter of the JPEG spec, set this to 255. However, darn + * few applications need more than 4 channels (maybe 5 for CMYK + alpha + * mask). We recommend 10 as a reasonable compromise; use 4 if you are + * really short on memory. (Each allowed component costs a hundred or so + * bytes of storage, whether actually used in an image or not.) + */ + +#define MAX_COMPONENTS 10 /* maximum number of image components */ + + +/* + * Basic data types. + * You may need to change these if you have a machine with unusual data + * type sizes; for example, "char" not 8 bits, "short" not 16 bits, + * or "long" not 32 bits. We don't care whether "int" is 16 or 32 bits, + * but it had better be at least 16. + */ + +/* Representation of a single sample (pixel element value). + * We frequently allocate large arrays of these, so it's important to keep + * them small. But if you have memory to burn and access to char or short + * arrays is very slow on your hardware, you might want to change these. + */ + +#if BITS_IN_JSAMPLE == 8 +/* JSAMPLE should be the smallest type that will hold the values 0..255. + * You can use a signed char by having GETJSAMPLE mask it with 0xFF. + */ + +#ifdef HAVE_UNSIGNED_CHAR + +typedef unsigned char JSAMPLE; +#define GETJSAMPLE(value) ((int) (value)) + +#else /* not HAVE_UNSIGNED_CHAR */ + +typedef char JSAMPLE; +#ifdef CHAR_IS_UNSIGNED +#define GETJSAMPLE(value) ((int) (value)) +#else +#define GETJSAMPLE(value) ((int) (value) & 0xFF) +#endif /* CHAR_IS_UNSIGNED */ + +#endif /* HAVE_UNSIGNED_CHAR */ + +#define MAXJSAMPLE 255 +#define CENTERJSAMPLE 128 + +#endif /* BITS_IN_JSAMPLE == 8 */ + + +#if BITS_IN_JSAMPLE == 12 +/* JSAMPLE should be the smallest type that will hold the values 0..4095. + * On nearly all machines "short" will do nicely. + */ + +typedef short JSAMPLE; +#define GETJSAMPLE(value) ((int) (value)) + +#define MAXJSAMPLE 4095 +#define CENTERJSAMPLE 2048 + +#endif /* BITS_IN_JSAMPLE == 12 */ + + +#if BITS_IN_JSAMPLE == 16 +/* JSAMPLE should be the smallest type that will hold the values 0..65535. + * You can use a signed short by having GETJSAMPLE mask it with 0xFFFF. + */ + +#ifdef HAVE_UNSIGNED_SHORT + +typedef unsigned short JSAMPLE; +#define GETJSAMPLE(value) ((int) (value)) + +#else /* not HAVE_UNSIGNED_SHORT */ + +typedef short JSAMPLE; +#ifdef SHORT_IS_UNSIGNED +#define GETJSAMPLE(value) ((int) (value)) +#else +#define GETJSAMPLE(value) ((int) (value) & 0xFFFF) +#endif /* SHORT_IS_UNSIGNED */ + +#endif /* HAVE_UNSIGNED_SHORT */ + +#define MAXJSAMPLE 65535 +#define CENTERJSAMPLE 32768 + +#endif /* BITS_IN_JSAMPLE == 16 */ + + +/* Representation of a DCT frequency coefficient. + * This should be a signed value of at least 16 bits; "short" is usually OK. + * Again, we allocate large arrays of these, but you can change to int + * if you have memory to burn and "short" is really slow. + */ + +typedef short JCOEF; + + +/* Representation of a spatial difference value. + * This should be a signed value of at least 16 bits; int is usually OK. + */ + +typedef int JDIFF; + + +/* Compressed datastreams are represented as arrays of JOCTET. + * These must be EXACTLY 8 bits wide, at least once they are written to + * external storage. Note that when using the stdio data source/destination + * managers, this is also the data type passed to fread/fwrite. + */ + +#ifdef HAVE_UNSIGNED_CHAR + +typedef unsigned char JOCTET; +#define GETJOCTET(value) (value) + +#else /* not HAVE_UNSIGNED_CHAR */ + +typedef char JOCTET; +#ifdef CHAR_IS_UNSIGNED +#define GETJOCTET(value) (value) +#else +#define GETJOCTET(value) ((value) & 0xFF) +#endif /* CHAR_IS_UNSIGNED */ + +#endif /* HAVE_UNSIGNED_CHAR */ + + +/* These typedefs are used for various table entries and so forth. + * They must be at least as wide as specified; but making them too big + * won't cost a huge amount of memory, so we don't provide special + * extraction code like we did for JSAMPLE. (In other words, these + * typedefs live at a different point on the speed/space tradeoff curve.) + */ + +/* UINT8 must hold at least the values 0..255. */ + +#ifdef HAVE_UNSIGNED_CHAR +typedef unsigned char UINT8; +#else /* not HAVE_UNSIGNED_CHAR */ +#ifdef CHAR_IS_UNSIGNED +typedef char UINT8; +#else /* not CHAR_IS_UNSIGNED */ +typedef short UINT8; +#endif /* CHAR_IS_UNSIGNED */ +#endif /* HAVE_UNSIGNED_CHAR */ + +/* UINT16 must hold at least the values 0..65535. */ + +#ifdef HAVE_UNSIGNED_SHORT +typedef unsigned short UINT16; +#else /* not HAVE_UNSIGNED_SHORT */ +typedef unsigned int UINT16; +#endif /* HAVE_UNSIGNED_SHORT */ + +/* INT16 must hold at least the values -32768..32767. */ + +#ifndef XMD_H /* X11/xmd.h correctly defines INT16 */ +typedef short INT16; +#endif + +/* INT32 must hold at least signed 32-bit values. */ +/* X11/xmd.h and basetsd.h correctly defines INT32 */ + +#if !defined(XMD_H) && !(defined(_BASETSD_H_) || defined(_BASETSD_H)) +typedef int INT32; +#endif + +/* Datatype used for image dimensions. The JPEG standard only supports + * images up to 64K*64K due to 16-bit fields in SOF markers. Therefore + * "unsigned int" is sufficient on all machines. However, if you need to + * handle larger images and you don't mind deviating from the spec, you + * can change this datatype. + */ + +typedef unsigned int JDIMENSION; + +#define JPEG_MAX_DIMENSION 65500L /* a tad under 64K to prevent overflows */ + + +/* These macros are used in all function definitions and extern declarations. + * You could modify them if you need to change function linkage conventions; + * in particular, you'll need to do that to make the library a Windows DLL. + * Another application is to make all functions global for use with debuggers + * or code profilers that require it. + */ + +/* a function called through method pointers: */ +#define METHODDEF(type) static type +/* a function used only in its module: */ +#define LOCAL(type) static type +/* a function referenced thru EXTERNs: */ +#if defined( _WIN32 ) && defined (JPEGDLL) +#define GLOBAL(type) __declspec(dllexport) type +#else +#define GLOBAL(type) type +#endif + +/* a reference to a GLOBAL function: */ +#if defined(_WIN32) && !defined(JPEGSTATIC) +#ifdef JPEGDLL +/* Win32, building a dll */ +#define EXTERN(type) __declspec(dllexport) type +#else +/* Win32, not building a dll but using the dll */ +#define EXTERN(type) __declspec(dllimport) type +#endif +#else +/* not a Win32 system or building a static Win32 lib */ +#define EXTERN(type) extern type +#endif + + +/* This macro is used to declare a "method", that is, a function pointer. + * We want to supply prototype parameters if the compiler can cope. + * Note that the arglist parameter must be parenthesized! + * Again, you can customize this if you need special linkage keywords. + */ + +#ifdef HAVE_PROTOTYPES +#define JMETHOD(type,methodname,arglist) type (*methodname) arglist +#else +#define JMETHOD(type,methodname,arglist) type (*methodname) () +#endif + + +/* Here is the pseudo-keyword for declaring pointers that must be "far" + * on 80x86 machines. Most of the specialized coding for 80x86 is handled + * by just saying "FAR *" where such a pointer is needed. In a few places + * explicit coding is needed; see uses of the NEED_FAR_POINTERS symbol. + */ + +#ifndef FAR +#ifdef NEED_FAR_POINTERS +#define FAR far +#else +#define FAR +#endif +#endif + + +/* + * On a few systems, type boolean and/or its values FALSE, TRUE may appear + * in standard header files. Or you may have conflicts with application- + * specific header files that you want to include together with these files. + * Defining HAVE_BOOLEAN before including jpeglib.h should make it work. + */ + +#ifndef HAVE_BOOLEAN +typedef int boolean; +#endif +#ifndef FALSE /* in case these macros already exist */ +#define FALSE 0 /* values of boolean */ +#endif +#ifndef TRUE +#define TRUE 1 +#endif + + +/* + * The remaining options affect code selection within the JPEG library, + * but they don't need to be visible to most applications using the library. + * To minimize application namespace pollution, the symbols won't be + * defined unless JPEG_INTERNALS or JPEG_INTERNAL_OPTIONS has been defined. + */ + +#ifdef JPEG_INTERNALS +#define JPEG_INTERNAL_OPTIONS +#endif + +#ifdef JPEG_INTERNAL_OPTIONS + + +/* + * These defines indicate whether to include various optional functions. + * Undefining some of these symbols will produce a smaller but less capable + * library. Note that you can leave certain source files out of the + * compilation/linking process if you've #undef'd the corresponding symbols. + * (You may HAVE to do that if your compiler doesn't like null source files.) + */ + +/* Arithmetic coding is unsupported for legal reasons. Complaints to IBM. */ + +/* Capability options common to encoder and decoder: */ + +#define DCT_ISLOW_SUPPORTED /* slow but accurate integer algorithm */ +#define DCT_IFAST_SUPPORTED /* faster, less accurate integer method */ +#define DCT_FLOAT_SUPPORTED /* floating-point: accurate, fast on fast HW */ + +/* Encoder capability options: */ + +#undef C_ARITH_CODING_SUPPORTED /* Arithmetic coding back end? */ +#define C_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */ +#define C_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/ +#define C_LOSSLESS_SUPPORTED /* Lossless JPEG? */ +#define ENTROPY_OPT_SUPPORTED /* Optimization of entropy coding parms? */ +/* Note: if you selected 12-bit data precision, it is dangerous to turn off + * ENTROPY_OPT_SUPPORTED. The standard Huffman tables are only good for 8-bit + * precision, so jcshuff.c normally uses entropy optimization to compute + * usable tables for higher precision. If you don't want to do optimization, + * you'll have to supply different default Huffman tables. + * The exact same statements apply for progressive and lossless JPEG: + * the default tables don't work for progressive mode or lossless mode. + * (This may get fixed, however.) + */ +#define INPUT_SMOOTHING_SUPPORTED /* Input image smoothing option? */ + +/* Decoder capability options: */ + +#undef D_ARITH_CODING_SUPPORTED /* Arithmetic coding back end? */ +#define D_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */ +#define D_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/ +#define D_LOSSLESS_SUPPORTED /* Lossless JPEG? */ +#define SAVE_MARKERS_SUPPORTED /* jpeg_save_markers() needed? */ +#define BLOCK_SMOOTHING_SUPPORTED /* Block smoothing? (Progressive only) */ +#define IDCT_SCALING_SUPPORTED /* Output rescaling via IDCT? */ +#undef UPSAMPLE_SCALING_SUPPORTED /* Output rescaling at upsample stage? */ +#define UPSAMPLE_MERGING_SUPPORTED /* Fast path for sloppy upsampling? */ +#define QUANT_1PASS_SUPPORTED /* 1-pass color quantization? */ +#define QUANT_2PASS_SUPPORTED /* 2-pass color quantization? */ + +/* more capability options later, no doubt */ + + +/* + * Ordering of RGB data in scanlines passed to or from the application. + * If your application wants to deal with data in the order B,G,R, just + * change these macros. You can also deal with formats such as R,G,B,X + * (one extra byte per pixel) by changing RGB_PIXELSIZE. Note that changing + * the offsets will also change the order in which colormap data is organized. + * RESTRICTIONS: + * 1. The sample applications cjpeg,djpeg do NOT support modified RGB formats. + * 2. These macros only affect RGB<=>YCbCr color conversion, so they are not + * useful if you are using JPEG color spaces other than YCbCr or grayscale. + * 3. The color quantizer modules will not behave desirably if RGB_PIXELSIZE + * is not 3 (they don't understand about dummy color components!). So you + * can't use color quantization if you change that value. + */ + +#define RGB_RED 0 /* Offset of Red in an RGB scanline element */ +#define RGB_GREEN 1 /* Offset of Green */ +#define RGB_BLUE 2 /* Offset of Blue */ +#define RGB_PIXELSIZE 3 /* JSAMPLEs per RGB scanline element */ + + +/* Definitions for speed-related optimizations. */ + + +/* If your compiler supports inline functions, define INLINE + * as the inline keyword; otherwise define it as empty. + */ + +#ifndef INLINE +#ifdef __GNUC__ /* for instance, GNU C knows about inline */ +#define INLINE __inline__ +#endif +#ifndef INLINE +#define INLINE /* default is to define it as empty */ +#endif +#endif + + +/* On some machines (notably 68000 series) "int" is 32 bits, but multiplying + * two 16-bit shorts is faster than multiplying two ints. Define MULTIPLIER + * as short on such a machine. MULTIPLIER must be at least 16 bits wide. + */ + +#ifndef MULTIPLIER +#define MULTIPLIER int /* type for fastest integer multiply */ +#endif + + +/* FAST_FLOAT should be either float or double, whichever is done faster + * by your compiler. (Note that this type is only used in the floating point + * DCT routines, so it only matters if you've defined DCT_FLOAT_SUPPORTED.) + * Typically, float is faster in ANSI C compilers, while double is faster in + * pre-ANSI compilers (because they insist on converting to double anyway). + * The code below therefore chooses float if we have ANSI-style prototypes. + */ + +#ifndef FAST_FLOAT +#ifdef HAVE_PROTOTYPES +#define FAST_FLOAT float +#else +#define FAST_FLOAT double +#endif +#endif + +#if defined ( _MSC_VER ) +#pragma warning ( disable : 4100 ) +#pragma warning ( disable : 4115 ) +#pragma warning ( disable : 4127 ) +#pragma warning ( disable : 4244 ) +#pragma warning ( disable : 4251 ) +#pragma warning ( disable : 4267 ) +#pragma warning ( disable : 4305 ) +#pragma warning ( disable : 4309 ) +#pragma warning ( disable : 4706 ) +#pragma warning ( disable : 4786 ) +#pragma warning ( disable : 4057 ) +#pragma warning ( disable : 4189 ) +#pragma warning ( disable : 4505 ) +#endif + + +#endif /* JPEG_INTERNAL_OPTIONS */ diff --git a/Utilities/ITK/Utilities/itkjpeg/jpegDllConfig.h.in b/Utilities/ITK/Utilities/itkjpeg/jpegDllConfig.h.in new file mode 100644 index 0000000000000000000000000000000000000000..0baca6474e8f4cf2800d93639572268639df0e26 --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jpegDllConfig.h.in @@ -0,0 +1,6 @@ +#ifndef _jpegDllConfig_h +#define _jpegDllConfig_h + +#cmakedefine JPEGSTATIC + +#endif diff --git a/Utilities/ITK/Utilities/itkjpeg/jpegint.h b/Utilities/ITK/Utilities/itkjpeg/jpegint.h new file mode 100644 index 0000000000000000000000000000000000000000..684dada046a2e3eec675dca64e98bb9fd38fd200 --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jpegint.h @@ -0,0 +1,365 @@ +/* + * jpegint.h + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file provides common declarations for the various JPEG modules. + * These declarations are considered internal to the JPEG library; most + * applications using the library shouldn't need to include this file. + */ + + +/* Declarations for both compression & decompression */ + +typedef enum { /* Operating modes for buffer controllers */ + JBUF_PASS_THRU, /* Plain stripwise operation */ + /* Remaining modes require a full-image buffer to have been created */ + JBUF_SAVE_SOURCE, /* Run source subobject only, save output */ + JBUF_CRANK_DEST, /* Run dest subobject only, using saved data */ + JBUF_SAVE_AND_PASS /* Run both subobjects, save output */ +} J_BUF_MODE; + +/* Values of global_state field (jdapi.c has some dependencies on ordering!) */ +#define CSTATE_START 100 /* after create_compress */ +#define CSTATE_SCANNING 101 /* start_compress done, write_scanlines OK */ +#define CSTATE_RAW_OK 102 /* start_compress done, write_raw_data OK */ +#define CSTATE_WRCOEFS 103 /* jpeg_write_coefficients done */ +#define DSTATE_START 200 /* after create_decompress */ +#define DSTATE_INHEADER 201 /* reading header markers, no SOS yet */ +#define DSTATE_READY 202 /* found SOS, ready for start_decompress */ +#define DSTATE_PRELOAD 203 /* reading multiscan file in start_decompress*/ +#define DSTATE_PRESCAN 204 /* performing dummy pass for 2-pass quant */ +#define DSTATE_SCANNING 205 /* start_decompress done, read_scanlines OK */ +#define DSTATE_RAW_OK 206 /* start_decompress done, read_raw_data OK */ +#define DSTATE_BUFIMAGE 207 /* expecting jpeg_start_output */ +#define DSTATE_BUFPOST 208 /* looking for SOS/EOI in jpeg_finish_output */ +#define DSTATE_RDCOEFS 209 /* reading file in jpeg_read_coefficients */ +#define DSTATE_STOPPING 210 /* looking for EOI in jpeg_finish_decompress */ + + +/* Declarations for compression modules */ + +/* Master control module */ +struct jpeg_comp_master { + JMETHOD(void, prepare_for_pass, (j_compress_ptr cinfo)); + JMETHOD(void, pass_startup, (j_compress_ptr cinfo)); + JMETHOD(void, finish_pass, (j_compress_ptr cinfo)); + + /* State variables made visible to other modules */ + boolean call_pass_startup; /* True if pass_startup must be called */ + boolean is_last_pass; /* True during last pass */ +}; + +/* Main buffer control (downsampled-data buffer) */ +struct jpeg_c_main_controller { + JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); + JMETHOD(void, process_data, (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JDIMENSION *in_row_ctr, + JDIMENSION in_rows_avail)); +}; + +/* Compression preprocessing (downsampling input buffer control) */ +struct jpeg_c_prep_controller { + JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); + JMETHOD(void, pre_process_data, (j_compress_ptr cinfo, + JSAMPARRAY input_buf, + JDIMENSION *in_row_ctr, + JDIMENSION in_rows_avail, + JSAMPIMAGE output_buf, + JDIMENSION *out_row_group_ctr, + JDIMENSION out_row_groups_avail)); +}; + +/* Compression codec (compressor proper) */ +struct jpeg_c_codec { + JMETHOD(void, entropy_start_pass, (j_compress_ptr cinfo, + boolean gather_statistics)); + JMETHOD(void, entropy_finish_pass, (j_compress_ptr cinfo)); + JMETHOD(boolean, need_optimization_pass, (j_compress_ptr cinfo)); + JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); + JMETHOD(boolean, compress_data, (j_compress_ptr cinfo, + JSAMPIMAGE input_buf)); +}; + +/* Colorspace conversion */ +struct jpeg_color_converter { + JMETHOD(void, start_pass, (j_compress_ptr cinfo)); + JMETHOD(void, color_convert, (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows)); +}; + +/* Downsampling */ +struct jpeg_downsampler { + JMETHOD(void, start_pass, (j_compress_ptr cinfo)); + JMETHOD(void, downsample, (j_compress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION in_row_index, + JSAMPIMAGE output_buf, + JDIMENSION out_row_group_index)); + + boolean need_context_rows; /* TRUE if need rows above & below */ +}; + +/* Marker writing */ +struct jpeg_marker_writer { + JMETHOD(void, write_file_header, (j_compress_ptr cinfo)); + JMETHOD(void, write_frame_header, (j_compress_ptr cinfo)); + JMETHOD(void, write_scan_header, (j_compress_ptr cinfo)); + JMETHOD(void, write_file_trailer, (j_compress_ptr cinfo)); + JMETHOD(void, write_tables_only, (j_compress_ptr cinfo)); + /* These routines are exported to allow insertion of extra markers */ + /* Probably only COM and APPn markers should be written this way */ + JMETHOD(void, write_marker_header, (j_compress_ptr cinfo, int marker, + unsigned int datalen)); + JMETHOD(void, write_marker_byte, (j_compress_ptr cinfo, int val)); +}; + + +/* Declarations for decompression modules */ + +/* Master control module */ +struct jpeg_decomp_master { + JMETHOD(void, prepare_for_output_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, finish_output_pass, (j_decompress_ptr cinfo)); + + /* State variables made visible to other modules */ + boolean is_dummy_pass; /* True during 1st pass for 2-pass quant */ +}; + +/* Input control module */ +struct jpeg_input_controller { + JMETHOD(int, consume_input, (j_decompress_ptr cinfo)); + JMETHOD(void, reset_input_controller, (j_decompress_ptr cinfo)); + JMETHOD(void, start_input_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, finish_input_pass, (j_decompress_ptr cinfo)); + + /* State variables made visible to other modules */ + boolean has_multiple_scans; /* True if file has multiple scans */ + boolean eoi_reached; /* True when EOI has been consumed */ +}; + +/* Main buffer control (downsampled-data buffer) */ +struct jpeg_d_main_controller { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo, J_BUF_MODE pass_mode)); + JMETHOD(void, process_data, (j_decompress_ptr cinfo, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail)); +}; + +/* Decompression codec (decompressor proper) */ +struct jpeg_d_codec { + JMETHOD(void, calc_output_dimensions, (j_decompress_ptr cinfo)); + JMETHOD(void, start_input_pass, (j_decompress_ptr cinfo)); + JMETHOD(int, consume_data, (j_decompress_ptr cinfo)); + JMETHOD(void, start_output_pass, (j_decompress_ptr cinfo)); + JMETHOD(int, decompress_data, (j_decompress_ptr cinfo, + JSAMPIMAGE output_buf)); +}; + +/* Decompression postprocessing (color quantization buffer control) */ +struct jpeg_d_post_controller { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo, J_BUF_MODE pass_mode)); + JMETHOD(void, post_process_data, (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, + JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, + JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail)); +}; + +/* Marker reading & parsing */ +struct jpeg_marker_reader { + JMETHOD(void, reset_marker_reader, (j_decompress_ptr cinfo)); + /* Read markers until SOS or EOI. + * Returns same codes as are defined for jpeg_consume_input: + * JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI. + */ + JMETHOD(int, read_markers, (j_decompress_ptr cinfo)); + /* Read a restart marker --- exported for use by entropy decoder only */ + jpeg_marker_parser_method read_restart_marker; + + /* State of marker reader --- nominally internal, but applications + * supplying COM or APPn handlers might like to know the state. + */ + boolean saw_SOI; /* found SOI? */ + boolean saw_SOF; /* found SOF? */ + int next_restart_num; /* next restart number expected (0-7) */ + unsigned int discarded_bytes; /* # of bytes skipped looking for a marker */ +}; + +/* Upsampling (note that upsampler must also call color converter) */ +struct jpeg_upsampler { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, upsample, (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, + JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, + JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail)); + + boolean need_context_rows; /* TRUE if need rows above & below */ +}; + +/* Colorspace conversion */ +struct jpeg_color_deconverter { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, color_convert, (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows)); +}; + +/* Color quantization or color precision reduction */ +struct jpeg_color_quantizer { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo, boolean is_pre_scan)); + JMETHOD(void, color_quantize, (j_decompress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPARRAY output_buf, + int num_rows)); + JMETHOD(void, finish_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, new_color_map, (j_decompress_ptr cinfo)); +}; + + +/* Miscellaneous useful macros */ + +#undef MAX +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#undef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) + + +/* We assume that right shift corresponds to signed division by 2 with + * rounding towards minus infinity. This is correct for typical "arithmetic + * shift" instructions that shift in copies of the sign bit. But some + * C compilers implement >> with an unsigned shift. For these machines you + * must define RIGHT_SHIFT_IS_UNSIGNED. + * RIGHT_SHIFT provides a proper signed right shift of an INT32 quantity. + * It is only applied with constant shift counts. SHIFT_TEMPS must be + * included in the variables of any routine using RIGHT_SHIFT. + */ + +#ifdef RIGHT_SHIFT_IS_UNSIGNED +#define SHIFT_TEMPS INT32 shift_temp; +#define RIGHT_SHIFT(x,shft) \ + ((shift_temp = (x)) < 0 ? \ + (shift_temp >> (shft)) | ((~((INT32) 0)) << (32-(shft))) : \ + (shift_temp >> (shft))) +#else +#define SHIFT_TEMPS +#define RIGHT_SHIFT(x,shft) ((x) >> (shft)) +#endif + + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jinit_c_codec jICCodec +#define jinit_c_diff_controller jICDiffC +#define jinit_lossy_c_codec jILossyC +#define jinit_lossless_c_codec jILosslessC +#define jinit_compress_master jICompress +#define jinit_c_master_control jICMaster +#define jinit_c_main_controller jICMainC +#define jinit_c_prep_controller jICPrepC +#define jinit_c_coef_controller jICCoefC +#define jinit_color_converter jICColor +#define jinit_downsampler jIDownsampler +#define jinit_forward_dct jIFDCT +#define jinit_shuff_encoder jISHEncoder +#define jinit_phuff_encoder jIPHEncoder +#define jinit_arith_encoder jIAEncoder +#define jinit_marker_writer jIMWriter +#define jinit_d_codec jIDCodec +#define jinit_lossy_d_codec jILossyD +#define jinit_lossless_d_codec jILosslsD +#define jinit_master_decompress jIDMaster +#define jinit_d_main_controller jIDMainC +#define jinit_d_coef_controller jIDCoefC +#define jinit_d_diff_controller jIDDiffC +#define jinit_d_post_controller jIDPostC +#define jinit_input_controller jIInCtlr +#define jinit_marker_reader jIMReader +#define jinit_shuff_decoder jISHDecoder +#define jinit_phuff_decoder jIPHDecoder +#define jinit_arith_decoder jIADecoder +#define jinit_lhuff_decoder jILHDecoder +#define jinit_undifferencer jIUndiff +#define jinit_d_scaler jIDScaler +#define jinit_inverse_dct jIIDCT +#define jinit_upsampler jIUpsampler +#define jinit_color_deconverter jIDColor +#define jinit_1pass_quantizer jI1Quant +#define jinit_2pass_quantizer jI2Quant +#define jinit_merged_upsampler jIMUpsampler +#define jinit_memory_mgr jIMemMgr +#define jdiv_round_up jDivRound +#define jround_up jRound +#define jcopy_sample_rows jCopySamples +#define jcopy_block_row jCopyBlocks +#define jzero_far jZeroFar +#define jpeg_zigzag_order jZIGTable +#define jpeg_natural_order jZAGTable +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + +/* Compression module initialization routines */ +EXTERN(void) jinit_c_codec JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_c_diff_controller JPP((j_compress_ptr cinfo, boolean need_full_buffer)); +EXTERN(void) jinit_compress_master JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_c_master_control JPP((j_compress_ptr cinfo, + boolean transcode_only)); +EXTERN(void) jinit_c_main_controller JPP((j_compress_ptr cinfo, + boolean need_full_buffer)); +EXTERN(void) jinit_c_prep_controller JPP((j_compress_ptr cinfo, + boolean need_full_buffer)); +EXTERN(void) jinit_compressor JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_color_converter JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_downsampler JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_marker_writer JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_arith_encoder JPP((j_compress_ptr cinfo)); +/* Decompression module initialization routines */ +EXTERN(void) jinit_d_codec JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_d_diff_controller JPP((j_decompress_ptr cinfo, boolean need_full_buffer)); +EXTERN(void) jinit_master_decompress JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_d_main_controller JPP((j_decompress_ptr cinfo, + boolean need_full_buffer)); +EXTERN(void) jinit_decompressor JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_d_post_controller JPP((j_decompress_ptr cinfo, + boolean need_full_buffer)); +EXTERN(void) jinit_input_controller JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_marker_reader JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_arith_decoder JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_upsampler JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_color_deconverter JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_1pass_quantizer JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_2pass_quantizer JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_merged_upsampler JPP((j_decompress_ptr cinfo)); +/* Memory manager initialization */ +EXTERN(void) jinit_memory_mgr JPP((j_common_ptr cinfo)); + +/* Utility routines in jutils.c */ +EXTERN(long) jdiv_round_up JPP((long a, long b)); +EXTERN(long) jround_up JPP((long a, long b)); +EXTERN(void) jcopy_sample_rows JPP((JSAMPARRAY input_array, int source_row, + JSAMPARRAY output_array, int dest_row, + int num_rows, JDIMENSION num_cols)); +EXTERN(void) jcopy_block_row JPP((JBLOCKROW input_row, JBLOCKROW output_row, + JDIMENSION num_blocks)); +EXTERN(void) jzero_far JPP((void FAR * target, size_t bytestozero)); +/* Constant tables in jutils.c */ +#if 0 /* This table is not actually needed in v6a */ +extern const int jpeg_zigzag_order[]; /* natural coef order to zigzag order */ +#endif +extern const int jpeg_natural_order[]; /* zigzag coef order to natural order */ + +/* Suppress undefined-structure complaints if necessary. */ + +#ifdef INCOMPLETE_TYPES_BROKEN +#ifndef AM_MEMORY_MANAGER /* only jmemmgr.c defines these */ +struct jvirt_sarray_control { long dummy; }; +struct jvirt_barray_control { long dummy; }; +#endif +#endif /* INCOMPLETE_TYPES_BROKEN */ diff --git a/Utilities/ITK/Utilities/itkjpeg/jpeglib.h b/Utilities/ITK/Utilities/itkjpeg/jpeglib.h new file mode 100644 index 0000000000000000000000000000000000000000..02c2d186b669871ca2476116e489512aa523166d --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jpeglib.h @@ -0,0 +1,1131 @@ +/* + * jpeglib.h + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file defines the application interface for the JPEG library. + * Most applications using the library need only include this file, + * and perhaps jerror.h if they want to know the exact error codes. + */ + +#ifndef JPEGLIB_H +#define JPEGLIB_H + +/* + * First we include the configuration files that record how this + * installation of the JPEG library is set up. jconfig.h can be + * generated automatically for many systems. jmorecfg.h contains + * manual configuration options that most people need not worry about. + */ + +#ifndef JCONFIG_INCLUDED /* in case jinclude.h already did */ +#include "jconfig.h" /* widely used configuration options */ +#endif +#include "jmorecfg.h" /* seldom changed options */ + + +/* Version ID for the JPEG library. + * Might be useful for tests like "#if JPEG_LIB_VERSION >= 60". + */ + +#define JPEG_LIB_VERSION 62 /* Version 6b */ + + +/* Various constants determining the sizes of things. + * All of these are specified by the JPEG standard, so don't change them + * if you want to be compatible. + */ + +#define DCTSIZE 8 /* The basic DCT block is 8x8 samples */ +#define DCTSIZE2 64 /* DCTSIZE squared; # of elements in a block */ +#define NUM_QUANT_TBLS 4 /* Quantization tables are numbered 0..3 */ +#define NUM_HUFF_TBLS 4 /* Huffman tables are numbered 0..3 */ +#define NUM_ARITH_TBLS 16 /* Arith-coding tables are numbered 0..15 */ +#define MAX_COMPS_IN_SCAN 4 /* JPEG limit on # of components in one scan */ +#define MAX_SAMP_FACTOR 4 /* JPEG limit on sampling factors */ +/* Unfortunately, some bozo at Adobe saw no reason to be bound by the standard; + * the PostScript DCT filter can emit files with many more than 10 data units + * per MCU. + * If you happen to run across such a file, you can up D_MAX_DATA_UNITS_IN_MCU + * to handle it. We even let you do this from the jconfig.h file. However, + * we strongly discourage changing C_MAX_DATA_UNITS_IN_MCU; just because Adobe + * sometimes emits noncompliant files doesn't mean you should too. + */ +#define C_MAX_DATA_UNITS_IN_MCU 10 /* compressor's limit on data units/MCU */ +#ifndef D_MAX_DATA_UNITS_IN_MCU +#define D_MAX_DATA_UNITS_IN_MCU 10 /* decompressor's limit on data units/MCU */ +#endif + + +/* Data structures for images (arrays of samples and of DCT coefficients). + * On 80x86 machines, the image arrays are too big for near pointers, + * but the pointer arrays can fit in near memory. + */ + +typedef JSAMPLE FAR *JSAMPROW; /* ptr to one image row of pixel samples. */ +typedef JSAMPROW *JSAMPARRAY; /* ptr to some rows (a 2-D sample array) */ +typedef JSAMPARRAY *JSAMPIMAGE; /* a 3-D sample array: top index is color */ + +typedef JCOEF JBLOCK[DCTSIZE2]; /* one block of coefficients */ +typedef JBLOCK FAR *JBLOCKROW; /* pointer to one row of coefficient blocks */ +typedef JBLOCKROW *JBLOCKARRAY; /* a 2-D array of coefficient blocks */ +typedef JBLOCKARRAY *JBLOCKIMAGE; /* a 3-D array of coefficient blocks */ + +typedef JCOEF FAR *JCOEFPTR; /* useful in a couple of places */ + +typedef JDIFF FAR *JDIFFROW; /* pointer to one row of difference values */ +typedef JDIFFROW *JDIFFARRAY; /* ptr to some rows (a 2-D diff array) */ +typedef JDIFFARRAY *JDIFFIMAGE; /* a 3-D diff array: top index is color */ + + +/* Types for JPEG compression parameters and working tables. */ + + +/* DCT coefficient quantization tables. */ + +typedef struct { + /* This array gives the coefficient quantizers in natural array order + * (not the zigzag order in which they are stored in a JPEG DQT marker). + * CAUTION: IJG versions prior to v6a kept this array in zigzag order. + */ + UINT16 quantval[DCTSIZE2]; /* quantization step for each coefficient */ + /* This field is used only during compression. It's initialized FALSE when + * the table is created, and set TRUE when it's been output to the file. + * You could suppress output of a table by setting this to TRUE. + * (See jpeg_suppress_tables for an example.) + */ + boolean sent_table; /* TRUE when table has been output */ +} JQUANT_TBL; + + +/* Huffman coding tables. */ + +typedef struct { + /* These two fields directly represent the contents of a JPEG DHT marker */ + UINT8 bits[17]; /* bits[k] = # of symbols with codes of */ + /* length k bits; bits[0] is unused */ + UINT8 huffval[256]; /* The symbols, in order of incr code length */ + /* This field is used only during compression. It's initialized FALSE when + * the table is created, and set TRUE when it's been output to the file. + * You could suppress output of a table by setting this to TRUE. + * (See jpeg_suppress_tables for an example.) + */ + boolean sent_table; /* TRUE when table has been output */ +} JHUFF_TBL; + + +/* Basic info about one component (color channel). */ + +typedef struct { + /* These values are fixed over the whole image. */ + /* For compression, they must be supplied by parameter setup; */ + /* for decompression, they are read from the SOF marker. */ + int component_id; /* identifier for this component (0..255) */ + int component_index; /* its index in SOF or cinfo->comp_info[] */ + int h_samp_factor; /* horizontal sampling factor (1..4) */ + int v_samp_factor; /* vertical sampling factor (1..4) */ + int quant_tbl_no; /* quantization table selector (0..3) */ + /* These values may vary between scans. */ + /* For compression, they must be supplied by parameter setup; */ + /* for decompression, they are read from the SOS marker. */ + /* The decompressor output side may not use these variables. */ + int dc_tbl_no; /* DC entropy table selector (0..3) */ + int ac_tbl_no; /* AC entropy table selector (0..3) */ + + /* Remaining fields should be treated as private by applications. */ + + /* These values are computed during compression or decompression startup: */ + /* Component's size in data units. + * Any dummy data units added to complete an MCU are not counted; therefore + * these values do not depend on whether a scan is interleaved or not. + */ + JDIMENSION width_in_data_units; + JDIMENSION height_in_data_units; + /* Size of a data unit in/output by the codec (in samples). Always + * data_unit for compression. For decompression this is the size of the + * output from one data_unit, reflecting any processing performed by the + * codec. For example, in the DCT-based codec, scaling may be applied + * during the IDCT step. Values of 1,2,4,8 are likely to be supported. + * Note that different components may have different codec_data_unit sizes. + */ + int codec_data_unit; + /* The downsampled dimensions are the component's actual, unpadded number + * of samples at the main buffer (preprocessing/compression interface), thus + * downsampled_width = ceil(image_width * Hi/Hmax) + * and similarly for height. For decompression, codec-based processing is + * included (ie, IDCT scaling), so + * downsampled_width = ceil(image_width * Hi/Hmax * codec_data_unit/data_unit) + */ + JDIMENSION downsampled_width; /* actual width in samples */ + JDIMENSION downsampled_height; /* actual height in samples */ + /* This flag is used only for decompression. In cases where some of the + * components will be ignored (eg grayscale output from YCbCr image), + * we can skip most computations for the unused components. + */ + boolean component_needed; /* do we need the value of this component? */ + + /* These values are computed before starting a scan of the component. */ + /* The decompressor output side may not use these variables. */ + int MCU_width; /* number of data units per MCU, horizontally */ + int MCU_height; /* number of data units per MCU, vertically */ + int MCU_data_units; /* MCU_width * MCU_height */ + int MCU_sample_width; /* MCU width in samples, MCU_width*codec_data_unit */ + int last_col_width; /* # of non-dummy data_units across in last MCU */ + int last_row_height; /* # of non-dummy data_units down in last MCU */ + + /* Saved quantization table for component; NULL if none yet saved. + * See jdinput.c comments about the need for this information. + * This field is currently used only for decompression. + */ + JQUANT_TBL * quant_table; + + /* Private per-component storage for DCT or IDCT subsystem. */ + void * dct_table; +} jpeg_component_info; + + +/* The script for encoding a multiple-scan file is an array of these: */ + +typedef struct { + int comps_in_scan; /* number of components encoded in this scan */ + int component_index[MAX_COMPS_IN_SCAN]; /* their SOF/comp_info[] indexes */ + int Ss, Se; /* progressive JPEG spectral selection parms + lossless JPEG predictor select parm (Ss) */ + int Ah, Al; /* progressive JPEG successive approx. parms + lossless JPEG point transform parm (Al) */ +} jpeg_scan_info; + +/* The decompressor can save APPn and COM markers in a list of these: */ + +typedef struct jpeg_marker_struct FAR * jpeg_saved_marker_ptr; + +struct jpeg_marker_struct { + jpeg_saved_marker_ptr next; /* next in list, or NULL */ + UINT8 marker; /* marker code: JPEG_COM, or JPEG_APP0+n */ + unsigned int original_length; /* # bytes of data in the file */ + unsigned int data_length; /* # bytes of data saved at data[] */ + JOCTET FAR * data; /* the data contained in the marker */ + /* the marker length word is not counted in data_length or original_length */ +}; + +/* Known codec processes. */ + +typedef enum { + JPROC_SEQUENTIAL, /* baseline/extended sequential DCT */ + JPROC_PROGRESSIVE, /* progressive DCT */ + JPROC_LOSSLESS /* lossless (sequential) */ +} J_CODEC_PROCESS; + +/* Known color spaces. */ + +typedef enum { + JCS_UNKNOWN, /* error/unspecified */ + JCS_GRAYSCALE, /* monochrome */ + JCS_RGB, /* red/green/blue */ + JCS_YCbCr, /* Y/Cb/Cr (also known as YUV) */ + JCS_CMYK, /* C/M/Y/K */ + JCS_YCCK /* Y/Cb/Cr/K */ +} J_COLOR_SPACE; + +/* DCT/IDCT algorithm options. */ + +typedef enum { + JDCT_ISLOW, /* slow but accurate integer algorithm */ + JDCT_IFAST, /* faster, less accurate integer method */ + JDCT_FLOAT /* floating-point: accurate, fast on fast HW */ +} J_DCT_METHOD; + +#ifndef JDCT_DEFAULT /* may be overridden in jconfig.h */ +#define JDCT_DEFAULT JDCT_ISLOW +#endif +#ifndef JDCT_FASTEST /* may be overridden in jconfig.h */ +#define JDCT_FASTEST JDCT_IFAST +#endif + +/* Dithering options for decompression. */ + +typedef enum { + JDITHER_NONE, /* no dithering */ + JDITHER_ORDERED, /* simple ordered dither */ + JDITHER_FS /* Floyd-Steinberg error diffusion dither */ +} J_DITHER_MODE; + + +/* Common fields between JPEG compression and decompression master structs. */ + +#define jpeg_common_fields \ + struct jpeg_error_mgr * err; /* Error handler module */\ + struct jpeg_memory_mgr * mem; /* Memory manager module */\ + struct jpeg_progress_mgr * progress; /* Progress monitor, or NULL if none */\ + void * client_data; /* Available for use by application */\ + boolean is_decompressor; /* So common code can tell which is which */\ + int global_state /* For checking call sequence validity */ + +/* Routines that are to be used by both halves of the library are declared + * to receive a pointer to this structure. There are no actual instances of + * jpeg_common_struct, only of jpeg_compress_struct and jpeg_decompress_struct. + */ +struct jpeg_common_struct { + jpeg_common_fields; /* Fields common to both master struct types */ + /* Additional fields follow in an actual jpeg_compress_struct or + * jpeg_decompress_struct. All three structs must agree on these + * initial fields! (This would be a lot cleaner in C++.) + */ +}; + +typedef struct jpeg_common_struct * j_common_ptr; +typedef struct jpeg_compress_struct * j_compress_ptr; +typedef struct jpeg_decompress_struct * j_decompress_ptr; + + +/* Master record for a compression instance */ + +struct jpeg_compress_struct { + jpeg_common_fields; /* Fields shared with jpeg_decompress_struct */ + + /* Destination for compressed data */ + struct jpeg_destination_mgr * dest; + + /* Description of source image --- these fields must be filled in by + * outer application before starting compression. in_color_space must + * be correct before you can even call jpeg_set_defaults(). + */ + + JDIMENSION image_width; /* input image width */ + JDIMENSION image_height; /* input image height */ + int input_components; /* # of color components in input image */ + J_COLOR_SPACE in_color_space; /* colorspace of input image */ + + double input_gamma; /* image gamma of input image */ + + /* Compression parameters --- these fields must be set before calling + * jpeg_start_compress(). We recommend calling jpeg_set_defaults() to + * initialize everything to reasonable defaults, then changing anything + * the application specifically wants to change. That way you won't get + * burnt when new parameters are added. Also note that there are several + * helper routines to simplify changing parameters. + */ + + boolean lossless; /* TRUE=lossless encoding, FALSE=lossy */ + + int data_precision; /* bits of precision in image data */ + + int num_components; /* # of color components in JPEG image */ + J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */ + + jpeg_component_info * comp_info; + /* comp_info[i] describes component that appears i'th in SOF */ + + JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS]; + /* ptrs to coefficient quantization tables, or NULL if not defined */ + + JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS]; + JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS]; + /* ptrs to Huffman coding tables, or NULL if not defined */ + + UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */ + UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */ + UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */ + + int num_scans; /* # of entries in scan_info array */ + const jpeg_scan_info * scan_info; /* script for multi-scan file, or NULL */ + /* The default value of scan_info is NULL, which causes a single-scan + * sequential JPEG file to be emitted. To create a multi-scan file, + * set num_scans and scan_info to point to an array of scan definitions. + */ + + boolean raw_data_in; /* TRUE=caller supplies downsampled data */ + boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */ + boolean optimize_coding; /* TRUE=optimize entropy encoding parms */ + boolean CCIR601_sampling; /* TRUE=first samples are cosited */ + int smoothing_factor; /* 1..100, or 0 for no input smoothing */ + J_DCT_METHOD dct_method; /* DCT algorithm selector */ + + /* The restart interval can be specified in absolute MCUs by setting + * restart_interval, or in MCU rows by setting restart_in_rows + * (in which case the correct restart_interval will be figured + * for each scan). + */ + unsigned int restart_interval; /* MCUs per restart, or 0 for no restart */ + int restart_in_rows; /* if > 0, MCU rows per restart interval */ + + /* Parameters controlling emission of special markers. */ + + boolean write_JFIF_header; /* should a JFIF marker be written? */ + UINT8 JFIF_major_version; /* What to write for the JFIF version number */ + UINT8 JFIF_minor_version; + /* These three values are not used by the JPEG code, merely copied */ + /* into the JFIF APP0 marker. density_unit can be 0 for unknown, */ + /* 1 for dots/inch, or 2 for dots/cm. Note that the pixel aspect */ + /* ratio is defined by X_density/Y_density even when density_unit=0. */ + UINT8 density_unit; /* JFIF code for pixel size units */ + UINT16 X_density; /* Horizontal pixel density */ + UINT16 Y_density; /* Vertical pixel density */ + boolean write_Adobe_marker; /* should an Adobe marker be written? */ + + /* State variable: index of next scanline to be written to + * jpeg_write_scanlines(). Application may use this to control its + * processing loop, e.g., "while (next_scanline < image_height)". + */ + + JDIMENSION next_scanline; /* 0 .. image_height-1 */ + + /* Remaining fields are known throughout compressor, but generally + * should not be touched by a surrounding application. + */ + + /* + * These fields are computed during compression startup + */ + int data_unit; /* size of data unit in samples */ + J_CODEC_PROCESS process; /* encoding process of JPEG image */ + + int max_h_samp_factor; /* largest h_samp_factor */ + int max_v_samp_factor; /* largest v_samp_factor */ + + JDIMENSION total_iMCU_rows; /* # of iMCU rows to be input to codec */ + /* The codec receives data in units of MCU rows as defined for fully + * interleaved scans (whether the JPEG file is interleaved or not). + * There are v_samp_factor * data_unit sample rows of each component in an + * "iMCU" (interleaved MCU) row. + */ + + /* + * These fields are valid during any one scan. + * They describe the components and MCUs actually appearing in the scan. + */ + int comps_in_scan; /* # of JPEG components in this scan */ + jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN]; + /* *cur_comp_info[i] describes component that appears i'th in SOS */ + + JDIMENSION MCUs_per_row; /* # of MCUs across the image */ + JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */ + + int data_units_in_MCU; /* # of data units per MCU */ + int MCU_membership[C_MAX_DATA_UNITS_IN_MCU]; + /* MCU_membership[i] is index in cur_comp_info of component owning */ + /* i'th block in an MCU */ + + int Ss, Se, Ah, Al; /* progressive/lossless JPEG parameters for scan */ + + /* + * Links to compression subobjects (methods and private variables of modules) + */ + struct jpeg_comp_master * master; + struct jpeg_c_main_controller * main; + struct jpeg_c_prep_controller * prep; + struct jpeg_c_codec * codec; + struct jpeg_marker_writer * marker; + struct jpeg_color_converter * cconvert; + struct jpeg_downsampler * downsample; + jpeg_scan_info * script_space; /* workspace for jpeg_simple_progression */ + int script_space_size; +}; + + +/* Master record for a decompression instance */ + +struct jpeg_decompress_struct { + jpeg_common_fields; /* Fields shared with jpeg_compress_struct */ + + /* Source of compressed data */ + struct jpeg_source_mgr * src; + + /* Basic description of image --- filled in by jpeg_read_header(). */ + /* Application may inspect these values to decide how to process image. */ + + JDIMENSION image_width; /* nominal image width (from SOF marker) */ + JDIMENSION image_height; /* nominal image height */ + int num_components; /* # of color components in JPEG image */ + J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */ + + /* Decompression processing parameters --- these fields must be set before + * calling jpeg_start_decompress(). Note that jpeg_read_header() initializes + * them to default values. + */ + + J_COLOR_SPACE out_color_space; /* colorspace for output */ + + unsigned int scale_num, scale_denom; /* fraction by which to scale image */ + + double output_gamma; /* image gamma wanted in output */ + + boolean buffered_image; /* TRUE=multiple output passes */ + boolean raw_data_out; /* TRUE=downsampled data wanted */ + + J_DCT_METHOD dct_method; /* IDCT algorithm selector */ + boolean do_fancy_upsampling; /* TRUE=apply fancy upsampling */ + boolean do_block_smoothing; /* TRUE=apply interblock smoothing */ + + boolean quantize_colors; /* TRUE=colormapped output wanted */ + /* the following are ignored if not quantize_colors: */ + J_DITHER_MODE dither_mode; /* type of color dithering to use */ + boolean two_pass_quantize; /* TRUE=use two-pass color quantization */ + int desired_number_of_colors; /* max # colors to use in created colormap */ + /* these are significant only in buffered-image mode: */ + boolean enable_1pass_quant; /* enable future use of 1-pass quantizer */ + boolean enable_external_quant;/* enable future use of external colormap */ + boolean enable_2pass_quant; /* enable future use of 2-pass quantizer */ + + /* Description of actual output image that will be returned to application. + * These fields are computed by jpeg_start_decompress(). + * You can also use jpeg_calc_output_dimensions() to determine these values + * in advance of calling jpeg_start_decompress(). + */ + + JDIMENSION output_width; /* scaled image width */ + JDIMENSION output_height; /* scaled image height */ + int out_color_components; /* # of color components in out_color_space */ + int output_components; /* # of color components returned */ + /* output_components is 1 (a colormap index) when quantizing colors; + * otherwise it equals out_color_components. + */ + int rec_outbuf_height; /* min recommended height of scanline buffer */ + /* If the buffer passed to jpeg_read_scanlines() is less than this many rows + * high, space and time will be wasted due to unnecessary data copying. + * Usually rec_outbuf_height will be 1 or 2, at most 4. + */ + + /* When quantizing colors, the output colormap is described by these fields. + * The application can supply a colormap by setting colormap non-NULL before + * calling jpeg_start_decompress; otherwise a colormap is created during + * jpeg_start_decompress or jpeg_start_output. + * The map has out_color_components rows and actual_number_of_colors columns. + */ + int actual_number_of_colors; /* number of entries in use */ + JSAMPARRAY colormap; /* The color map as a 2-D pixel array */ + + /* State variables: these variables indicate the progress of decompression. + * The application may examine these but must not modify them. + */ + + /* Row index of next scanline to be read from jpeg_read_scanlines(). + * Application may use this to control its processing loop, e.g., + * "while (output_scanline < output_height)". + */ + JDIMENSION output_scanline; /* 0 .. output_height-1 */ + + /* Current input scan number and number of iMCU rows completed in scan. + * These indicate the progress of the decompressor input side. + */ + int input_scan_number; /* Number of SOS markers seen so far */ + JDIMENSION input_iMCU_row; /* Number of iMCU rows completed */ + + /* The "output scan number" is the notional scan being displayed by the + * output side. The decompressor will not allow output scan/row number + * to get ahead of input scan/row, but it can fall arbitrarily far behind. + */ + int output_scan_number; /* Nominal scan number being displayed */ + JDIMENSION output_iMCU_row; /* Number of iMCU rows read */ + + /* Current progression status. coef_bits[c][i] indicates the precision + * with which component c's DCT coefficient i (in zigzag order) is known. + * It is -1 when no data has yet been received, otherwise it is the point + * transform (shift) value for the most recent scan of the coefficient + * (thus, 0 at completion of the progression). + * This pointer is NULL when reading a non-progressive file. + */ + int (*coef_bits)[DCTSIZE2]; /* -1 or current Al value for each coef */ + + /* Internal JPEG parameters --- the application usually need not look at + * these fields. Note that the decompressor output side may not use + * any parameters that can change between scans. + */ + + /* Quantization and Huffman tables are carried forward across input + * datastreams when processing abbreviated JPEG datastreams. + */ + + JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS]; + /* ptrs to coefficient quantization tables, or NULL if not defined */ + + JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS]; + JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS]; + /* ptrs to Huffman coding tables, or NULL if not defined */ + + /* These parameters are never carried across datastreams, since they + * are given in SOF/SOS markers or defined to be reset by SOI. + */ + + int data_precision; /* bits of precision in image data */ + + jpeg_component_info * comp_info; + /* comp_info[i] describes component that appears i'th in SOF */ + + boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */ + + UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */ + UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */ + UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */ + + unsigned int restart_interval; /* MCUs per restart interval, or 0 for no restart */ + + /* These fields record data obtained from optional markers recognized by + * the JPEG library. + */ + boolean saw_JFIF_marker; /* TRUE iff a JFIF APP0 marker was found */ + /* Data copied from JFIF marker; only valid if saw_JFIF_marker is TRUE: */ + UINT8 JFIF_major_version; /* JFIF version number */ + UINT8 JFIF_minor_version; + UINT8 density_unit; /* JFIF code for pixel size units */ + UINT16 X_density; /* Horizontal pixel density */ + UINT16 Y_density; /* Vertical pixel density */ + boolean saw_Adobe_marker; /* TRUE iff an Adobe APP14 marker was found */ + UINT8 Adobe_transform; /* Color transform code from Adobe marker */ + + boolean CCIR601_sampling; /* TRUE=first samples are cosited */ + + /* Aside from the specific data retained from APPn markers known to the + * library, the uninterpreted contents of any or all APPn and COM markers + * can be saved in a list for examination by the application. + */ + jpeg_saved_marker_ptr marker_list; /* Head of list of saved markers */ + + /* Remaining fields are known throughout decompressor, but generally + * should not be touched by a surrounding application. + */ + + /* + * These fields are computed during decompression startup + */ + int data_unit; /* size of data unit in samples */ + J_CODEC_PROCESS process; /* decoding process of JPEG image */ + + int max_h_samp_factor; /* largest h_samp_factor */ + int max_v_samp_factor; /* largest v_samp_factor */ + + int min_codec_data_unit; /* smallest codec_data_unit of any component */ + + JDIMENSION total_iMCU_rows; /* # of iMCU rows in image */ + /* The codec's input and output progress is measured in units of "iMCU" + * (interleaved MCU) rows. These are the same as MCU rows in fully + * interleaved JPEG scans, but are used whether the scan is interleaved + * or not. We define an iMCU row as v_samp_factor data_unit rows of each + * component. Therefore, the codec output contains + * v_samp_factor*codec_data_unit sample rows of a component per iMCU row. + */ + + JSAMPLE * sample_range_limit; /* table for fast range-limiting */ + + /* + * These fields are valid during any one scan. + * They describe the components and MCUs actually appearing in the scan. + * Note that the decompressor output side must not use these fields. + */ + int comps_in_scan; /* # of JPEG components in this scan */ + jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN]; + /* *cur_comp_info[i] describes component that appears i'th in SOS */ + + JDIMENSION MCUs_per_row; /* # of MCUs across the image */ + JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */ + + int data_units_in_MCU; /* # of data _units per MCU */ + int MCU_membership[D_MAX_DATA_UNITS_IN_MCU]; + /* MCU_membership[i] is index in cur_comp_info of component owning */ + /* i'th data unit in an MCU */ + + int Ss, Se, Ah, Al; /* progressive/lossless JPEG parms for scan */ + + /* This field is shared between entropy decoder and marker parser. + * It is either zero or the code of a JPEG marker that has been + * read from the data source, but has not yet been processed. + */ + int unread_marker; + + /* + * Links to decompression subobjects (methods, private variables of modules) + */ + struct jpeg_decomp_master * master; + struct jpeg_d_main_controller * main; + struct jpeg_d_codec * codec; + struct jpeg_d_post_controller * post; + struct jpeg_input_controller * inputctl; + struct jpeg_marker_reader * marker; + struct jpeg_upsampler * upsample; + struct jpeg_color_deconverter * cconvert; + struct jpeg_color_quantizer * cquantize; +}; + + +/* "Object" declarations for JPEG modules that may be supplied or called + * directly by the surrounding application. + * As with all objects in the JPEG library, these structs only define the + * publicly visible methods and state variables of a module. Additional + * private fields may exist after the public ones. + */ + + +/* Error handler object */ + +struct jpeg_error_mgr { + /* Error exit handler: does not return to caller */ + JMETHOD(void, error_exit, (j_common_ptr cinfo)); + /* Conditionally emit a trace or warning message */ + JMETHOD(void, emit_message, (j_common_ptr cinfo, int msg_level)); + /* Routine that actually outputs a trace or error message */ + JMETHOD(void, output_message, (j_common_ptr cinfo)); + /* Format a message string for the most recent JPEG error or message */ + JMETHOD(void, format_message, (j_common_ptr cinfo, char * buffer)); +#define JMSG_LENGTH_MAX 200 /* recommended size of format_message buffer */ + /* Reset error state variables at start of a new image */ + JMETHOD(void, reset_error_mgr, (j_common_ptr cinfo)); + + /* The message ID code and any parameters are saved here. + * A message can have one string parameter or up to 8 int parameters. + */ + int msg_code; +#define JMSG_STR_PARM_MAX 80 + union { + int i[8]; + char s[JMSG_STR_PARM_MAX]; + } msg_parm; + + /* Standard state variables for error facility */ + + int trace_level; /* max msg_level that will be displayed */ + + /* For recoverable corrupt-data errors, we emit a warning message, + * but keep going unless emit_message chooses to abort. emit_message + * should count warnings in num_warnings. The surrounding application + * can check for bad data by seeing if num_warnings is nonzero at the + * end of processing. + */ + long num_warnings; /* number of corrupt-data warnings */ + + /* These fields point to the table(s) of error message strings. + * An application can change the table pointer to switch to a different + * message list (typically, to change the language in which errors are + * reported). Some applications may wish to add additional error codes + * that will be handled by the JPEG library error mechanism; the second + * table pointer is used for this purpose. + * + * First table includes all errors generated by JPEG library itself. + * Error code 0 is reserved for a "no such error string" message. + */ + const char * const * jpeg_message_table; /* Library errors */ + int last_jpeg_message; /* Table contains strings 0..last_jpeg_message */ + /* Second table can be added by application (see cjpeg/djpeg for example). + * It contains strings numbered first_addon_message..last_addon_message. + */ + const char * const * addon_message_table; /* Non-library errors */ + int first_addon_message; /* code for first string in addon table */ + int last_addon_message; /* code for last string in addon table */ +}; + + +/* Progress monitor object */ + +struct jpeg_progress_mgr { + JMETHOD(void, progress_monitor, (j_common_ptr cinfo)); + + long pass_counter; /* work units completed in this pass */ + long pass_limit; /* total number of work units in this pass */ + int completed_passes; /* passes completed so far */ + int total_passes; /* total number of passes expected */ +}; + + +/* Data destination object for compression */ + +struct jpeg_destination_mgr { + JOCTET * next_output_byte; /* => next byte to write in buffer */ + size_t free_in_buffer; /* # of byte spaces remaining in buffer */ + + JMETHOD(void, init_destination, (j_compress_ptr cinfo)); + JMETHOD(boolean, empty_output_buffer, (j_compress_ptr cinfo)); + JMETHOD(void, term_destination, (j_compress_ptr cinfo)); +}; + + +/* Data source object for decompression */ + +struct jpeg_source_mgr { + const JOCTET * next_input_byte; /* => next byte to read from buffer */ + size_t bytes_in_buffer; /* # of bytes remaining in buffer */ + + JMETHOD(void, init_source, (j_decompress_ptr cinfo)); + JMETHOD(boolean, fill_input_buffer, (j_decompress_ptr cinfo)); + JMETHOD(void, skip_input_data, (j_decompress_ptr cinfo, long num_bytes)); + JMETHOD(boolean, resync_to_restart, (j_decompress_ptr cinfo, int desired)); + JMETHOD(void, term_source, (j_decompress_ptr cinfo)); +}; + + +/* Memory manager object. + * Allocates "small" objects (a few K total), "large" objects (tens of K), + * and "really big" objects (virtual arrays with backing store if needed). + * The memory manager does not allow individual objects to be freed; rather, + * each created object is assigned to a pool, and whole pools can be freed + * at once. This is faster and more convenient than remembering exactly what + * to free, especially where malloc()/free() are not too speedy. + * NB: alloc routines never return NULL. They exit to error_exit if not + * successful. + */ + +#define JPOOL_PERMANENT 0 /* lasts until master record is destroyed */ +#define JPOOL_IMAGE 1 /* lasts until done with image/datastream */ +#define JPOOL_NUMPOOLS 2 + +typedef struct jvirt_sarray_control * jvirt_sarray_ptr; +typedef struct jvirt_barray_control * jvirt_barray_ptr; + + +#ifdef C_LOSSLESS_SUPPORTED +#define NEED_DARRAY +#else +#ifdef D_LOSSLESS_SUPPORTED +#define NEED_DARRAY +#endif +#endif + +struct jpeg_memory_mgr { + /* Method pointers */ + JMETHOD(void *, alloc_small, (j_common_ptr cinfo, int pool_id, + size_t sizeofobject)); + JMETHOD(void FAR *, alloc_large, (j_common_ptr cinfo, int pool_id, + size_t sizeofobject)); + JMETHOD(JSAMPARRAY, alloc_sarray, (j_common_ptr cinfo, int pool_id, + JDIMENSION samplesperrow, + JDIMENSION numrows)); + JMETHOD(JBLOCKARRAY, alloc_barray, (j_common_ptr cinfo, int pool_id, + JDIMENSION blocksperrow, + JDIMENSION numrows)); +#ifdef NEED_DARRAY + JMETHOD(JDIFFARRAY, alloc_darray, (j_common_ptr cinfo, int pool_id, + JDIMENSION diffsperrow, + JDIMENSION numrows)); +#endif + JMETHOD(jvirt_sarray_ptr, request_virt_sarray, (j_common_ptr cinfo, + int pool_id, + boolean pre_zero, + JDIMENSION samplesperrow, + JDIMENSION numrows, + JDIMENSION maxaccess)); + JMETHOD(jvirt_barray_ptr, request_virt_barray, (j_common_ptr cinfo, + int pool_id, + boolean pre_zero, + JDIMENSION blocksperrow, + JDIMENSION numrows, + JDIMENSION maxaccess)); + JMETHOD(void, realize_virt_arrays, (j_common_ptr cinfo)); + JMETHOD(JSAMPARRAY, access_virt_sarray, (j_common_ptr cinfo, + jvirt_sarray_ptr ptr, + JDIMENSION start_row, + JDIMENSION num_rows, + boolean writable)); + JMETHOD(JBLOCKARRAY, access_virt_barray, (j_common_ptr cinfo, + jvirt_barray_ptr ptr, + JDIMENSION start_row, + JDIMENSION num_rows, + boolean writable)); + JMETHOD(void, free_pool, (j_common_ptr cinfo, int pool_id)); + JMETHOD(void, self_destruct, (j_common_ptr cinfo)); + + /* Limit on memory allocation for this JPEG object. (Note that this is + * merely advisory, not a guaranteed maximum; it only affects the space + * used for virtual-array buffers.) May be changed by outer application + * after creating the JPEG object. + */ + long max_memory_to_use; + + /* Maximum allocation request accepted by alloc_large. */ + long max_alloc_chunk; +}; + + +/* Routine signature for application-supplied marker processing methods. + * Need not pass marker code since it is stored in cinfo->unread_marker. + */ +typedef JMETHOD(boolean, jpeg_marker_parser_method, (j_decompress_ptr cinfo)); + + +/* Declarations for routines called by application. + * The JPP macro hides prototype parameters from compilers that can't cope. + * Note JPP requires double parentheses. + */ + +#ifdef HAVE_PROTOTYPES +#define JPP(arglist) arglist +#else +#define JPP(arglist) () +#endif + + +/* Short forms of external names for systems with brain-damaged linkers. + * We shorten external names to be unique in the first six letters, which + * is good enough for all known systems. + * (If your compiler itself needs names to be unique in less than 15 + * characters, you are out of luck. Get a better compiler.) + */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_std_error jStdError +#define jpeg_CreateCompress jCreaCompress +#define jpeg_CreateDecompress jCreaDecompress +#define jpeg_destroy_compress jDestCompress +#define jpeg_destroy_decompress jDestDecompress +#define jpeg_stdio_dest jStdDest +#define jpeg_stdio_src jStdSrc +#define jpeg_set_defaults jSetDefaults +#define jpeg_set_colorspace jSetColorspace +#define jpeg_default_colorspace jDefColorspace +#define jpeg_set_quality jSetQuality +#define jpeg_set_linear_quality jSetLQuality +#define jpeg_add_quant_table jAddQuantTable +#define jpeg_quality_scaling jQualityScaling +#define jpeg_simple_lossless jSimLossless +#define jpeg_simple_progression jSimProgress +#define jpeg_suppress_tables jSuppressTables +#define jpeg_alloc_quant_table jAlcQTable +#define jpeg_alloc_huff_table jAlcHTable +#define jpeg_start_compress jStrtCompress +#define jpeg_write_scanlines jWrtScanlines +#define jpeg_finish_compress jFinCompress +#define jpeg_write_raw_data jWrtRawData +#define jpeg_write_marker jWrtMarker +#define jpeg_write_m_header jWrtMHeader +#define jpeg_write_m_byte jWrtMByte +#define jpeg_write_tables jWrtTables +#define jpeg_read_header jReadHeader +#define jpeg_start_decompress jStrtDecompress +#define jpeg_read_scanlines jReadScanlines +#define jpeg_finish_decompress jFinDecompress +#define jpeg_read_raw_data jReadRawData +#define jpeg_has_multiple_scans jHasMultScn +#define jpeg_start_output jStrtOutput +#define jpeg_finish_output jFinOutput +#define jpeg_input_complete jInComplete +#define jpeg_new_colormap jNewCMap +#define jpeg_consume_input jConsumeInput +#define jpeg_calc_output_dimensions jCalcDimensions +#define jpeg_save_markers jSaveMarkers +#define jpeg_set_marker_processor jSetMarker +#define jpeg_read_coefficients jReadCoefs +#define jpeg_write_coefficients jWrtCoefs +#define jpeg_copy_critical_parameters jCopyCrit +#define jpeg_abort_compress jAbrtCompress +#define jpeg_abort_decompress jAbrtDecompress +#define jpeg_abort jAbort +#define jpeg_destroy jDestroy +#define jpeg_resync_to_restart jResyncRestart +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + +/* Default error-management setup */ +EXTERN(struct jpeg_error_mgr *) jpeg_std_error + JPP((struct jpeg_error_mgr * err)); + +/* Initialization of JPEG compression objects. + * jpeg_create_compress() and jpeg_create_decompress() are the exported + * names that applications should call. These expand to calls on + * jpeg_CreateCompress and jpeg_CreateDecompress with additional information + * passed for version mismatch checking. + * NB: you must set up the error-manager BEFORE calling jpeg_create_xxx. + */ +#define jpeg_create_compress(cinfo) \ + jpeg_CreateCompress((cinfo), JPEG_LIB_VERSION, \ + (size_t) sizeof(struct jpeg_compress_struct)) +#define jpeg_create_decompress(cinfo) \ + jpeg_CreateDecompress((cinfo), JPEG_LIB_VERSION, \ + (size_t) sizeof(struct jpeg_decompress_struct)) +EXTERN(void) jpeg_CreateCompress JPP((j_compress_ptr cinfo, + int version, size_t structsize)); +EXTERN(void) jpeg_CreateDecompress JPP((j_decompress_ptr cinfo, + int version, size_t structsize)); +/* Destruction of JPEG compression objects */ +EXTERN(void) jpeg_destroy_compress JPP((j_compress_ptr cinfo)); +EXTERN(void) jpeg_destroy_decompress JPP((j_decompress_ptr cinfo)); + +/* Standard data source and destination managers: stdio streams. */ +/* Caller is responsible for opening the file before and closing after. */ +EXTERN(void) jpeg_stdio_dest JPP((j_compress_ptr cinfo, FILE * outfile)); +EXTERN(void) jpeg_stdio_src JPP((j_decompress_ptr cinfo, FILE * infile)); + +/* Default parameter setup for compression */ +EXTERN(void) jpeg_set_defaults JPP((j_compress_ptr cinfo)); +/* Compression parameter setup aids */ +EXTERN(void) jpeg_set_colorspace JPP((j_compress_ptr cinfo, + J_COLOR_SPACE colorspace)); +EXTERN(void) jpeg_default_colorspace JPP((j_compress_ptr cinfo)); +EXTERN(void) jpeg_set_quality JPP((j_compress_ptr cinfo, int quality, + boolean force_baseline)); +EXTERN(void) jpeg_set_linear_quality JPP((j_compress_ptr cinfo, + int scale_factor, + boolean force_baseline)); +EXTERN(void) jpeg_add_quant_table JPP((j_compress_ptr cinfo, int which_tbl, + const unsigned int *basic_table, + int scale_factor, + boolean force_baseline)); +EXTERN(int) jpeg_quality_scaling JPP((int quality)); +EXTERN(void) jpeg_simple_lossless JPP((j_compress_ptr cinfo, + int predictor, int point_transform)); +EXTERN(void) jpeg_simple_progression JPP((j_compress_ptr cinfo)); +EXTERN(void) jpeg_suppress_tables JPP((j_compress_ptr cinfo, + boolean suppress)); +EXTERN(JQUANT_TBL *) jpeg_alloc_quant_table JPP((j_common_ptr cinfo)); +EXTERN(JHUFF_TBL *) jpeg_alloc_huff_table JPP((j_common_ptr cinfo)); + +/* Main entry points for compression */ +EXTERN(void) jpeg_start_compress JPP((j_compress_ptr cinfo, + boolean write_all_tables)); +EXTERN(JDIMENSION) jpeg_write_scanlines JPP((j_compress_ptr cinfo, + JSAMPARRAY scanlines, + JDIMENSION num_lines)); +EXTERN(void) jpeg_finish_compress JPP((j_compress_ptr cinfo)); + +/* Replaces jpeg_write_scanlines when writing raw downsampled data. */ +EXTERN(JDIMENSION) jpeg_write_raw_data JPP((j_compress_ptr cinfo, + JSAMPIMAGE data, + JDIMENSION num_lines)); + +/* Write a special marker. See libjpeg.doc concerning safe usage. */ +EXTERN(void) jpeg_write_marker + JPP((j_compress_ptr cinfo, int marker, + const JOCTET * dataptr, unsigned int datalen)); +/* Same, but piecemeal. */ +EXTERN(void) jpeg_write_m_header + JPP((j_compress_ptr cinfo, int marker, unsigned int datalen)); +EXTERN(void) jpeg_write_m_byte + JPP((j_compress_ptr cinfo, int val)); + +/* Alternate compression function: just write an abbreviated table file */ +EXTERN(void) jpeg_write_tables JPP((j_compress_ptr cinfo)); + +/* Decompression startup: read start of JPEG datastream to see what's there */ +EXTERN(int) jpeg_read_header JPP((j_decompress_ptr cinfo, + boolean require_image)); +/* Return value is one of: */ +#define JPEG_SUSPENDED 0 /* Suspended due to lack of input data */ +#define JPEG_HEADER_OK 1 /* Found valid image datastream */ +#define JPEG_HEADER_TABLES_ONLY 2 /* Found valid table-specs-only datastream */ +/* If you pass require_image = TRUE (normal case), you need not check for + * a TABLES_ONLY return code; an abbreviated file will cause an error exit. + * JPEG_SUSPENDED is only possible if you use a data source module that can + * give a suspension return (the stdio source module doesn't). + */ + +/* Main entry points for decompression */ +EXTERN(boolean) jpeg_start_decompress JPP((j_decompress_ptr cinfo)); +EXTERN(JDIMENSION) jpeg_read_scanlines JPP((j_decompress_ptr cinfo, + JSAMPARRAY scanlines, + JDIMENSION max_lines)); +EXTERN(boolean) jpeg_finish_decompress JPP((j_decompress_ptr cinfo)); + +/* Replaces jpeg_read_scanlines when reading raw downsampled data. */ +EXTERN(JDIMENSION) jpeg_read_raw_data JPP((j_decompress_ptr cinfo, + JSAMPIMAGE data, + JDIMENSION max_lines)); + +/* Additional entry points for buffered-image mode. */ +EXTERN(boolean) jpeg_has_multiple_scans JPP((j_decompress_ptr cinfo)); +EXTERN(boolean) jpeg_start_output JPP((j_decompress_ptr cinfo, + int scan_number)); +EXTERN(boolean) jpeg_finish_output JPP((j_decompress_ptr cinfo)); +EXTERN(boolean) jpeg_input_complete JPP((j_decompress_ptr cinfo)); +EXTERN(void) jpeg_new_colormap JPP((j_decompress_ptr cinfo)); +EXTERN(int) jpeg_consume_input JPP((j_decompress_ptr cinfo)); +/* Return value is one of: */ +/* #define JPEG_SUSPENDED 0 Suspended due to lack of input data */ +#define JPEG_REACHED_SOS 1 /* Reached start of new scan */ +#define JPEG_REACHED_EOI 2 /* Reached end of image */ +#define JPEG_ROW_COMPLETED 3 /* Completed one iMCU row */ +#define JPEG_SCAN_COMPLETED 4 /* Completed last iMCU row of a scan */ + +/* Precalculate output dimensions for current decompression parameters. */ +EXTERN(void) jpeg_calc_output_dimensions JPP((j_decompress_ptr cinfo)); + +/* Control saving of COM and APPn markers into marker_list. */ +EXTERN(void) jpeg_save_markers + JPP((j_decompress_ptr cinfo, int marker_code, + unsigned int length_limit)); + +/* Install a special processing method for COM or APPn markers. */ +EXTERN(void) jpeg_set_marker_processor + JPP((j_decompress_ptr cinfo, int marker_code, + jpeg_marker_parser_method routine)); + +/* Read or write raw DCT coefficients --- useful for lossless transcoding. */ +EXTERN(jvirt_barray_ptr *) jpeg_read_coefficients JPP((j_decompress_ptr cinfo)); +EXTERN(void) jpeg_write_coefficients JPP((j_compress_ptr cinfo, + jvirt_barray_ptr * coef_arrays)); +EXTERN(void) jpeg_copy_critical_parameters JPP((j_decompress_ptr srcinfo, + j_compress_ptr dstinfo)); + +/* If you choose to abort compression or decompression before completing + * jpeg_finish_(de)compress, then you need to clean up to release memory, + * temporary files, etc. You can just call jpeg_destroy_(de)compress + * if you're done with the JPEG object, but if you want to clean it up and + * reuse it, call this: + */ +EXTERN(void) jpeg_abort_compress JPP((j_compress_ptr cinfo)); +EXTERN(void) jpeg_abort_decompress JPP((j_decompress_ptr cinfo)); + +/* Generic versions of jpeg_abort and jpeg_destroy that work on either + * flavor of JPEG object. These may be more convenient in some places. + */ +EXTERN(void) jpeg_abort JPP((j_common_ptr cinfo)); +EXTERN(void) jpeg_destroy JPP((j_common_ptr cinfo)); + +/* Default restart-marker-resync procedure for use by data source modules */ +EXTERN(boolean) jpeg_resync_to_restart JPP((j_decompress_ptr cinfo, + int desired)); + + +/* These marker codes are exported since applications and data source modules + * are likely to want to use them. + */ + +#define JPEG_RST0 0xD0 /* RST0 marker code */ +#define JPEG_EOI 0xD9 /* EOI marker code */ +#define JPEG_APP0 0xE0 /* APP0 marker code */ +#define JPEG_COM 0xFE /* COM marker code */ + + +/* If we have a brain-damaged compiler that emits warnings (or worse, errors) + * for structure definitions that are never filled in, keep it quiet by + * supplying dummy definitions for the various substructures. + */ + +#ifdef INCOMPLETE_TYPES_BROKEN +#ifndef JPEG_INTERNALS /* will be defined in jpegint.h */ +struct jvirt_sarray_control { long dummy; }; +struct jvirt_barray_control { long dummy; }; +struct jpeg_comp_master { long dummy; }; +struct jpeg_c_main_controller { long dummy; }; +struct jpeg_c_prep_controller { long dummy; }; +struct jpeg_c_coef_controller { long dummy; }; +struct jpeg_marker_writer { long dummy; }; +struct jpeg_color_converter { long dummy; }; +struct jpeg_downsampler { long dummy; }; +struct jpeg_forward_dct { long dummy; }; +struct jpeg_entropy_encoder { long dummy; }; +struct jpeg_decomp_master { long dummy; }; +struct jpeg_d_main_controller { long dummy; }; +struct jpeg_d_coef_controller { long dummy; }; +struct jpeg_d_post_controller { long dummy; }; +struct jpeg_input_controller { long dummy; }; +struct jpeg_marker_reader { long dummy; }; +struct jpeg_entropy_decoder { long dummy; }; +struct jpeg_inverse_dct { long dummy; }; +struct jpeg_upsampler { long dummy; }; +struct jpeg_color_deconverter { long dummy; }; +struct jpeg_color_quantizer { long dummy; }; +#endif /* JPEG_INTERNALS */ +#endif /* INCOMPLETE_TYPES_BROKEN */ + + +/* + * The JPEG library modules define JPEG_INTERNALS before including this file. + * The internal structure declarations are read only when that is true. + * Applications using the library should not include jpegint.h, but may wish + * to include jerror.h. + */ + +#ifdef JPEG_INTERNALS +#include "jpegint.h" /* fetch private declarations */ +#include "jerror.h" /* fetch error codes too */ +#endif + +#endif /* JPEGLIB_H */ diff --git a/Utilities/ITK/Utilities/itkjpeg/jquant1.c b/Utilities/ITK/Utilities/itkjpeg/jquant1.c new file mode 100644 index 0000000000000000000000000000000000000000..a5abd0a8bd500bf4c55ab03cdbf08d16e34b2221 --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jquant1.c @@ -0,0 +1,860 @@ +/* + * jquant1.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains 1-pass color quantization (color mapping) routines. + * These routines provide mapping to a fixed color map using equally spaced + * color values. Optional Floyd-Steinberg or ordered dithering is available. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + +#ifdef QUANT_1PASS_SUPPORTED + + +/* + * The main purpose of 1-pass quantization is to provide a fast, if not very + * high quality, colormapped output capability. A 2-pass quantizer usually + * gives better visual quality; however, for quantized grayscale output this + * quantizer is perfectly adequate. Dithering is highly recommended with this + * quantizer, though you can turn it off if you really want to. + * + * In 1-pass quantization the colormap must be chosen in advance of seeing the + * image. We use a map consisting of all combinations of Ncolors[i] color + * values for the i'th component. The Ncolors[] values are chosen so that + * their product, the total number of colors, is no more than that requested. + * (In most cases, the product will be somewhat less.) + * + * Since the colormap is orthogonal, the representative value for each color + * component can be determined without considering the other components; + * then these indexes can be combined into a colormap index by a standard + * N-dimensional-array-subscript calculation. Most of the arithmetic involved + * can be precalculated and stored in the lookup table colorindex[]. + * colorindex[i][j] maps pixel value j in component i to the nearest + * representative value (grid plane) for that component; this index is + * multiplied by the array stride for component i, so that the + * index of the colormap entry closest to a given pixel value is just + * sum( colorindex[component-number][pixel-component-value] ) + * Aside from being fast, this scheme allows for variable spacing between + * representative values with no additional lookup cost. + * + * If gamma correction has been applied in color conversion, it might be wise + * to adjust the color grid spacing so that the representative colors are + * equidistant in linear space. At this writing, gamma correction is not + * implemented by jdcolor, so nothing is done here. + */ + + +/* Declarations for ordered dithering. + * + * We use a standard 16x16 ordered dither array. The basic concept of ordered + * dithering is described in many references, for instance Dale Schumacher's + * chapter II.2 of Graphics Gems II (James Arvo, ed. Academic Press, 1991). + * In place of Schumacher's comparisons against a "threshold" value, we add a + * "dither" value to the input pixel and then round the result to the nearest + * output value. The dither value is equivalent to (0.5 - threshold) times + * the distance between output values. For ordered dithering, we assume that + * the output colors are equally spaced; if not, results will probably be + * worse, since the dither may be too much or too little at a given point. + * + * The normal calculation would be to form pixel value + dither, range-limit + * this to 0..MAXJSAMPLE, and then index into the colorindex table as usual. + * We can skip the separate range-limiting step by extending the colorindex + * table in both directions. + */ + +#define ODITHER_SIZE 16 /* dimension of dither matrix */ +/* NB: if ODITHER_SIZE is not a power of 2, ODITHER_MASK uses will break */ +#define ODITHER_CELLS (ODITHER_SIZE*ODITHER_SIZE) /* # cells in matrix */ +#define ODITHER_MASK (ODITHER_SIZE-1) /* mask for wrapping around counters */ + +typedef int ODITHER_MATRIX[ODITHER_SIZE][ODITHER_SIZE]; +typedef int (*ODITHER_MATRIX_PTR)[ODITHER_SIZE]; + +static const UINT8 base_dither_matrix[ODITHER_SIZE][ODITHER_SIZE] = { + /* Bayer's order-4 dither array. Generated by the code given in + * Stephen Hawley's article "Ordered Dithering" in Graphics Gems I. + * The values in this array must range from 0 to ODITHER_CELLS-1. + */ + { 0,192, 48,240, 12,204, 60,252, 3,195, 51,243, 15,207, 63,255 }, + { 128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127 }, + { 32,224, 16,208, 44,236, 28,220, 35,227, 19,211, 47,239, 31,223 }, + { 160, 96,144, 80,172,108,156, 92,163, 99,147, 83,175,111,159, 95 }, + { 8,200, 56,248, 4,196, 52,244, 11,203, 59,251, 7,199, 55,247 }, + { 136, 72,184,120,132, 68,180,116,139, 75,187,123,135, 71,183,119 }, + { 40,232, 24,216, 36,228, 20,212, 43,235, 27,219, 39,231, 23,215 }, + { 168,104,152, 88,164,100,148, 84,171,107,155, 91,167,103,151, 87 }, + { 2,194, 50,242, 14,206, 62,254, 1,193, 49,241, 13,205, 61,253 }, + { 130, 66,178,114,142, 78,190,126,129, 65,177,113,141, 77,189,125 }, + { 34,226, 18,210, 46,238, 30,222, 33,225, 17,209, 45,237, 29,221 }, + { 162, 98,146, 82,174,110,158, 94,161, 97,145, 81,173,109,157, 93 }, + { 10,202, 58,250, 6,198, 54,246, 9,201, 57,249, 5,197, 53,245 }, + { 138, 74,186,122,134, 70,182,118,137, 73,185,121,133, 69,181,117 }, + { 42,234, 26,218, 38,230, 22,214, 41,233, 25,217, 37,229, 21,213 }, + { 170,106,154, 90,166,102,150, 86,169,105,153, 89,165,101,149, 85 } +}; + + +/* Declarations for Floyd-Steinberg dithering. + * + * Errors are accumulated into the array fserrors[], at a resolution of + * 1/16th of a pixel count. The error at a given pixel is propagated + * to its not-yet-processed neighbors using the standard F-S fractions, + * ... (here) 7/16 + * 3/16 5/16 1/16 + * We work left-to-right on even rows, right-to-left on odd rows. + * + * We can get away with a single array (holding one row's worth of errors) + * by using it to store the current row's errors at pixel columns not yet + * processed, but the next row's errors at columns already processed. We + * need only a few extra variables to hold the errors immediately around the + * current column. (If we are lucky, those variables are in registers, but + * even if not, they're probably cheaper to access than array elements are.) + * + * The fserrors[] array is indexed [component#][position]. + * We provide (#columns + 2) entries per component; the extra entry at each + * end saves us from special-casing the first and last pixels. + * + * Note: on a wide image, we might not have enough room in a PC's near data + * segment to hold the error array; so it is allocated with alloc_large. + */ + +#if BITS_IN_JSAMPLE == 8 +typedef INT16 FSERROR; /* 16 bits should be enough */ +typedef int LOCFSERROR; /* use 'int' for calculation temps */ +#else +typedef INT32 FSERROR; /* may need more than 16 bits */ +typedef INT32 LOCFSERROR; /* be sure calculation temps are big enough */ +#endif + +typedef FSERROR FAR *FSERRPTR; /* pointer to error array (in FAR storage!) */ + + +/* Private subobject */ + +#define MAX_Q_COMPS 4 /* max components I can handle */ + +typedef struct { + struct jpeg_color_quantizer pub; /* public fields */ + + /* Initially allocated colormap is saved here */ + JSAMPARRAY sv_colormap; /* The color map as a 2-D pixel array */ + int sv_actual; /* number of entries in use */ + + JSAMPARRAY colorindex; /* Precomputed mapping for speed */ + /* colorindex[i][j] = index of color closest to pixel value j in component i, + * premultiplied as described above. Since colormap indexes must fit into + * JSAMPLEs, the entries of this array will too. + */ + boolean is_padded; /* is the colorindex padded for odither? */ + + int Ncolors[MAX_Q_COMPS]; /* # of values alloced to each component */ + + /* Variables for ordered dithering */ + int row_index; /* cur row's vertical index in dither matrix */ + ODITHER_MATRIX_PTR odither[MAX_Q_COMPS]; /* one dither array per component */ + + /* Variables for Floyd-Steinberg dithering */ + FSERRPTR fserrors[MAX_Q_COMPS]; /* accumulated errors */ + boolean on_odd_row; /* flag to remember which row we are on */ +} my_cquantizer; + +typedef my_cquantizer * my_cquantize_ptr; + + +/* + * Policy-making subroutines for create_colormap and create_colorindex. + * These routines determine the colormap to be used. The rest of the module + * only assumes that the colormap is orthogonal. + * + * * select_ncolors decides how to divvy up the available colors + * among the components. + * * output_value defines the set of representative values for a component. + * * largest_input_value defines the mapping from input values to + * representative values for a component. + * Note that the latter two routines may impose different policies for + * different components, though this is not currently done. + */ + + +LOCAL(int) +select_ncolors (j_decompress_ptr cinfo, int Ncolors[]) +/* Determine allocation of desired colors to components, */ +/* and fill in Ncolors[] array to indicate choice. */ +/* Return value is total number of colors (product of Ncolors[] values). */ +{ + int nc = cinfo->out_color_components; /* number of color components */ + int max_colors = cinfo->desired_number_of_colors; + int total_colors, iroot, i, j; + boolean changed; + long temp; + static const int RGB_order[3] = { RGB_GREEN, RGB_RED, RGB_BLUE }; + + /* We can allocate at least the nc'th root of max_colors per component. */ + /* Compute floor(nc'th root of max_colors). */ + iroot = 1; + do { + iroot++; + temp = iroot; /* set temp = iroot ** nc */ + for (i = 1; i < nc; i++) + temp *= iroot; + } while (temp <= (long) max_colors); /* repeat till iroot exceeds root */ + iroot--; /* now iroot = floor(root) */ + + /* Must have at least 2 color values per component */ + if (iroot < 2) + ERREXIT1(cinfo, JERR_QUANT_FEW_COLORS, (int) temp); + + /* Initialize to iroot color values for each component */ + total_colors = 1; + for (i = 0; i < nc; i++) { + Ncolors[i] = iroot; + total_colors *= iroot; + } + /* We may be able to increment the count for one or more components without + * exceeding max_colors, though we know not all can be incremented. + * Sometimes, the first component can be incremented more than once! + * (Example: for 16 colors, we start at 2*2*2, go to 3*2*2, then 4*2*2.) + * In RGB colorspace, try to increment G first, then R, then B. + */ + do { + changed = FALSE; + for (i = 0; i < nc; i++) { + j = (cinfo->out_color_space == JCS_RGB ? RGB_order[i] : i); + /* calculate new total_colors if Ncolors[j] is incremented */ + temp = total_colors / Ncolors[j]; + temp *= Ncolors[j]+1; /* done in long arith to avoid oflo */ + if (temp > (long) max_colors) + break; /* won't fit, done with this pass */ + Ncolors[j]++; /* OK, apply the increment */ + total_colors = (int) temp; + changed = TRUE; + } + } while (changed); + + return total_colors; +} + + +LOCAL(int) +output_value (j_decompress_ptr cinfo, int ci, int j, int maxj) +/* Return j'th output value, where j will range from 0 to maxj */ +/* The output values must fall in 0..MAXJSAMPLE in increasing order */ +{ + (void)cinfo;(void)ci; + /* We always provide values 0 and MAXJSAMPLE for each component; + * any additional values are equally spaced between these limits. + * (Forcing the upper and lower values to the limits ensures that + * dithering can't produce a color outside the selected gamut.) + */ + return (int) (((INT32) j * MAXJSAMPLE + maxj/2) / maxj); +} + + +LOCAL(int) +largest_input_value (j_decompress_ptr cinfo, int ci, int j, int maxj) +/* Return largest input value that should map to j'th output value */ +/* Must have largest(j=0) >= 0, and largest(j=maxj) >= MAXJSAMPLE */ +{ + (void)cinfo;(void)ci; + /* Breakpoints are halfway between values returned by output_value */ + return (int) (((INT32) (2*j + 1) * MAXJSAMPLE + maxj) / (2*maxj)); +} + + +/* + * Create the colormap. + */ + +LOCAL(void) +create_colormap (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + JSAMPARRAY colormap; /* Created colormap */ + int total_colors; /* Number of distinct output colors */ + int i,j,k, nci, blksize, blkdist, ptr, val; + + /* Select number of colors for each component */ + total_colors = select_ncolors(cinfo, cquantize->Ncolors); + + /* Report selected color counts */ + if (cinfo->out_color_components == 3) + TRACEMS4(cinfo, 1, JTRC_QUANT_3_NCOLORS, + total_colors, cquantize->Ncolors[0], + cquantize->Ncolors[1], cquantize->Ncolors[2]); + else + TRACEMS1(cinfo, 1, JTRC_QUANT_NCOLORS, total_colors); + + /* Allocate and fill in the colormap. */ + /* The colors are ordered in the map in standard row-major order, */ + /* i.e. rightmost (highest-indexed) color changes most rapidly. */ + + colormap = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (JDIMENSION) total_colors, (JDIMENSION) cinfo->out_color_components); + + /* blksize is number of adjacent repeated entries for a component */ + /* blkdist is distance between groups of identical entries for a component */ + blkdist = total_colors; + + for (i = 0; i < cinfo->out_color_components; i++) { + /* fill in colormap entries for i'th color component */ + nci = cquantize->Ncolors[i]; /* # of distinct values for this color */ + blksize = blkdist / nci; + for (j = 0; j < nci; j++) { + /* Compute j'th output value (out of nci) for component */ + val = output_value(cinfo, i, j, nci-1); + /* Fill in all colormap entries that have this value of this component */ + for (ptr = j * blksize; ptr < total_colors; ptr += blkdist) { + /* fill in blksize entries beginning at ptr */ + for (k = 0; k < blksize; k++) + colormap[i][ptr+k] = (JSAMPLE) val; + } + } + blkdist = blksize; /* blksize of this color is blkdist of next */ + } + + /* Save the colormap in private storage, + * where it will survive color quantization mode changes. + */ + cquantize->sv_colormap = colormap; + cquantize->sv_actual = total_colors; +} + + +/* + * Create the color index table. + */ + +LOCAL(void) +create_colorindex (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + JSAMPROW indexptr; + int i,j,k, nci, blksize, val, pad; + + /* For ordered dither, we pad the color index tables by MAXJSAMPLE in + * each direction (input index values can be -MAXJSAMPLE .. 2*MAXJSAMPLE). + * This is not necessary in the other dithering modes. However, we + * flag whether it was done in case user changes dithering mode. + */ + if (cinfo->dither_mode == JDITHER_ORDERED) { + pad = MAXJSAMPLE*2; + cquantize->is_padded = TRUE; + } else { + pad = 0; + cquantize->is_padded = FALSE; + } + + cquantize->colorindex = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (JDIMENSION) (MAXJSAMPLE+1 + pad), + (JDIMENSION) cinfo->out_color_components); + + /* blksize is number of adjacent repeated entries for a component */ + blksize = cquantize->sv_actual; + + for (i = 0; i < cinfo->out_color_components; i++) { + /* fill in colorindex entries for i'th color component */ + nci = cquantize->Ncolors[i]; /* # of distinct values for this color */ + blksize = blksize / nci; + + /* adjust colorindex pointers to provide padding at negative indexes. */ + if (pad) + cquantize->colorindex[i] += MAXJSAMPLE; + + /* in loop, val = index of current output value, */ + /* and k = largest j that maps to current val */ + indexptr = cquantize->colorindex[i]; + val = 0; + k = largest_input_value(cinfo, i, 0, nci-1); + for (j = 0; j <= MAXJSAMPLE; j++) { + while (j > k) /* advance val if past boundary */ + k = largest_input_value(cinfo, i, ++val, nci-1); + /* premultiply so that no multiplication needed in main processing */ + indexptr[j] = (JSAMPLE) (val * blksize); + } + /* Pad at both ends if necessary */ + if (pad) + for (j = 1; j <= MAXJSAMPLE; j++) { + indexptr[-j] = indexptr[0]; + indexptr[MAXJSAMPLE+j] = indexptr[MAXJSAMPLE]; + } + } +} + + +/* + * Create an ordered-dither array for a component having ncolors + * distinct output values. + */ + +LOCAL(ODITHER_MATRIX_PTR) +make_odither_array (j_decompress_ptr cinfo, int ncolors) +{ + ODITHER_MATRIX_PTR odither; + int j,k; + INT32 num,den; + + odither = (ODITHER_MATRIX_PTR) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(ODITHER_MATRIX)); + /* The inter-value distance for this color is MAXJSAMPLE/(ncolors-1). + * Hence the dither value for the matrix cell with fill order f + * (f=0..N-1) should be (N-1-2*f)/(2*N) * MAXJSAMPLE/(ncolors-1). + * On 16-bit-int machine, be careful to avoid overflow. + */ + den = 2 * ODITHER_CELLS * ((INT32) (ncolors - 1)); + for (j = 0; j < ODITHER_SIZE; j++) { + for (k = 0; k < ODITHER_SIZE; k++) { + num = ((INT32) (ODITHER_CELLS-1 - 2*((int)base_dither_matrix[j][k]))) + * MAXJSAMPLE; + /* Ensure round towards zero despite C's lack of consistency + * about rounding negative values in integer division... + */ + odither[j][k] = (int) (num<0 ? -((-num)/den) : num/den); + } + } + return odither; +} + + +/* + * Create the ordered-dither tables. + * Components having the same number of representative colors may + * share a dither table. + */ + +LOCAL(void) +create_odither_tables (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + ODITHER_MATRIX_PTR odither; + int i, j, nci; + + for (i = 0; i < cinfo->out_color_components; i++) { + nci = cquantize->Ncolors[i]; /* # of distinct values for this color */ + odither = NULL; /* search for matching prior component */ + for (j = 0; j < i; j++) { + if (nci == cquantize->Ncolors[j]) { + odither = cquantize->odither[j]; + break; + } + } + if (odither == NULL) /* need a new table? */ + odither = make_odither_array(cinfo, nci); + cquantize->odither[i] = odither; + } +} + + +/* + * Map some rows of pixels to the output colormapped representation. + */ + +METHODDEF(void) +color_quantize (j_decompress_ptr cinfo, JSAMPARRAY input_buf, + JSAMPARRAY output_buf, int num_rows) +/* General case, no dithering */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + JSAMPARRAY colorindex = cquantize->colorindex; + register int pixcode, ci; + register JSAMPROW ptrin, ptrout; + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + register int nc = cinfo->out_color_components; + + for (row = 0; row < num_rows; row++) { + ptrin = input_buf[row]; + ptrout = output_buf[row]; + for (col = width; col > 0; col--) { + pixcode = 0; + for (ci = 0; ci < nc; ci++) { + pixcode += GETJSAMPLE(colorindex[ci][GETJSAMPLE(*ptrin++)]); + } + *ptrout++ = (JSAMPLE) pixcode; + } + } +} + + +METHODDEF(void) +color_quantize3 (j_decompress_ptr cinfo, JSAMPARRAY input_buf, + JSAMPARRAY output_buf, int num_rows) +/* Fast path for out_color_components==3, no dithering */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + register int pixcode; + register JSAMPROW ptrin, ptrout; + JSAMPROW colorindex0 = cquantize->colorindex[0]; + JSAMPROW colorindex1 = cquantize->colorindex[1]; + JSAMPROW colorindex2 = cquantize->colorindex[2]; + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + + for (row = 0; row < num_rows; row++) { + ptrin = input_buf[row]; + ptrout = output_buf[row]; + for (col = width; col > 0; col--) { + pixcode = GETJSAMPLE(colorindex0[GETJSAMPLE(*ptrin++)]); + pixcode += GETJSAMPLE(colorindex1[GETJSAMPLE(*ptrin++)]); + pixcode += GETJSAMPLE(colorindex2[GETJSAMPLE(*ptrin++)]); + *ptrout++ = (JSAMPLE) pixcode; + } + } +} + + +METHODDEF(void) +quantize_ord_dither (j_decompress_ptr cinfo, JSAMPARRAY input_buf, + JSAMPARRAY output_buf, int num_rows) +/* General case, with ordered dithering */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + register JSAMPROW input_ptr; + register JSAMPROW output_ptr; + JSAMPROW colorindex_ci; + int * dither; /* points to active row of dither matrix */ + int row_index, col_index; /* current indexes into dither matrix */ + int nc = cinfo->out_color_components; + int ci; + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + + for (row = 0; row < num_rows; row++) { + /* Initialize output values to 0 so can process components separately */ + jzero_far((void FAR *) output_buf[row], + (size_t) (width * SIZEOF(JSAMPLE))); + row_index = cquantize->row_index; + for (ci = 0; ci < nc; ci++) { + input_ptr = input_buf[row] + ci; + output_ptr = output_buf[row]; + colorindex_ci = cquantize->colorindex[ci]; + dither = cquantize->odither[ci][row_index]; + col_index = 0; + + for (col = width; col > 0; col--) { + /* Form pixel value + dither, range-limit to 0..MAXJSAMPLE, + * select output value, accumulate into output code for this pixel. + * Range-limiting need not be done explicitly, as we have extended + * the colorindex table to produce the right answers for out-of-range + * inputs. The maximum dither is +- MAXJSAMPLE; this sets the + * required amount of padding. + */ + *output_ptr += colorindex_ci[GETJSAMPLE(*input_ptr)+dither[col_index]]; + input_ptr += nc; + output_ptr++; + col_index = (col_index + 1) & ODITHER_MASK; + } + } + /* Advance row index for next row */ + row_index = (row_index + 1) & ODITHER_MASK; + cquantize->row_index = row_index; + } +} + + +METHODDEF(void) +quantize3_ord_dither (j_decompress_ptr cinfo, JSAMPARRAY input_buf, + JSAMPARRAY output_buf, int num_rows) +/* Fast path for out_color_components==3, with ordered dithering */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + register int pixcode; + register JSAMPROW input_ptr; + register JSAMPROW output_ptr; + JSAMPROW colorindex0 = cquantize->colorindex[0]; + JSAMPROW colorindex1 = cquantize->colorindex[1]; + JSAMPROW colorindex2 = cquantize->colorindex[2]; + int * dither0; /* points to active row of dither matrix */ + int * dither1; + int * dither2; + int row_index, col_index; /* current indexes into dither matrix */ + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + + for (row = 0; row < num_rows; row++) { + row_index = cquantize->row_index; + input_ptr = input_buf[row]; + output_ptr = output_buf[row]; + dither0 = cquantize->odither[0][row_index]; + dither1 = cquantize->odither[1][row_index]; + dither2 = cquantize->odither[2][row_index]; + col_index = 0; + + for (col = width; col > 0; col--) { + pixcode = GETJSAMPLE(colorindex0[GETJSAMPLE(*input_ptr++) + + dither0[col_index]]); + pixcode += GETJSAMPLE(colorindex1[GETJSAMPLE(*input_ptr++) + + dither1[col_index]]); + pixcode += GETJSAMPLE(colorindex2[GETJSAMPLE(*input_ptr++) + + dither2[col_index]]); + *output_ptr++ = (JSAMPLE) pixcode; + col_index = (col_index + 1) & ODITHER_MASK; + } + row_index = (row_index + 1) & ODITHER_MASK; + cquantize->row_index = row_index; + } +} + + +METHODDEF(void) +quantize_fs_dither (j_decompress_ptr cinfo, JSAMPARRAY input_buf, + JSAMPARRAY output_buf, int num_rows) +/* General case, with Floyd-Steinberg dithering */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + register LOCFSERROR cur; /* current error or pixel value */ + LOCFSERROR belowerr; /* error for pixel below cur */ + LOCFSERROR bpreverr; /* error for below/prev col */ + LOCFSERROR bnexterr; /* error for below/next col */ + LOCFSERROR delta; + register FSERRPTR errorptr; /* => fserrors[] at column before current */ + register JSAMPROW input_ptr; + register JSAMPROW output_ptr; + JSAMPROW colorindex_ci; + JSAMPROW colormap_ci; + int pixcode; + int nc = cinfo->out_color_components; + int dir; /* 1 for left-to-right, -1 for right-to-left */ + int dirnc; /* dir * nc */ + int ci; + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + JSAMPLE *range_limit = cinfo->sample_range_limit; + SHIFT_TEMPS + + for (row = 0; row < num_rows; row++) { + /* Initialize output values to 0 so can process components separately */ + jzero_far((void FAR *) output_buf[row], + (size_t) (width * SIZEOF(JSAMPLE))); + for (ci = 0; ci < nc; ci++) { + input_ptr = input_buf[row] + ci; + output_ptr = output_buf[row]; + if (cquantize->on_odd_row) { + /* work right to left in this row */ + input_ptr += (width-1) * nc; /* so point to rightmost pixel */ + output_ptr += width-1; + dir = -1; + dirnc = -nc; + errorptr = cquantize->fserrors[ci] + (width+1); /* => entry after last column */ + } else { + /* work left to right in this row */ + dir = 1; + dirnc = nc; + errorptr = cquantize->fserrors[ci]; /* => entry before first column */ + } + colorindex_ci = cquantize->colorindex[ci]; + colormap_ci = cquantize->sv_colormap[ci]; + /* Preset error values: no error propagated to first pixel from left */ + cur = 0; + /* and no error propagated to row below yet */ + belowerr = bpreverr = 0; + + for (col = width; col > 0; col--) { + /* cur holds the error propagated from the previous pixel on the + * current line. Add the error propagated from the previous line + * to form the complete error correction term for this pixel, and + * round the error term (which is expressed * 16) to an integer. + * RIGHT_SHIFT rounds towards minus infinity, so adding 8 is correct + * for either sign of the error value. + * Note: errorptr points to *previous* column's array entry. + */ + cur = RIGHT_SHIFT(cur + errorptr[dir] + 8, 4); + /* Form pixel value + error, and range-limit to 0..MAXJSAMPLE. + * The maximum error is +- MAXJSAMPLE; this sets the required size + * of the range_limit array. + */ + cur += GETJSAMPLE(*input_ptr); + cur = GETJSAMPLE(range_limit[cur]); + /* Select output value, accumulate into output code for this pixel */ + pixcode = GETJSAMPLE(colorindex_ci[cur]); + *output_ptr += (JSAMPLE) pixcode; + /* Compute actual representation error at this pixel */ + /* Note: we can do this even though we don't have the final */ + /* pixel code, because the colormap is orthogonal. */ + cur -= GETJSAMPLE(colormap_ci[pixcode]); + /* Compute error fractions to be propagated to adjacent pixels. + * Add these into the running sums, and simultaneously shift the + * next-line error sums left by 1 column. + */ + bnexterr = cur; + delta = cur * 2; + cur += delta; /* form error * 3 */ + errorptr[0] = (FSERROR) (bpreverr + cur); + cur += delta; /* form error * 5 */ + bpreverr = belowerr + cur; + belowerr = bnexterr; + cur += delta; /* form error * 7 */ + /* At this point cur contains the 7/16 error value to be propagated + * to the next pixel on the current line, and all the errors for the + * next line have been shifted over. We are therefore ready to move on. + */ + input_ptr += dirnc; /* advance input ptr to next column */ + output_ptr += dir; /* advance output ptr to next column */ + errorptr += dir; /* advance errorptr to current column */ + } + /* Post-loop cleanup: we must unload the final error value into the + * final fserrors[] entry. Note we need not unload belowerr because + * it is for the dummy column before or after the actual array. + */ + errorptr[0] = (FSERROR) bpreverr; /* unload prev err into array */ + } + cquantize->on_odd_row = (cquantize->on_odd_row ? FALSE : TRUE); + } +} + + +/* + * Allocate workspace for Floyd-Steinberg errors. + */ + +LOCAL(void) +alloc_fs_workspace (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + size_t arraysize; + int i; + + arraysize = (size_t) ((cinfo->output_width + 2) * SIZEOF(FSERROR)); + for (i = 0; i < cinfo->out_color_components; i++) { + cquantize->fserrors[i] = (FSERRPTR) + (*cinfo->mem->alloc_large)((j_common_ptr) cinfo, JPOOL_IMAGE, arraysize); + } +} + + +/* + * Initialize for one-pass color quantization. + */ + +METHODDEF(void) +start_pass_1_quant (j_decompress_ptr cinfo, boolean is_pre_scan) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + size_t arraysize; + int i; + (void)is_pre_scan; + + /* Install my colormap. */ + cinfo->colormap = cquantize->sv_colormap; + cinfo->actual_number_of_colors = cquantize->sv_actual; + + /* Initialize for desired dithering mode. */ + switch (cinfo->dither_mode) { + case JDITHER_NONE: + if (cinfo->out_color_components == 3) + cquantize->pub.color_quantize = color_quantize3; + else + cquantize->pub.color_quantize = color_quantize; + break; + case JDITHER_ORDERED: + if (cinfo->out_color_components == 3) + cquantize->pub.color_quantize = quantize3_ord_dither; + else + cquantize->pub.color_quantize = quantize_ord_dither; + cquantize->row_index = 0; /* initialize state for ordered dither */ + /* If user changed to ordered dither from another mode, + * we must recreate the color index table with padding. + * This will cost extra space, but probably isn't very likely. + */ + if (! cquantize->is_padded) + create_colorindex(cinfo); + /* Create ordered-dither tables if we didn't already. */ + if (cquantize->odither[0] == NULL) + create_odither_tables(cinfo); + break; + case JDITHER_FS: + cquantize->pub.color_quantize = quantize_fs_dither; + cquantize->on_odd_row = FALSE; /* initialize state for F-S dither */ + /* Allocate Floyd-Steinberg workspace if didn't already. */ + if (cquantize->fserrors[0] == NULL) + alloc_fs_workspace(cinfo); + /* Initialize the propagated errors to zero. */ + arraysize = (size_t) ((cinfo->output_width + 2) * SIZEOF(FSERROR)); + for (i = 0; i < cinfo->out_color_components; i++) + jzero_far((void FAR *) cquantize->fserrors[i], arraysize); + break; + default: + ERREXIT(cinfo, JERR_NOT_COMPILED); + break; + } +} + + +/* + * Finish up at the end of the pass. + */ + +METHODDEF(void) +finish_pass_1_quant (j_decompress_ptr cinfo) +{ + (void)cinfo; + /* no work in 1-pass case */ +} + + +/* + * Switch to a new external colormap between output passes. + * Shouldn't get to this module! + */ + +METHODDEF(void) +new_color_map_1_quant (j_decompress_ptr cinfo) +{ + ERREXIT(cinfo, JERR_MODE_CHANGE); +} + + +/* + * Module initialization routine for 1-pass color quantization. + */ + +GLOBAL(void) +jinit_1pass_quantizer (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize; + + cquantize = (my_cquantize_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_cquantizer)); + cinfo->cquantize = (struct jpeg_color_quantizer *) cquantize; + cquantize->pub.start_pass = start_pass_1_quant; + cquantize->pub.finish_pass = finish_pass_1_quant; + cquantize->pub.new_color_map = new_color_map_1_quant; + cquantize->fserrors[0] = NULL; /* Flag FS workspace not allocated */ + cquantize->odither[0] = NULL; /* Also flag odither arrays not allocated */ + + /* Make sure my internal arrays won't overflow */ + if (cinfo->out_color_components > MAX_Q_COMPS) + ERREXIT1(cinfo, JERR_QUANT_COMPONENTS, MAX_Q_COMPS); + /* Make sure colormap indexes can be represented by JSAMPLEs */ + if (cinfo->desired_number_of_colors > (MAXJSAMPLE+1)) + ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, MAXJSAMPLE+1); + + /* Create the colormap and color index table. */ + create_colormap(cinfo); + create_colorindex(cinfo); + + /* Allocate Floyd-Steinberg workspace now if requested. + * We do this now since it is FAR storage and may affect the memory + * manager's space calculations. If the user changes to FS dither + * mode in a later pass, we will allocate the space then, and will + * possibly overrun the max_memory_to_use setting. + */ + if (cinfo->dither_mode == JDITHER_FS) + alloc_fs_workspace(cinfo); +} + +#endif /* QUANT_1PASS_SUPPORTED */ diff --git a/Utilities/ITK/Utilities/itkjpeg/jquant2.c b/Utilities/ITK/Utilities/itkjpeg/jquant2.c new file mode 100644 index 0000000000000000000000000000000000000000..9f9f7091906c0f455f9c4bc93897161dd7dcf971 --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jquant2.c @@ -0,0 +1,1312 @@ +/* + * jquant2.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains 2-pass color quantization (color mapping) routines. + * These routines provide selection of a custom color map for an image, + * followed by mapping of the image to that color map, with optional + * Floyd-Steinberg dithering. + * It is also possible to use just the second pass to map to an arbitrary + * externally-given color map. + * + * Note: ordered dithering is not supported, since there isn't any fast + * way to compute intercolor distances; it's unclear that ordered dither's + * fundamental assumptions even hold with an irregularly spaced color map. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + +#ifdef QUANT_2PASS_SUPPORTED + + +/* + * This module implements the well-known Heckbert paradigm for color + * quantization. Most of the ideas used here can be traced back to + * Heckbert's seminal paper + * Heckbert, Paul. "Color Image Quantization for Frame Buffer Display", + * Proc. SIGGRAPH '82, Computer Graphics v.16 #3 (July 1982), pp 297-304. + * + * In the first pass over the image, we accumulate a histogram showing the + * usage count of each possible color. To keep the histogram to a reasonable + * size, we reduce the precision of the input; typical practice is to retain + * 5 or 6 bits per color, so that 8 or 4 different input values are counted + * in the same histogram cell. + * + * Next, the color-selection step begins with a box representing the whole + * color space, and repeatedly splits the "largest" remaining box until we + * have as many boxes as desired colors. Then the mean color in each + * remaining box becomes one of the possible output colors. + * + * The second pass over the image maps each input pixel to the closest output + * color (optionally after applying a Floyd-Steinberg dithering correction). + * This mapping is logically trivial, but making it go fast enough requires + * considerable care. + * + * Heckbert-style quantizers vary a good deal in their policies for choosing + * the "largest" box and deciding where to cut it. The particular policies + * used here have proved out well in experimental comparisons, but better ones + * may yet be found. + * + * In earlier versions of the IJG code, this module quantized in YCbCr color + * space, processing the raw upsampled data without a color conversion step. + * This allowed the color conversion math to be done only once per colormap + * entry, not once per pixel. However, that optimization precluded other + * useful optimizations (such as merging color conversion with upsampling) + * and it also interfered with desired capabilities such as quantizing to an + * externally-supplied colormap. We have therefore abandoned that approach. + * The present code works in the post-conversion color space, typically RGB. + * + * To improve the visual quality of the results, we actually work in scaled + * RGB space, giving G distances more weight than R, and R in turn more than + * B. To do everything in integer math, we must use integer scale factors. + * The 2/3/1 scale factors used here correspond loosely to the relative + * weights of the colors in the NTSC grayscale equation. + * If you want to use this code to quantize a non-RGB color space, you'll + * probably need to change these scale factors. + */ + +#define R_SCALE 2 /* scale R distances by this much */ +#define G_SCALE 3 /* scale G distances by this much */ +#define B_SCALE 1 /* and B by this much */ + +/* Relabel R/G/B as components 0/1/2, respecting the RGB ordering defined + * in jmorecfg.h. As the code stands, it will do the right thing for R,G,B + * and B,G,R orders. If you define some other weird order in jmorecfg.h, + * you'll get compile errors until you extend this logic. In that case + * you'll probably want to tweak the histogram sizes too. + */ + +#if RGB_RED == 0 +#define C0_SCALE R_SCALE +#endif +#if RGB_BLUE == 0 +#define C0_SCALE B_SCALE +#endif +#if RGB_GREEN == 1 +#define C1_SCALE G_SCALE +#endif +#if RGB_RED == 2 +#define C2_SCALE R_SCALE +#endif +#if RGB_BLUE == 2 +#define C2_SCALE B_SCALE +#endif + + +/* + * First we have the histogram data structure and routines for creating it. + * + * The number of bits of precision can be adjusted by changing these symbols. + * We recommend keeping 6 bits for G and 5 each for R and B. + * If you have plenty of memory and cycles, 6 bits all around gives marginally + * better results; if you are short of memory, 5 bits all around will save + * some space but degrade the results. + * To maintain a fully accurate histogram, we'd need to allocate a "long" + * (preferably unsigned long) for each cell. In practice this is overkill; + * we can get by with 16 bits per cell. Few of the cell counts will overflow, + * and clamping those that do overflow to the maximum value will give close- + * enough results. This reduces the recommended histogram size from 256Kb + * to 128Kb, which is a useful savings on PC-class machines. + * (In the second pass the histogram space is re-used for pixel mapping data; + * in that capacity, each cell must be able to store zero to the number of + * desired colors. 16 bits/cell is plenty for that too.) + * Since the JPEG code is intended to run in small memory model on 80x86 + * machines, we can't just allocate the histogram in one chunk. Instead + * of a true 3-D array, we use a row of pointers to 2-D arrays. Each + * pointer corresponds to a C0 value (typically 2^5 = 32 pointers) and + * each 2-D array has 2^6*2^5 = 2048 or 2^6*2^6 = 4096 entries. Note that + * on 80x86 machines, the pointer row is in near memory but the actual + * arrays are in far memory (same arrangement as we use for image arrays). + */ + +#define MAXNUMCOLORS (MAXJSAMPLE+1) /* maximum size of colormap */ + +/* These will do the right thing for either R,G,B or B,G,R color order, + * but you may not like the results for other color orders. + */ +#define HIST_C0_BITS 5 /* bits of precision in R/B histogram */ +#define HIST_C1_BITS 6 /* bits of precision in G histogram */ +#define HIST_C2_BITS 5 /* bits of precision in B/R histogram */ + +/* Number of elements along histogram axes. */ +#define HIST_C0_ELEMS (1<<HIST_C0_BITS) +#define HIST_C1_ELEMS (1<<HIST_C1_BITS) +#define HIST_C2_ELEMS (1<<HIST_C2_BITS) + +/* These are the amounts to shift an input value to get a histogram index. */ +#define C0_SHIFT (BITS_IN_JSAMPLE-HIST_C0_BITS) +#define C1_SHIFT (BITS_IN_JSAMPLE-HIST_C1_BITS) +#define C2_SHIFT (BITS_IN_JSAMPLE-HIST_C2_BITS) + + +typedef UINT16 histcell; /* histogram cell; prefer an unsigned type */ + +typedef histcell FAR * histptr; /* for pointers to histogram cells */ + +typedef histcell hist1d[HIST_C2_ELEMS]; /* typedefs for the array */ +typedef hist1d FAR * hist2d; /* type for the 2nd-level pointers */ +typedef hist2d * hist3d; /* type for top-level pointer */ + + +/* Declarations for Floyd-Steinberg dithering. + * + * Errors are accumulated into the array fserrors[], at a resolution of + * 1/16th of a pixel count. The error at a given pixel is propagated + * to its not-yet-processed neighbors using the standard F-S fractions, + * ... (here) 7/16 + * 3/16 5/16 1/16 + * We work left-to-right on even rows, right-to-left on odd rows. + * + * We can get away with a single array (holding one row's worth of errors) + * by using it to store the current row's errors at pixel columns not yet + * processed, but the next row's errors at columns already processed. We + * need only a few extra variables to hold the errors immediately around the + * current column. (If we are lucky, those variables are in registers, but + * even if not, they're probably cheaper to access than array elements are.) + * + * The fserrors[] array has (#columns + 2) entries; the extra entry at + * each end saves us from special-casing the first and last pixels. + * Each entry is three values long, one value for each color component. + * + * Note: on a wide image, we might not have enough room in a PC's near data + * segment to hold the error array; so it is allocated with alloc_large. + */ + +#if BITS_IN_JSAMPLE == 8 +typedef INT16 FSERROR; /* 16 bits should be enough */ +typedef int LOCFSERROR; /* use 'int' for calculation temps */ +#else +typedef INT32 FSERROR; /* may need more than 16 bits */ +typedef INT32 LOCFSERROR; /* be sure calculation temps are big enough */ +#endif + +typedef FSERROR FAR *FSERRPTR; /* pointer to error array (in FAR storage!) */ + + +/* Private subobject */ + +typedef struct { + struct jpeg_color_quantizer pub; /* public fields */ + + /* Space for the eventually created colormap is stashed here */ + JSAMPARRAY sv_colormap; /* colormap allocated at init time */ + int desired; /* desired # of colors = size of colormap */ + + /* Variables for accumulating image statistics */ + hist3d histogram; /* pointer to the histogram */ + + boolean needs_zeroed; /* TRUE if next pass must zero histogram */ + + /* Variables for Floyd-Steinberg dithering */ + FSERRPTR fserrors; /* accumulated errors */ + boolean on_odd_row; /* flag to remember which row we are on */ + int * error_limiter; /* table for clamping the applied error */ +} my_cquantizer; + +typedef my_cquantizer * my_cquantize_ptr; + + +/* + * Prescan some rows of pixels. + * In this module the prescan simply updates the histogram, which has been + * initialized to zeroes by start_pass. + * An output_buf parameter is required by the method signature, but no data + * is actually output (in fact the buffer controller is probably passing a + * NULL pointer). + */ + +METHODDEF(void) +prescan_quantize (j_decompress_ptr cinfo, JSAMPARRAY input_buf, + JSAMPARRAY output_buf, int num_rows) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + register JSAMPROW ptr; + register histptr histp; + register hist3d histogram = cquantize->histogram; + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + (void)output_buf; + + for (row = 0; row < num_rows; row++) { + ptr = input_buf[row]; + for (col = width; col > 0; col--) { + /* get pixel value and index into the histogram */ + histp = & histogram[GETJSAMPLE(ptr[0]) >> C0_SHIFT] + [GETJSAMPLE(ptr[1]) >> C1_SHIFT] + [GETJSAMPLE(ptr[2]) >> C2_SHIFT]; + /* increment, check for overflow and undo increment if so. */ + if (++(*histp) <= 0) + (*histp)--; + ptr += 3; + } + } +} + + +/* + * Next we have the really interesting routines: selection of a colormap + * given the completed histogram. + * These routines work with a list of "boxes", each representing a rectangular + * subset of the input color space (to histogram precision). + */ + +typedef struct { + /* The bounds of the box (inclusive); expressed as histogram indexes */ + int c0min, c0max; + int c1min, c1max; + int c2min, c2max; + /* The volume (actually 2-norm) of the box */ + INT32 volume; + /* The number of nonzero histogram cells within this box */ + long colorcount; +} box; + +typedef box * boxptr; + + +LOCAL(boxptr) +find_biggest_color_pop (boxptr boxlist, int numboxes) +/* Find the splittable box with the largest color population */ +/* Returns NULL if no splittable boxes remain */ +{ + register boxptr boxp; + register int i; + register long maxc = 0; + boxptr which = NULL; + + for (i = 0, boxp = boxlist; i < numboxes; i++, boxp++) { + if (boxp->colorcount > maxc && boxp->volume > 0) { + which = boxp; + maxc = boxp->colorcount; + } + } + return which; +} + + +LOCAL(boxptr) +find_biggest_volume (boxptr boxlist, int numboxes) +/* Find the splittable box with the largest (scaled) volume */ +/* Returns NULL if no splittable boxes remain */ +{ + register boxptr boxp; + register int i; + register INT32 maxv = 0; + boxptr which = NULL; + + for (i = 0, boxp = boxlist; i < numboxes; i++, boxp++) { + if (boxp->volume > maxv) { + which = boxp; + maxv = boxp->volume; + } + } + return which; +} + + +LOCAL(void) +update_box (j_decompress_ptr cinfo, boxptr boxp) +/* Shrink the min/max bounds of a box to enclose only nonzero elements, */ +/* and recompute its volume and population */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + hist3d histogram = cquantize->histogram; + histptr histp; + int c0,c1,c2; + int c0min,c0max,c1min,c1max,c2min,c2max; + INT32 dist0,dist1,dist2; + long ccount; + + c0min = boxp->c0min; c0max = boxp->c0max; + c1min = boxp->c1min; c1max = boxp->c1max; + c2min = boxp->c2min; c2max = boxp->c2max; + + if (c0max > c0min) + for (c0 = c0min; c0 <= c0max; c0++) + for (c1 = c1min; c1 <= c1max; c1++) { + histp = & histogram[c0][c1][c2min]; + for (c2 = c2min; c2 <= c2max; c2++) + if (*histp++ != 0) { + boxp->c0min = c0min = c0; + goto have_c0min; + } + } + have_c0min: + if (c0max > c0min) + for (c0 = c0max; c0 >= c0min; c0--) + for (c1 = c1min; c1 <= c1max; c1++) { + histp = & histogram[c0][c1][c2min]; + for (c2 = c2min; c2 <= c2max; c2++) + if (*histp++ != 0) { + boxp->c0max = c0max = c0; + goto have_c0max; + } + } + have_c0max: + if (c1max > c1min) + for (c1 = c1min; c1 <= c1max; c1++) + for (c0 = c0min; c0 <= c0max; c0++) { + histp = & histogram[c0][c1][c2min]; + for (c2 = c2min; c2 <= c2max; c2++) + if (*histp++ != 0) { + boxp->c1min = c1min = c1; + goto have_c1min; + } + } + have_c1min: + if (c1max > c1min) + for (c1 = c1max; c1 >= c1min; c1--) + for (c0 = c0min; c0 <= c0max; c0++) { + histp = & histogram[c0][c1][c2min]; + for (c2 = c2min; c2 <= c2max; c2++) + if (*histp++ != 0) { + boxp->c1max = c1max = c1; + goto have_c1max; + } + } + have_c1max: + if (c2max > c2min) + for (c2 = c2min; c2 <= c2max; c2++) + for (c0 = c0min; c0 <= c0max; c0++) { + histp = & histogram[c0][c1min][c2]; + for (c1 = c1min; c1 <= c1max; c1++, histp += HIST_C2_ELEMS) + if (*histp != 0) { + boxp->c2min = c2min = c2; + goto have_c2min; + } + } + have_c2min: + if (c2max > c2min) + for (c2 = c2max; c2 >= c2min; c2--) + for (c0 = c0min; c0 <= c0max; c0++) { + histp = & histogram[c0][c1min][c2]; + for (c1 = c1min; c1 <= c1max; c1++, histp += HIST_C2_ELEMS) + if (*histp != 0) { + boxp->c2max = c2max = c2; + goto have_c2max; + } + } + have_c2max: + + /* Update box volume. + * We use 2-norm rather than real volume here; this biases the method + * against making long narrow boxes, and it has the side benefit that + * a box is splittable iff norm > 0. + * Since the differences are expressed in histogram-cell units, + * we have to shift back to JSAMPLE units to get consistent distances; + * after which, we scale according to the selected distance scale factors. + */ + dist0 = ((c0max - c0min) << C0_SHIFT) * C0_SCALE; + dist1 = ((c1max - c1min) << C1_SHIFT) * C1_SCALE; + dist2 = ((c2max - c2min) << C2_SHIFT) * C2_SCALE; + boxp->volume = dist0*dist0 + dist1*dist1 + dist2*dist2; + + /* Now scan remaining volume of box and compute population */ + ccount = 0; + for (c0 = c0min; c0 <= c0max; c0++) + for (c1 = c1min; c1 <= c1max; c1++) { + histp = & histogram[c0][c1][c2min]; + for (c2 = c2min; c2 <= c2max; c2++, histp++) + if (*histp != 0) { + ccount++; + } + } + boxp->colorcount = ccount; +} + + +LOCAL(int) +median_cut (j_decompress_ptr cinfo, boxptr boxlist, int numboxes, + int desired_colors) +/* Repeatedly select and split the largest box until we have enough boxes */ +{ + int n,lb; + int c0,c1,c2,cmax; + register boxptr b1,b2; + + while (numboxes < desired_colors) { + /* Select box to split. + * Current algorithm: by population for first half, then by volume. + */ + if (numboxes*2 <= desired_colors) { + b1 = find_biggest_color_pop(boxlist, numboxes); + } else { + b1 = find_biggest_volume(boxlist, numboxes); + } + if (b1 == NULL) /* no splittable boxes left! */ + break; + b2 = &boxlist[numboxes]; /* where new box will go */ + /* Copy the color bounds to the new box. */ + b2->c0max = b1->c0max; b2->c1max = b1->c1max; b2->c2max = b1->c2max; + b2->c0min = b1->c0min; b2->c1min = b1->c1min; b2->c2min = b1->c2min; + /* Choose which axis to split the box on. + * Current algorithm: longest scaled axis. + * See notes in update_box about scaling distances. + */ + c0 = ((b1->c0max - b1->c0min) << C0_SHIFT) * C0_SCALE; + c1 = ((b1->c1max - b1->c1min) << C1_SHIFT) * C1_SCALE; + c2 = ((b1->c2max - b1->c2min) << C2_SHIFT) * C2_SCALE; + /* We want to break any ties in favor of green, then red, blue last. + * This code does the right thing for R,G,B or B,G,R color orders only. + */ +#if RGB_RED == 0 + cmax = c1; n = 1; + if (c0 > cmax) { cmax = c0; n = 0; } + if (c2 > cmax) { n = 2; } +#else + cmax = c1; n = 1; + if (c2 > cmax) { cmax = c2; n = 2; } + if (c0 > cmax) { n = 0; } +#endif + /* Choose split point along selected axis, and update box bounds. + * Current algorithm: split at halfway point. + * (Since the box has been shrunk to minimum volume, + * any split will produce two nonempty subboxes.) + * Note that lb value is max for lower box, so must be < old max. + */ + switch (n) { + case 0: + lb = (b1->c0max + b1->c0min) / 2; + b1->c0max = lb; + b2->c0min = lb+1; + break; + case 1: + lb = (b1->c1max + b1->c1min) / 2; + b1->c1max = lb; + b2->c1min = lb+1; + break; + case 2: + lb = (b1->c2max + b1->c2min) / 2; + b1->c2max = lb; + b2->c2min = lb+1; + break; + } + /* Update stats for boxes */ + update_box(cinfo, b1); + update_box(cinfo, b2); + numboxes++; + } + return numboxes; +} + + +LOCAL(void) +compute_color (j_decompress_ptr cinfo, boxptr boxp, int icolor) +/* Compute representative color for a box, put it in colormap[icolor] */ +{ + /* Current algorithm: mean weighted by pixels (not colors) */ + /* Note it is important to get the rounding correct! */ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + hist3d histogram = cquantize->histogram; + histptr histp; + int c0,c1,c2; + int c0min,c0max,c1min,c1max,c2min,c2max; + long count; + long total = 0; + long c0total = 0; + long c1total = 0; + long c2total = 0; + + c0min = boxp->c0min; c0max = boxp->c0max; + c1min = boxp->c1min; c1max = boxp->c1max; + c2min = boxp->c2min; c2max = boxp->c2max; + + for (c0 = c0min; c0 <= c0max; c0++) + for (c1 = c1min; c1 <= c1max; c1++) { + histp = & histogram[c0][c1][c2min]; + for (c2 = c2min; c2 <= c2max; c2++) { + if ((count = *histp++) != 0) { + total += count; + c0total += ((c0 << C0_SHIFT) + ((1<<C0_SHIFT)>>1)) * count; + c1total += ((c1 << C1_SHIFT) + ((1<<C1_SHIFT)>>1)) * count; + c2total += ((c2 << C2_SHIFT) + ((1<<C2_SHIFT)>>1)) * count; + } + } + } + + cinfo->colormap[0][icolor] = (JSAMPLE) ((c0total + (total>>1)) / total); + cinfo->colormap[1][icolor] = (JSAMPLE) ((c1total + (total>>1)) / total); + cinfo->colormap[2][icolor] = (JSAMPLE) ((c2total + (total>>1)) / total); +} + + +LOCAL(void) +select_colors (j_decompress_ptr cinfo, int desired_colors) +/* Master routine for color selection */ +{ + boxptr boxlist; + int numboxes; + int i; + + /* Allocate workspace for box list */ + boxlist = (boxptr) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, desired_colors * SIZEOF(box)); + /* Initialize one box containing whole space */ + numboxes = 1; + boxlist[0].c0min = 0; + boxlist[0].c0max = MAXJSAMPLE >> C0_SHIFT; + boxlist[0].c1min = 0; + boxlist[0].c1max = MAXJSAMPLE >> C1_SHIFT; + boxlist[0].c2min = 0; + boxlist[0].c2max = MAXJSAMPLE >> C2_SHIFT; + /* Shrink it to actually-used volume and set its statistics */ + update_box(cinfo, & boxlist[0]); + /* Perform median-cut to produce final box list */ + numboxes = median_cut(cinfo, boxlist, numboxes, desired_colors); + /* Compute the representative color for each box, fill colormap */ + for (i = 0; i < numboxes; i++) + compute_color(cinfo, & boxlist[i], i); + cinfo->actual_number_of_colors = numboxes; + TRACEMS1(cinfo, 1, JTRC_QUANT_SELECTED, numboxes); +} + + +/* + * These routines are concerned with the time-critical task of mapping input + * colors to the nearest color in the selected colormap. + * + * We re-use the histogram space as an "inverse color map", essentially a + * cache for the results of nearest-color searches. All colors within a + * histogram cell will be mapped to the same colormap entry, namely the one + * closest to the cell's center. This may not be quite the closest entry to + * the actual input color, but it's almost as good. A zero in the cache + * indicates we haven't found the nearest color for that cell yet; the array + * is cleared to zeroes before starting the mapping pass. When we find the + * nearest color for a cell, its colormap index plus one is recorded in the + * cache for future use. The pass2 scanning routines call fill_inverse_cmap + * when they need to use an unfilled entry in the cache. + * + * Our method of efficiently finding nearest colors is based on the "locally + * sorted search" idea described by Heckbert and on the incremental distance + * calculation described by Spencer W. Thomas in chapter III.1 of Graphics + * Gems II (James Arvo, ed. Academic Press, 1991). Thomas points out that + * the distances from a given colormap entry to each cell of the histogram can + * be computed quickly using an incremental method: the differences between + * distances to adjacent cells themselves differ by a constant. This allows a + * fairly fast implementation of the "brute force" approach of computing the + * distance from every colormap entry to every histogram cell. Unfortunately, + * it needs a work array to hold the best-distance-so-far for each histogram + * cell (because the inner loop has to be over cells, not colormap entries). + * The work array elements have to be INT32s, so the work array would need + * 256Kb at our recommended precision. This is not feasible in DOS machines. + * + * To get around these problems, we apply Thomas' method to compute the + * nearest colors for only the cells within a small subbox of the histogram. + * The work array need be only as big as the subbox, so the memory usage + * problem is solved. Furthermore, we need not fill subboxes that are never + * referenced in pass2; many images use only part of the color gamut, so a + * fair amount of work is saved. An additional advantage of this + * approach is that we can apply Heckbert's locality criterion to quickly + * eliminate colormap entries that are far away from the subbox; typically + * three-fourths of the colormap entries are rejected by Heckbert's criterion, + * and we need not compute their distances to individual cells in the subbox. + * The speed of this approach is heavily influenced by the subbox size: too + * small means too much overhead, too big loses because Heckbert's criterion + * can't eliminate as many colormap entries. Empirically the best subbox + * size seems to be about 1/512th of the histogram (1/8th in each direction). + * + * Thomas' article also describes a refined method which is asymptotically + * faster than the brute-force method, but it is also far more complex and + * cannot efficiently be applied to small subboxes. It is therefore not + * useful for programs intended to be portable to DOS machines. On machines + * with plenty of memory, filling the whole histogram in one shot with Thomas' + * refined method might be faster than the present code --- but then again, + * it might not be any faster, and it's certainly more complicated. + */ + + +/* log2(histogram cells in update box) for each axis; this can be adjusted */ +#define BOX_C0_LOG (HIST_C0_BITS-3) +#define BOX_C1_LOG (HIST_C1_BITS-3) +#define BOX_C2_LOG (HIST_C2_BITS-3) + +#define BOX_C0_ELEMS (1<<BOX_C0_LOG) /* # of hist cells in update box */ +#define BOX_C1_ELEMS (1<<BOX_C1_LOG) +#define BOX_C2_ELEMS (1<<BOX_C2_LOG) + +#define BOX_C0_SHIFT (C0_SHIFT + BOX_C0_LOG) +#define BOX_C1_SHIFT (C1_SHIFT + BOX_C1_LOG) +#define BOX_C2_SHIFT (C2_SHIFT + BOX_C2_LOG) + + +/* + * The next three routines implement inverse colormap filling. They could + * all be folded into one big routine, but splitting them up this way saves + * some stack space (the mindist[] and bestdist[] arrays need not coexist) + * and may allow some compilers to produce better code by registerizing more + * inner-loop variables. + */ + +LOCAL(int) +find_nearby_colors (j_decompress_ptr cinfo, int minc0, int minc1, int minc2, + JSAMPLE colorlist[]) +/* Locate the colormap entries close enough to an update box to be candidates + * for the nearest entry to some cell(s) in the update box. The update box + * is specified by the center coordinates of its first cell. The number of + * candidate colormap entries is returned, and their colormap indexes are + * placed in colorlist[]. + * This routine uses Heckbert's "locally sorted search" criterion to select + * the colors that need further consideration. + */ +{ + int numcolors = cinfo->actual_number_of_colors; + int maxc0, maxc1, maxc2; + int centerc0, centerc1, centerc2; + int i, x, ncolors; + INT32 minmaxdist, min_dist, max_dist, tdist; + INT32 mindist[MAXNUMCOLORS]; /* min distance to colormap entry i */ + + /* Compute true coordinates of update box's upper corner and center. + * Actually we compute the coordinates of the center of the upper-corner + * histogram cell, which are the upper bounds of the volume we care about. + * Note that since ">>" rounds down, the "center" values may be closer to + * min than to max; hence comparisons to them must be "<=", not "<". + */ + maxc0 = minc0 + ((1 << BOX_C0_SHIFT) - (1 << C0_SHIFT)); + centerc0 = (minc0 + maxc0) >> 1; + maxc1 = minc1 + ((1 << BOX_C1_SHIFT) - (1 << C1_SHIFT)); + centerc1 = (minc1 + maxc1) >> 1; + maxc2 = minc2 + ((1 << BOX_C2_SHIFT) - (1 << C2_SHIFT)); + centerc2 = (minc2 + maxc2) >> 1; + + /* For each color in colormap, find: + * 1. its minimum squared-distance to any point in the update box + * (zero if color is within update box); + * 2. its maximum squared-distance to any point in the update box. + * Both of these can be found by considering only the corners of the box. + * We save the minimum distance for each color in mindist[]; + * only the smallest maximum distance is of interest. + */ + minmaxdist = 0x7FFFFFFFL; + + for (i = 0; i < numcolors; i++) { + /* We compute the squared-c0-distance term, then add in the other two. */ + x = GETJSAMPLE(cinfo->colormap[0][i]); + if (x < minc0) { + tdist = (x - minc0) * C0_SCALE; + min_dist = tdist*tdist; + tdist = (x - maxc0) * C0_SCALE; + max_dist = tdist*tdist; + } else if (x > maxc0) { + tdist = (x - maxc0) * C0_SCALE; + min_dist = tdist*tdist; + tdist = (x - minc0) * C0_SCALE; + max_dist = tdist*tdist; + } else { + /* within cell range so no contribution to min_dist */ + min_dist = 0; + if (x <= centerc0) { + tdist = (x - maxc0) * C0_SCALE; + max_dist = tdist*tdist; + } else { + tdist = (x - minc0) * C0_SCALE; + max_dist = tdist*tdist; + } + } + + x = GETJSAMPLE(cinfo->colormap[1][i]); + if (x < minc1) { + tdist = (x - minc1) * C1_SCALE; + min_dist += tdist*tdist; + tdist = (x - maxc1) * C1_SCALE; + max_dist += tdist*tdist; + } else if (x > maxc1) { + tdist = (x - maxc1) * C1_SCALE; + min_dist += tdist*tdist; + tdist = (x - minc1) * C1_SCALE; + max_dist += tdist*tdist; + } else { + /* within cell range so no contribution to min_dist */ + if (x <= centerc1) { + tdist = (x - maxc1) * C1_SCALE; + max_dist += tdist*tdist; + } else { + tdist = (x - minc1) * C1_SCALE; + max_dist += tdist*tdist; + } + } + + x = GETJSAMPLE(cinfo->colormap[2][i]); + if (x < minc2) { + tdist = (x - minc2) * C2_SCALE; + min_dist += tdist*tdist; + tdist = (x - maxc2) * C2_SCALE; + max_dist += tdist*tdist; + } else if (x > maxc2) { + tdist = (x - maxc2) * C2_SCALE; + min_dist += tdist*tdist; + tdist = (x - minc2) * C2_SCALE; + max_dist += tdist*tdist; + } else { + /* within cell range so no contribution to min_dist */ + if (x <= centerc2) { + tdist = (x - maxc2) * C2_SCALE; + max_dist += tdist*tdist; + } else { + tdist = (x - minc2) * C2_SCALE; + max_dist += tdist*tdist; + } + } + + mindist[i] = min_dist; /* save away the results */ + if (max_dist < minmaxdist) + minmaxdist = max_dist; + } + + /* Now we know that no cell in the update box is more than minmaxdist + * away from some colormap entry. Therefore, only colors that are + * within minmaxdist of some part of the box need be considered. + */ + ncolors = 0; + for (i = 0; i < numcolors; i++) { + if (mindist[i] <= minmaxdist) + colorlist[ncolors++] = (JSAMPLE) i; + } + return ncolors; +} + + +LOCAL(void) +find_best_colors (j_decompress_ptr cinfo, int minc0, int minc1, int minc2, + int numcolors, JSAMPLE colorlist[], JSAMPLE bestcolor[]) +/* Find the closest colormap entry for each cell in the update box, + * given the list of candidate colors prepared by find_nearby_colors. + * Return the indexes of the closest entries in the bestcolor[] array. + * This routine uses Thomas' incremental distance calculation method to + * find the distance from a colormap entry to successive cells in the box. + */ +{ + int ic0, ic1, ic2; + int i, icolor; + register INT32 * bptr; /* pointer into bestdist[] array */ + JSAMPLE * cptr; /* pointer into bestcolor[] array */ + INT32 dist0, dist1; /* initial distance values */ + register INT32 dist2; /* current distance in inner loop */ + INT32 xx0, xx1; /* distance increments */ + register INT32 xx2; + INT32 inc0, inc1, inc2; /* initial values for increments */ + /* This array holds the distance to the nearest-so-far color for each cell */ + INT32 bestdist[BOX_C0_ELEMS * BOX_C1_ELEMS * BOX_C2_ELEMS]; + + /* Initialize best-distance for each cell of the update box */ + bptr = bestdist; + for (i = BOX_C0_ELEMS*BOX_C1_ELEMS*BOX_C2_ELEMS-1; i >= 0; i--) + *bptr++ = 0x7FFFFFFFL; + + /* For each color selected by find_nearby_colors, + * compute its distance to the center of each cell in the box. + * If that's less than best-so-far, update best distance and color number. + */ + + /* Nominal steps between cell centers ("x" in Thomas article) */ +#define STEP_C0 ((1 << C0_SHIFT) * C0_SCALE) +#define STEP_C1 ((1 << C1_SHIFT) * C1_SCALE) +#define STEP_C2 ((1 << C2_SHIFT) * C2_SCALE) + + for (i = 0; i < numcolors; i++) { + icolor = GETJSAMPLE(colorlist[i]); + /* Compute (square of) distance from minc0/c1/c2 to this color */ + inc0 = (minc0 - GETJSAMPLE(cinfo->colormap[0][icolor])) * C0_SCALE; + dist0 = inc0*inc0; + inc1 = (minc1 - GETJSAMPLE(cinfo->colormap[1][icolor])) * C1_SCALE; + dist0 += inc1*inc1; + inc2 = (minc2 - GETJSAMPLE(cinfo->colormap[2][icolor])) * C2_SCALE; + dist0 += inc2*inc2; + /* Form the initial difference increments */ + inc0 = inc0 * (2 * STEP_C0) + STEP_C0 * STEP_C0; + inc1 = inc1 * (2 * STEP_C1) + STEP_C1 * STEP_C1; + inc2 = inc2 * (2 * STEP_C2) + STEP_C2 * STEP_C2; + /* Now loop over all cells in box, updating distance per Thomas method */ + bptr = bestdist; + cptr = bestcolor; + xx0 = inc0; + for (ic0 = BOX_C0_ELEMS-1; ic0 >= 0; ic0--) { + dist1 = dist0; + xx1 = inc1; + for (ic1 = BOX_C1_ELEMS-1; ic1 >= 0; ic1--) { + dist2 = dist1; + xx2 = inc2; + for (ic2 = BOX_C2_ELEMS-1; ic2 >= 0; ic2--) { + if (dist2 < *bptr) { + *bptr = dist2; + *cptr = (JSAMPLE) icolor; + } + dist2 += xx2; + xx2 += 2 * STEP_C2 * STEP_C2; + bptr++; + cptr++; + } + dist1 += xx1; + xx1 += 2 * STEP_C1 * STEP_C1; + } + dist0 += xx0; + xx0 += 2 * STEP_C0 * STEP_C0; + } + } +} + + +LOCAL(void) +fill_inverse_cmap (j_decompress_ptr cinfo, int c0, int c1, int c2) +/* Fill the inverse-colormap entries in the update box that contains */ +/* histogram cell c0/c1/c2. (Only that one cell MUST be filled, but */ +/* we can fill as many others as we wish.) */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + hist3d histogram = cquantize->histogram; + int minc0, minc1, minc2; /* lower left corner of update box */ + int ic0, ic1, ic2; + register JSAMPLE * cptr; /* pointer into bestcolor[] array */ + register histptr cachep; /* pointer into main cache array */ + /* This array lists the candidate colormap indexes. */ + JSAMPLE colorlist[MAXNUMCOLORS]; + int numcolors; /* number of candidate colors */ + /* This array holds the actually closest colormap index for each cell. */ + JSAMPLE bestcolor[BOX_C0_ELEMS * BOX_C1_ELEMS * BOX_C2_ELEMS]; + + /* Convert cell coordinates to update box ID */ + c0 >>= BOX_C0_LOG; + c1 >>= BOX_C1_LOG; + c2 >>= BOX_C2_LOG; + + /* Compute true coordinates of update box's origin corner. + * Actually we compute the coordinates of the center of the corner + * histogram cell, which are the lower bounds of the volume we care about. + */ + minc0 = (c0 << BOX_C0_SHIFT) + ((1 << C0_SHIFT) >> 1); + minc1 = (c1 << BOX_C1_SHIFT) + ((1 << C1_SHIFT) >> 1); + minc2 = (c2 << BOX_C2_SHIFT) + ((1 << C2_SHIFT) >> 1); + + /* Determine which colormap entries are close enough to be candidates + * for the nearest entry to some cell in the update box. + */ + numcolors = find_nearby_colors(cinfo, minc0, minc1, minc2, colorlist); + + /* Determine the actually nearest colors. */ + find_best_colors(cinfo, minc0, minc1, minc2, numcolors, colorlist, + bestcolor); + + /* Save the best color numbers (plus 1) in the main cache array */ + c0 <<= BOX_C0_LOG; /* convert ID back to base cell indexes */ + c1 <<= BOX_C1_LOG; + c2 <<= BOX_C2_LOG; + cptr = bestcolor; + for (ic0 = 0; ic0 < BOX_C0_ELEMS; ic0++) { + for (ic1 = 0; ic1 < BOX_C1_ELEMS; ic1++) { + cachep = & histogram[c0+ic0][c1+ic1][c2]; + for (ic2 = 0; ic2 < BOX_C2_ELEMS; ic2++) { + *cachep++ = (histcell) (GETJSAMPLE(*cptr++) + 1); + } + } + } +} + + +/* + * Map some rows of pixels to the output colormapped representation. + */ + +METHODDEF(void) +pass2_no_dither (j_decompress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPARRAY output_buf, int num_rows) +/* This version performs no dithering */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + hist3d histogram = cquantize->histogram; + register JSAMPROW inptr, outptr; + register histptr cachep; + register int c0, c1, c2; + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + + for (row = 0; row < num_rows; row++) { + inptr = input_buf[row]; + outptr = output_buf[row]; + for (col = width; col > 0; col--) { + /* get pixel value and index into the cache */ + c0 = GETJSAMPLE(*inptr++) >> C0_SHIFT; + c1 = GETJSAMPLE(*inptr++) >> C1_SHIFT; + c2 = GETJSAMPLE(*inptr++) >> C2_SHIFT; + cachep = & histogram[c0][c1][c2]; + /* If we have not seen this color before, find nearest colormap entry */ + /* and update the cache */ + if (*cachep == 0) + fill_inverse_cmap(cinfo, c0,c1,c2); + /* Now emit the colormap index for this cell */ + *outptr++ = (JSAMPLE) (*cachep - 1); + } + } +} + + +METHODDEF(void) +pass2_fs_dither (j_decompress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPARRAY output_buf, int num_rows) +/* This version performs Floyd-Steinberg dithering */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + hist3d histogram = cquantize->histogram; + register LOCFSERROR cur0, cur1, cur2; /* current error or pixel value */ + LOCFSERROR belowerr0, belowerr1, belowerr2; /* error for pixel below cur */ + LOCFSERROR bpreverr0, bpreverr1, bpreverr2; /* error for below/prev col */ + register FSERRPTR errorptr; /* => fserrors[] at column before current */ + JSAMPROW inptr; /* => current input pixel */ + JSAMPROW outptr; /* => current output pixel */ + histptr cachep; + int dir; /* +1 or -1 depending on direction */ + int dir3; /* 3*dir, for advancing inptr & errorptr */ + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + JSAMPLE *range_limit = cinfo->sample_range_limit; + int *error_limit = cquantize->error_limiter; + JSAMPROW colormap0 = cinfo->colormap[0]; + JSAMPROW colormap1 = cinfo->colormap[1]; + JSAMPROW colormap2 = cinfo->colormap[2]; + SHIFT_TEMPS + + for (row = 0; row < num_rows; row++) { + inptr = input_buf[row]; + outptr = output_buf[row]; + if (cquantize->on_odd_row) { + /* work right to left in this row */ + inptr += (width-1) * 3; /* so point to rightmost pixel */ + outptr += width-1; + dir = -1; + dir3 = -3; + errorptr = cquantize->fserrors + (width+1)*3; /* => entry after last column */ + cquantize->on_odd_row = FALSE; /* flip for next time */ + } else { + /* work left to right in this row */ + dir = 1; + dir3 = 3; + errorptr = cquantize->fserrors; /* => entry before first real column */ + cquantize->on_odd_row = TRUE; /* flip for next time */ + } + /* Preset error values: no error propagated to first pixel from left */ + cur0 = cur1 = cur2 = 0; + /* and no error propagated to row below yet */ + belowerr0 = belowerr1 = belowerr2 = 0; + bpreverr0 = bpreverr1 = bpreverr2 = 0; + + for (col = width; col > 0; col--) { + /* curN holds the error propagated from the previous pixel on the + * current line. Add the error propagated from the previous line + * to form the complete error correction term for this pixel, and + * round the error term (which is expressed * 16) to an integer. + * RIGHT_SHIFT rounds towards minus infinity, so adding 8 is correct + * for either sign of the error value. + * Note: errorptr points to *previous* column's array entry. + */ + cur0 = RIGHT_SHIFT(cur0 + errorptr[dir3+0] + 8, 4); + cur1 = RIGHT_SHIFT(cur1 + errorptr[dir3+1] + 8, 4); + cur2 = RIGHT_SHIFT(cur2 + errorptr[dir3+2] + 8, 4); + /* Limit the error using transfer function set by init_error_limit. + * See comments with init_error_limit for rationale. + */ + cur0 = error_limit[cur0]; + cur1 = error_limit[cur1]; + cur2 = error_limit[cur2]; + /* Form pixel value + error, and range-limit to 0..MAXJSAMPLE. + * The maximum error is +- MAXJSAMPLE (or less with error limiting); + * this sets the required size of the range_limit array. + */ + cur0 += GETJSAMPLE(inptr[0]); + cur1 += GETJSAMPLE(inptr[1]); + cur2 += GETJSAMPLE(inptr[2]); + cur0 = GETJSAMPLE(range_limit[cur0]); + cur1 = GETJSAMPLE(range_limit[cur1]); + cur2 = GETJSAMPLE(range_limit[cur2]); + /* Index into the cache with adjusted pixel value */ + cachep = & histogram[cur0>>C0_SHIFT][cur1>>C1_SHIFT][cur2>>C2_SHIFT]; + /* If we have not seen this color before, find nearest colormap */ + /* entry and update the cache */ + if (*cachep == 0) + fill_inverse_cmap(cinfo, cur0>>C0_SHIFT,cur1>>C1_SHIFT,cur2>>C2_SHIFT); + /* Now emit the colormap index for this cell */ + { register int pixcode = *cachep - 1; + *outptr = (JSAMPLE) pixcode; + /* Compute representation error for this pixel */ + cur0 -= GETJSAMPLE(colormap0[pixcode]); + cur1 -= GETJSAMPLE(colormap1[pixcode]); + cur2 -= GETJSAMPLE(colormap2[pixcode]); + } + /* Compute error fractions to be propagated to adjacent pixels. + * Add these into the running sums, and simultaneously shift the + * next-line error sums left by 1 column. + */ + { register LOCFSERROR bnexterr, delta; + + bnexterr = cur0; /* Process component 0 */ + delta = cur0 * 2; + cur0 += delta; /* form error * 3 */ + errorptr[0] = (FSERROR) (bpreverr0 + cur0); + cur0 += delta; /* form error * 5 */ + bpreverr0 = belowerr0 + cur0; + belowerr0 = bnexterr; + cur0 += delta; /* form error * 7 */ + bnexterr = cur1; /* Process component 1 */ + delta = cur1 * 2; + cur1 += delta; /* form error * 3 */ + errorptr[1] = (FSERROR) (bpreverr1 + cur1); + cur1 += delta; /* form error * 5 */ + bpreverr1 = belowerr1 + cur1; + belowerr1 = bnexterr; + cur1 += delta; /* form error * 7 */ + bnexterr = cur2; /* Process component 2 */ + delta = cur2 * 2; + cur2 += delta; /* form error * 3 */ + errorptr[2] = (FSERROR) (bpreverr2 + cur2); + cur2 += delta; /* form error * 5 */ + bpreverr2 = belowerr2 + cur2; + belowerr2 = bnexterr; + cur2 += delta; /* form error * 7 */ + } + /* At this point curN contains the 7/16 error value to be propagated + * to the next pixel on the current line, and all the errors for the + * next line have been shifted over. We are therefore ready to move on. + */ + inptr += dir3; /* Advance pixel pointers to next column */ + outptr += dir; + errorptr += dir3; /* advance errorptr to current column */ + } + /* Post-loop cleanup: we must unload the final error values into the + * final fserrors[] entry. Note we need not unload belowerrN because + * it is for the dummy column before or after the actual array. + */ + errorptr[0] = (FSERROR) bpreverr0; /* unload prev errs into array */ + errorptr[1] = (FSERROR) bpreverr1; + errorptr[2] = (FSERROR) bpreverr2; + } +} + + +/* + * Initialize the error-limiting transfer function (lookup table). + * The raw F-S error computation can potentially compute error values of up to + * +- MAXJSAMPLE. But we want the maximum correction applied to a pixel to be + * much less, otherwise obviously wrong pixels will be created. (Typical + * effects include weird fringes at color-area boundaries, isolated bright + * pixels in a dark area, etc.) The standard advice for avoiding this problem + * is to ensure that the "corners" of the color cube are allocated as output + * colors; then repeated errors in the same direction cannot cause cascading + * error buildup. However, that only prevents the error from getting + * completely out of hand; Aaron Giles reports that error limiting improves + * the results even with corner colors allocated. + * A simple clamping of the error values to about +- MAXJSAMPLE/8 works pretty + * well, but the smoother transfer function used below is even better. Thanks + * to Aaron Giles for this idea. + */ + +LOCAL(void) +init_error_limit (j_decompress_ptr cinfo) +/* Allocate and fill in the error_limiter table */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + int * table; + int in, out; + + table = (int *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, (MAXJSAMPLE*2+1) * SIZEOF(int)); + table += MAXJSAMPLE; /* so can index -MAXJSAMPLE .. +MAXJSAMPLE */ + cquantize->error_limiter = table; + +#define STEPSIZE ((MAXJSAMPLE+1)/16) + /* Map errors 1:1 up to +- MAXJSAMPLE/16 */ + out = 0; + for (in = 0; in < STEPSIZE; in++, out++) { + table[in] = out; table[-in] = -out; + } + /* Map errors 1:2 up to +- 3*MAXJSAMPLE/16 */ + for (; in < STEPSIZE*3; in++, out += (in&1) ? 0 : 1) { + table[in] = out; table[-in] = -out; + } + /* Clamp the rest to final out value (which is (MAXJSAMPLE+1)/8) */ + for (; in <= MAXJSAMPLE; in++) { + table[in] = out; table[-in] = -out; + } +#undef STEPSIZE +} + + +/* + * Finish up at the end of each pass. + */ + +METHODDEF(void) +finish_pass1 (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + + /* Select the representative colors and fill in cinfo->colormap */ + cinfo->colormap = cquantize->sv_colormap; + select_colors(cinfo, cquantize->desired); + /* Force next pass to zero the color index table */ + cquantize->needs_zeroed = TRUE; +} + + +METHODDEF(void) +finish_pass2 (j_decompress_ptr cinfo) +{ + (void)cinfo; + /* no work */ +} + + +/* + * Initialize for each processing pass. + */ + +METHODDEF(void) +start_pass_2_quant (j_decompress_ptr cinfo, boolean is_pre_scan) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + hist3d histogram = cquantize->histogram; + int i; + + /* Only F-S dithering or no dithering is supported. */ + /* If user asks for ordered dither, give him F-S. */ + if (cinfo->dither_mode != JDITHER_NONE) + cinfo->dither_mode = JDITHER_FS; + + if (is_pre_scan) { + /* Set up method pointers */ + cquantize->pub.color_quantize = prescan_quantize; + cquantize->pub.finish_pass = finish_pass1; + cquantize->needs_zeroed = TRUE; /* Always zero histogram */ + } else { + /* Set up method pointers */ + if (cinfo->dither_mode == JDITHER_FS) + cquantize->pub.color_quantize = pass2_fs_dither; + else + cquantize->pub.color_quantize = pass2_no_dither; + cquantize->pub.finish_pass = finish_pass2; + + /* Make sure color count is acceptable */ + i = cinfo->actual_number_of_colors; + if (i < 1) + ERREXIT1(cinfo, JERR_QUANT_FEW_COLORS, 1); + if (i > MAXNUMCOLORS) + ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, MAXNUMCOLORS); + + if (cinfo->dither_mode == JDITHER_FS) { + size_t arraysize = (size_t) ((cinfo->output_width + 2) * + (3 * SIZEOF(FSERROR))); + /* Allocate Floyd-Steinberg workspace if we didn't already. */ + if (cquantize->fserrors == NULL) + cquantize->fserrors = (FSERRPTR) (*cinfo->mem->alloc_large) + ((j_common_ptr) cinfo, JPOOL_IMAGE, arraysize); + /* Initialize the propagated errors to zero. */ + jzero_far((void FAR *) cquantize->fserrors, arraysize); + /* Make the error-limit table if we didn't already. */ + if (cquantize->error_limiter == NULL) + init_error_limit(cinfo); + cquantize->on_odd_row = FALSE; + } + + } + /* Zero the histogram or inverse color map, if necessary */ + if (cquantize->needs_zeroed) { + for (i = 0; i < HIST_C0_ELEMS; i++) { + jzero_far((void FAR *) histogram[i], + HIST_C1_ELEMS*HIST_C2_ELEMS * SIZEOF(histcell)); + } + cquantize->needs_zeroed = FALSE; + } +} + + +/* + * Switch to a new external colormap between output passes. + */ + +METHODDEF(void) +new_color_map_2_quant (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + + /* Reset the inverse color map */ + cquantize->needs_zeroed = TRUE; +} + + +/* + * Module initialization routine for 2-pass color quantization. + */ + +GLOBAL(void) +jinit_2pass_quantizer (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize; + int i; + + cquantize = (my_cquantize_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_cquantizer)); + cinfo->cquantize = (struct jpeg_color_quantizer *) cquantize; + cquantize->pub.start_pass = start_pass_2_quant; + cquantize->pub.new_color_map = new_color_map_2_quant; + cquantize->fserrors = NULL; /* flag optional arrays not allocated */ + cquantize->error_limiter = NULL; + + /* Make sure jdmaster didn't give me a case I can't handle */ + if (cinfo->out_color_components != 3) + ERREXIT(cinfo, JERR_NOTIMPL); + + /* Allocate the histogram/inverse colormap storage */ + cquantize->histogram = (hist3d) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, HIST_C0_ELEMS * SIZEOF(hist2d)); + for (i = 0; i < HIST_C0_ELEMS; i++) { + cquantize->histogram[i] = (hist2d) (*cinfo->mem->alloc_large) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + HIST_C1_ELEMS*HIST_C2_ELEMS * SIZEOF(histcell)); + } + cquantize->needs_zeroed = TRUE; /* histogram is garbage now */ + + /* Allocate storage for the completed colormap, if required. + * We do this now since it is FAR storage and may affect + * the memory manager's space calculations. + */ + if (cinfo->enable_2pass_quant) { + /* Make sure color count is acceptable */ + int desired = cinfo->desired_number_of_colors; + /* Lower bound on # of colors ... somewhat arbitrary as long as > 0 */ + if (desired < 8) + ERREXIT1(cinfo, JERR_QUANT_FEW_COLORS, 8); + /* Make sure colormap indexes can be represented by JSAMPLEs */ + if (desired > MAXNUMCOLORS) + ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, MAXNUMCOLORS); + cquantize->sv_colormap = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo,JPOOL_IMAGE, (JDIMENSION) desired, (JDIMENSION) 3); + cquantize->desired = desired; + } else + cquantize->sv_colormap = NULL; + + /* Only F-S dithering or no dithering is supported. */ + /* If user asks for ordered dither, give him F-S. */ + if (cinfo->dither_mode != JDITHER_NONE) + cinfo->dither_mode = JDITHER_FS; + + /* Allocate Floyd-Steinberg workspace if necessary. + * This isn't really needed until pass 2, but again it is FAR storage. + * Although we will cope with a later change in dither_mode, + * we do not promise to honor max_memory_to_use if dither_mode changes. + */ + if (cinfo->dither_mode == JDITHER_FS) { + cquantize->fserrors = (FSERRPTR) (*cinfo->mem->alloc_large) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (size_t) ((cinfo->output_width + 2) * (3 * SIZEOF(FSERROR)))); + /* Might as well create the error-limiting table too. */ + init_error_limit(cinfo); + } +} + +#endif /* QUANT_2PASS_SUPPORTED */ diff --git a/Utilities/ITK/Utilities/itkjpeg/jutils.c b/Utilities/ITK/Utilities/itkjpeg/jutils.c new file mode 100644 index 0000000000000000000000000000000000000000..23abeb881f8a1cdc7474d2e53c6add73250ab8d3 --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jutils.c @@ -0,0 +1,179 @@ +/* + * jutils.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains tables and miscellaneous utility routines needed + * for both compression and decompression. + * Note we prefix all global names with "j" to minimize conflicts with + * a surrounding application. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* + * jpeg_zigzag_order[i] is the zigzag-order position of the i'th element + * of a DCT block read in natural order (left to right, top to bottom). + */ + +#if 0 /* This table is not actually needed in v6a */ + +const int jpeg_zigzag_order[DCTSIZE2] = { + 0, 1, 5, 6, 14, 15, 27, 28, + 2, 4, 7, 13, 16, 26, 29, 42, + 3, 8, 12, 17, 25, 30, 41, 43, + 9, 11, 18, 24, 31, 40, 44, 53, + 10, 19, 23, 32, 39, 45, 52, 54, + 20, 22, 33, 38, 46, 51, 55, 60, + 21, 34, 37, 47, 50, 56, 59, 61, + 35, 36, 48, 49, 57, 58, 62, 63 +}; + +#endif + +/* + * jpeg_natural_order[i] is the natural-order position of the i'th element + * of zigzag order. + * + * When reading corrupted data, the Huffman decoders could attempt + * to reference an entry beyond the end of this array (if the decoded + * zero run length reaches past the end of the block). To prevent + * wild stores without adding an inner-loop test, we put some extra + * "63"s after the real entries. This will cause the extra coefficient + * to be stored in location 63 of the block, not somewhere random. + * The worst case would be a run-length of 15, which means we need 16 + * fake entries. + */ + +const int jpeg_natural_order[DCTSIZE2+16] = { + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63, + 63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */ + 63, 63, 63, 63, 63, 63, 63, 63 +}; + + +/* + * Arithmetic utilities + */ + +GLOBAL(long) +jdiv_round_up (long a, long b) +/* Compute a/b rounded up to next integer, ie, ceil(a/b) */ +/* Assumes a >= 0, b > 0 */ +{ + return (a + b - 1L) / b; +} + + +GLOBAL(long) +jround_up (long a, long b) +/* Compute a rounded up to next multiple of b, ie, ceil(a/b)*b */ +/* Assumes a >= 0, b > 0 */ +{ + a += b - 1L; + return a - (a % b); +} + + +/* On normal machines we can apply MEMCOPY() and MEMZERO() to sample arrays + * and coefficient-block arrays. This won't work on 80x86 because the arrays + * are FAR and we're assuming a small-pointer memory model. However, some + * DOS compilers provide far-pointer versions of memcpy() and memset() even + * in the small-model libraries. These will be used if USE_FMEM is defined. + * Otherwise, the routines below do it the hard way. (The performance cost + * is not all that great, because these routines aren't very heavily used.) + */ + +#ifndef NEED_FAR_POINTERS /* normal case, same as regular macros */ +#define FMEMCOPY(dest,src,size) MEMCOPY(dest,src,size) +#define FMEMZERO(target,size) MEMZERO(target,size) +#else /* 80x86 case, define if we can */ +#ifdef USE_FMEM +#define FMEMCOPY(dest,src,size) _fmemcpy((void FAR *)(dest), (const void FAR *)(src), (size_t)(size)) +#define FMEMZERO(target,size) _fmemset((void FAR *)(target), 0, (size_t)(size)) +#endif +#endif + + +GLOBAL(void) +jcopy_sample_rows (JSAMPARRAY input_array, int source_row, + JSAMPARRAY output_array, int dest_row, + int num_rows, JDIMENSION num_cols) +/* Copy some rows of samples from one place to another. + * num_rows rows are copied from input_array[source_row++] + * to output_array[dest_row++]; these areas may overlap for duplication. + * The source and destination arrays must be at least as wide as num_cols. + */ +{ + register JSAMPROW inptr, outptr; +#ifdef FMEMCOPY + register size_t count = (size_t) (num_cols * SIZEOF(JSAMPLE)); +#else + register JDIMENSION count; +#endif + register int row; + + input_array += source_row; + output_array += dest_row; + + for (row = num_rows; row > 0; row--) { + inptr = *input_array++; + outptr = *output_array++; +#ifdef FMEMCOPY + FMEMCOPY(outptr, inptr, count); +#else + for (count = num_cols; count > 0; count--) + *outptr++ = *inptr++; /* needn't bother with GETJSAMPLE() here */ +#endif + } +} + + +GLOBAL(void) +jcopy_block_row (JBLOCKROW input_row, JBLOCKROW output_row, + JDIMENSION num_blocks) +/* Copy a row of coefficient blocks from one place to another. */ +{ +#ifdef FMEMCOPY + FMEMCOPY(output_row, input_row, num_blocks * (DCTSIZE2 * SIZEOF(JCOEF))); +#else + register JCOEFPTR inptr, outptr; + register long count; + + inptr = (JCOEFPTR) input_row; + outptr = (JCOEFPTR) output_row; + for (count = (long) num_blocks * DCTSIZE2; count > 0; count--) { + *outptr++ = *inptr++; + } +#endif +} + + +GLOBAL(void) +jzero_far (void FAR * target, size_t bytestozero) +/* Zero out a chunk of FAR memory. */ +/* This might be sample-array data, block-array data, or alloc_large data. */ +{ +#ifdef FMEMZERO + FMEMZERO(target, bytestozero); +#else + register char FAR * ptr = (char FAR *) target; + register size_t count; + + for (count = bytestozero; count > 0; count--) { + *ptr++ = 0; + } +#endif +} diff --git a/Utilities/ITK/Utilities/itkjpeg/jversion.h b/Utilities/ITK/Utilities/itkjpeg/jversion.h new file mode 100644 index 0000000000000000000000000000000000000000..95d81303031a23a9c4a99b7bdb1005e3d3ff175b --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/jversion.h @@ -0,0 +1,14 @@ +/* + * jversion.h + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains software version identification. + */ + + +#define JVERSION "6b 27-Mar-1998" + +#define JCOPYRIGHT "Copyright (C) 1998, Thomas G. Lane" diff --git a/Utilities/ITK/Utilities/itkjpeg/libjpeg.doc b/Utilities/ITK/Utilities/itkjpeg/libjpeg.doc new file mode 100644 index 0000000000000000000000000000000000000000..20ce7b48192ca3d118cc7053d4f8a0ad9b42fd4f --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/libjpeg.doc @@ -0,0 +1,3011 @@ +USING THE IJG JPEG LIBRARY + +Copyright (C) 1994-1998, Thomas G. Lane. +This file is part of the Independent JPEG Group's software. +For conditions of distribution and use, see the accompanying README file. + + +This file describes how to use the IJG JPEG library within an application +program. Read it if you want to write a program that uses the library. + +The file example.c provides heavily commented skeleton code for calling the +JPEG library. Also see jpeglib.h (the include file to be used by application +programs) for full details about data structures and function parameter lists. +The library source code, of course, is the ultimate reference. + +Note that there have been *major* changes from the application interface +presented by IJG version 4 and earlier versions. The old design had several +inherent limitations, and it had accumulated a lot of cruft as we added +features while trying to minimize application-interface changes. We have +sacrificed backward compatibility in the version 5 rewrite, but we think the +improvements justify this. + + +TABLE OF CONTENTS +----------------- + +Overview: + Functions provided by the library + Outline of typical usage +Basic library usage: + Data formats + Compression details + Decompression details + Mechanics of usage: include files, linking, etc +Advanced features: + Compression parameter selection + Decompression parameter selection + Special color spaces + Error handling + Compressed data handling (source and destination managers) + I/O suspension + Progressive JPEG support + Buffered-image mode + Abbreviated datastreams and multiple images + Special markers + Raw (downsampled) image data + Really raw data: DCT coefficients + Progress monitoring + Memory management + Memory usage + Library compile-time options + Portability considerations + Notes for MS-DOS implementors + +You should read at least the overview and basic usage sections before trying +to program with the library. The sections on advanced features can be read +if and when you need them. + + +OVERVIEW +======== + +Functions provided by the library +--------------------------------- + +The IJG JPEG library provides C code to read and write JPEG-compressed image +files. The surrounding application program receives or supplies image data a +scanline at a time, using a straightforward uncompressed image format. All +details of color conversion and other preprocessing/postprocessing can be +handled by the library. + +The library includes a substantial amount of code that is not covered by the +JPEG standard but is necessary for typical applications of JPEG. These +functions preprocess the image before JPEG compression or postprocess it after +decompression. They include colorspace conversion, downsampling/upsampling, +and color quantization. The application indirectly selects use of this code +by specifying the format in which it wishes to supply or receive image data. +For example, if colormapped output is requested, then the decompression +library automatically invokes color quantization. + +A wide range of quality vs. speed tradeoffs are possible in JPEG processing, +and even more so in decompression postprocessing. The decompression library +provides multiple implementations that cover most of the useful tradeoffs, +ranging from very-high-quality down to fast-preview operation. On the +compression side we have generally not provided low-quality choices, since +compression is normally less time-critical. It should be understood that the +low-quality modes may not meet the JPEG standard's accuracy requirements; +nonetheless, they are useful for viewers. + +A word about functions *not* provided by the library. We handle a subset of +the ISO JPEG standard; most baseline, extended-sequential, and progressive +JPEG processes are supported. (Our subset includes all features now in common +use.) Unsupported ISO options include: + * Hierarchical storage + * Arithmetic entropy coding (unsupported for legal reasons) + * DNL marker + * Nonintegral subsampling ratios +We support both 8- and 12-bit data precision, but this is a compile-time +choice rather than a run-time choice; hence it is difficult to use both +precisions in a single application. + +By itself, the library handles only interchange JPEG datastreams --- in +particular the widely used JFIF file format. The library can be used by +surrounding code to process interchange or abbreviated JPEG datastreams that +are embedded in more complex file formats. (For example, this library is +used by the free LIBTIFF library to support JPEG compression in TIFF.) + + +Outline of typical usage +------------------------ + +The rough outline of a JPEG compression operation is: + + Allocate and initialize a JPEG compression object + Specify the destination for the compressed data (eg, a file) + Set parameters for compression, including image size & colorspace + jpeg_start_compress(...); + while (scan lines remain to be written) + jpeg_write_scanlines(...); + jpeg_finish_compress(...); + Release the JPEG compression object + +A JPEG compression object holds parameters and working state for the JPEG +library. We make creation/destruction of the object separate from starting +or finishing compression of an image; the same object can be re-used for a +series of image compression operations. This makes it easy to re-use the +same parameter settings for a sequence of images. Re-use of a JPEG object +also has important implications for processing abbreviated JPEG datastreams, +as discussed later. + +The image data to be compressed is supplied to jpeg_write_scanlines() from +in-memory buffers. If the application is doing file-to-file compression, +reading image data from the source file is the application's responsibility. +The library emits compressed data by calling a "data destination manager", +which typically will write the data into a file; but the application can +provide its own destination manager to do something else. + +Similarly, the rough outline of a JPEG decompression operation is: + + Allocate and initialize a JPEG decompression object + Specify the source of the compressed data (eg, a file) + Call jpeg_read_header() to obtain image info + Set parameters for decompression + jpeg_start_decompress(...); + while (scan lines remain to be read) + jpeg_read_scanlines(...); + jpeg_finish_decompress(...); + Release the JPEG decompression object + +This is comparable to the compression outline except that reading the +datastream header is a separate step. This is helpful because information +about the image's size, colorspace, etc is available when the application +selects decompression parameters. For example, the application can choose an +output scaling ratio that will fit the image into the available screen size. + +The decompression library obtains compressed data by calling a data source +manager, which typically will read the data from a file; but other behaviors +can be obtained with a custom source manager. Decompressed data is delivered +into in-memory buffers passed to jpeg_read_scanlines(). + +It is possible to abort an incomplete compression or decompression operation +by calling jpeg_abort(); or, if you do not need to retain the JPEG object, +simply release it by calling jpeg_destroy(). + +JPEG compression and decompression objects are two separate struct types. +However, they share some common fields, and certain routines such as +jpeg_destroy() can work on either type of object. + +The JPEG library has no static variables: all state is in the compression +or decompression object. Therefore it is possible to process multiple +compression and decompression operations concurrently, using multiple JPEG +objects. + +Both compression and decompression can be done in an incremental memory-to- +memory fashion, if suitable source/destination managers are used. See the +section on "I/O suspension" for more details. + + +BASIC LIBRARY USAGE +=================== + +Data formats +------------ + +Before diving into procedural details, it is helpful to understand the +image data format that the JPEG library expects or returns. + +The standard input image format is a rectangular array of pixels, with each +pixel having the same number of "component" or "sample" values (color +channels). You must specify how many components there are and the colorspace +interpretation of the components. Most applications will use RGB data +(three components per pixel) or grayscale data (one component per pixel). +PLEASE NOTE THAT RGB DATA IS THREE SAMPLES PER PIXEL, GRAYSCALE ONLY ONE. +A remarkable number of people manage to miss this, only to find that their +programs don't work with grayscale JPEG files. + +There is no provision for colormapped input. JPEG files are always full-color +or full grayscale (or sometimes another colorspace such as CMYK). You can +feed in a colormapped image by expanding it to full-color format. However +JPEG often doesn't work very well with source data that has been colormapped, +because of dithering noise. This is discussed in more detail in the JPEG FAQ +and the other references mentioned in the README file. + +Pixels are stored by scanlines, with each scanline running from left to +right. The component values for each pixel are adjacent in the row; for +example, R,G,B,R,G,B,R,G,B,... for 24-bit RGB color. Each scanline is an +array of data type JSAMPLE --- which is typically "unsigned char", unless +you've changed jmorecfg.h. (You can also change the RGB pixel layout, say +to B,G,R order, by modifying jmorecfg.h. But see the restrictions listed in +that file before doing so.) + +A 2-D array of pixels is formed by making a list of pointers to the starts of +scanlines; so the scanlines need not be physically adjacent in memory. Even +if you process just one scanline at a time, you must make a one-element +pointer array to conform to this structure. Pointers to JSAMPLE rows are of +type JSAMPROW, and the pointer to the pointer array is of type JSAMPARRAY. + +The library accepts or supplies one or more complete scanlines per call. +It is not possible to process part of a row at a time. Scanlines are always +processed top-to-bottom. You can process an entire image in one call if you +have it all in memory, but usually it's simplest to process one scanline at +a time. + +For best results, source data values should have the precision specified by +BITS_IN_JSAMPLE (normally 8 bits). For instance, if you choose to compress +data that's only 6 bits/channel, you should left-justify each value in a +byte before passing it to the compressor. If you need to compress data +that has more than 8 bits/channel, compile with BITS_IN_JSAMPLE = 12. +(See "Library compile-time options", later.) + + +The data format returned by the decompressor is the same in all details, +except that colormapped output is supported. (Again, a JPEG file is never +colormapped. But you can ask the decompressor to perform on-the-fly color +quantization to deliver colormapped output.) If you request colormapped +output then the returned data array contains a single JSAMPLE per pixel; +its value is an index into a color map. The color map is represented as +a 2-D JSAMPARRAY in which each row holds the values of one color component, +that is, colormap[i][j] is the value of the i'th color component for pixel +value (map index) j. Note that since the colormap indexes are stored in +JSAMPLEs, the maximum number of colors is limited by the size of JSAMPLE +(ie, at most 256 colors for an 8-bit JPEG library). + + +Compression details +------------------- + +Here we revisit the JPEG compression outline given in the overview. + +1. Allocate and initialize a JPEG compression object. + +A JPEG compression object is a "struct jpeg_compress_struct". (It also has +a bunch of subsidiary structures which are allocated via malloc(), but the +application doesn't control those directly.) This struct can be just a local +variable in the calling routine, if a single routine is going to execute the +whole JPEG compression sequence. Otherwise it can be static or allocated +from malloc(). + +You will also need a structure representing a JPEG error handler. The part +of this that the library cares about is a "struct jpeg_error_mgr". If you +are providing your own error handler, you'll typically want to embed the +jpeg_error_mgr struct in a larger structure; this is discussed later under +"Error handling". For now we'll assume you are just using the default error +handler. The default error handler will print JPEG error/warning messages +on stderr, and it will call exit() if a fatal error occurs. + +You must initialize the error handler structure, store a pointer to it into +the JPEG object's "err" field, and then call jpeg_create_compress() to +initialize the rest of the JPEG object. + +Typical code for this step, if you are using the default error handler, is + + struct jpeg_compress_struct cinfo; + struct jpeg_error_mgr jerr; + ... + cinfo.err = jpeg_std_error(&jerr); + jpeg_create_compress(&cinfo); + +jpeg_create_compress allocates a small amount of memory, so it could fail +if you are out of memory. In that case it will exit via the error handler; +that's why the error handler must be initialized first. + + +2. Specify the destination for the compressed data (eg, a file). + +As previously mentioned, the JPEG library delivers compressed data to a +"data destination" module. The library includes one data destination +module which knows how to write to a stdio stream. You can use your own +destination module if you want to do something else, as discussed later. + +If you use the standard destination module, you must open the target stdio +stream beforehand. Typical code for this step looks like: + + FILE * outfile; + ... + if ((outfile = fopen(filename, "wb")) == NULL) { + fprintf(stderr, "can't open %s\n", filename); + exit(1); + } + jpeg_stdio_dest(&cinfo, outfile); + +where the last line invokes the standard destination module. + +WARNING: it is critical that the binary compressed data be delivered to the +output file unchanged. On non-Unix systems the stdio library may perform +newline translation or otherwise corrupt binary data. To suppress this +behavior, you may need to use a "b" option to fopen (as shown above), or use +setmode() or another routine to put the stdio stream in binary mode. See +cjpeg.c and djpeg.c for code that has been found to work on many systems. + +You can select the data destination after setting other parameters (step 3), +if that's more convenient. You may not change the destination between +calling jpeg_start_compress() and jpeg_finish_compress(). + + +3. Set parameters for compression, including image size & colorspace. + +You must supply information about the source image by setting the following +fields in the JPEG object (cinfo structure): + + image_width Width of image, in pixels + image_height Height of image, in pixels + input_components Number of color channels (samples per pixel) + in_color_space Color space of source image + +The image dimensions are, hopefully, obvious. JPEG supports image dimensions +of 1 to 64K pixels in either direction. The input color space is typically +RGB or grayscale, and input_components is 3 or 1 accordingly. (See "Special +color spaces", later, for more info.) The in_color_space field must be +assigned one of the J_COLOR_SPACE enum constants, typically JCS_RGB or +JCS_GRAYSCALE. + +JPEG has a large number of compression parameters that determine how the +image is encoded. Most applications don't need or want to know about all +these parameters. You can set all the parameters to reasonable defaults by +calling jpeg_set_defaults(); then, if there are particular values you want +to change, you can do so after that. The "Compression parameter selection" +section tells about all the parameters. + +You must set in_color_space correctly before calling jpeg_set_defaults(), +because the defaults depend on the source image colorspace. However the +other three source image parameters need not be valid until you call +jpeg_start_compress(). There's no harm in calling jpeg_set_defaults() more +than once, if that happens to be convenient. + +Typical code for a 24-bit RGB source image is + + cinfo.image_width = Width; /* image width and height, in pixels */ + cinfo.image_height = Height; + cinfo.input_components = 3; /* # of color components per pixel */ + cinfo.in_color_space = JCS_RGB; /* colorspace of input image */ + + jpeg_set_defaults(&cinfo); + /* Make optional parameter settings here */ + + +4. jpeg_start_compress(...); + +After you have established the data destination and set all the necessary +source image info and other parameters, call jpeg_start_compress() to begin +a compression cycle. This will initialize internal state, allocate working +storage, and emit the first few bytes of the JPEG datastream header. + +Typical code: + + jpeg_start_compress(&cinfo, TRUE); + +The "TRUE" parameter ensures that a complete JPEG interchange datastream +will be written. This is appropriate in most cases. If you think you might +want to use an abbreviated datastream, read the section on abbreviated +datastreams, below. + +Once you have called jpeg_start_compress(), you may not alter any JPEG +parameters or other fields of the JPEG object until you have completed +the compression cycle. + + +5. while (scan lines remain to be written) + jpeg_write_scanlines(...); + +Now write all the required image data by calling jpeg_write_scanlines() +one or more times. You can pass one or more scanlines in each call, up +to the total image height. In most applications it is convenient to pass +just one or a few scanlines at a time. The expected format for the passed +data is discussed under "Data formats", above. + +Image data should be written in top-to-bottom scanline order. The JPEG spec +contains some weasel wording about how top and bottom are application-defined +terms (a curious interpretation of the English language...) but if you want +your files to be compatible with everyone else's, you WILL use top-to-bottom +order. If the source data must be read in bottom-to-top order, you can use +the JPEG library's virtual array mechanism to invert the data efficiently. +Examples of this can be found in the sample application cjpeg. + +The library maintains a count of the number of scanlines written so far +in the next_scanline field of the JPEG object. Usually you can just use +this variable as the loop counter, so that the loop test looks like +"while (cinfo.next_scanline < cinfo.image_height)". + +Code for this step depends heavily on the way that you store the source data. +example.c shows the following code for the case of a full-size 2-D source +array containing 3-byte RGB pixels: + + JSAMPROW row_pointer[1]; /* pointer to a single row */ + int row_stride; /* physical row width in buffer */ + + row_stride = image_width * 3; /* JSAMPLEs per row in image_buffer */ + + while (cinfo.next_scanline < cinfo.image_height) { + row_pointer[0] = & image_buffer[cinfo.next_scanline * row_stride]; + jpeg_write_scanlines(&cinfo, row_pointer, 1); + } + +jpeg_write_scanlines() returns the number of scanlines actually written. +This will normally be equal to the number passed in, so you can usually +ignore the return value. It is different in just two cases: + * If you try to write more scanlines than the declared image height, + the additional scanlines are ignored. + * If you use a suspending data destination manager, output buffer overrun + will cause the compressor to return before accepting all the passed lines. + This feature is discussed under "I/O suspension", below. The normal + stdio destination manager will NOT cause this to happen. +In any case, the return value is the same as the change in the value of +next_scanline. + + +6. jpeg_finish_compress(...); + +After all the image data has been written, call jpeg_finish_compress() to +complete the compression cycle. This step is ESSENTIAL to ensure that the +last bufferload of data is written to the data destination. +jpeg_finish_compress() also releases working memory associated with the JPEG +object. + +Typical code: + + jpeg_finish_compress(&cinfo); + +If using the stdio destination manager, don't forget to close the output +stdio stream (if necessary) afterwards. + +If you have requested a multi-pass operating mode, such as Huffman code +optimization, jpeg_finish_compress() will perform the additional passes using +data buffered by the first pass. In this case jpeg_finish_compress() may take +quite a while to complete. With the default compression parameters, this will +not happen. + +It is an error to call jpeg_finish_compress() before writing the necessary +total number of scanlines. If you wish to abort compression, call +jpeg_abort() as discussed below. + +After completing a compression cycle, you may dispose of the JPEG object +as discussed next, or you may use it to compress another image. In that case +return to step 2, 3, or 4 as appropriate. If you do not change the +destination manager, the new datastream will be written to the same target. +If you do not change any JPEG parameters, the new datastream will be written +with the same parameters as before. Note that you can change the input image +dimensions freely between cycles, but if you change the input colorspace, you +should call jpeg_set_defaults() to adjust for the new colorspace; and then +you'll need to repeat all of step 3. + + +7. Release the JPEG compression object. + +When you are done with a JPEG compression object, destroy it by calling +jpeg_destroy_compress(). This will free all subsidiary memory (regardless of +the previous state of the object). Or you can call jpeg_destroy(), which +works for either compression or decompression objects --- this may be more +convenient if you are sharing code between compression and decompression +cases. (Actually, these routines are equivalent except for the declared type +of the passed pointer. To avoid gripes from ANSI C compilers, jpeg_destroy() +should be passed a j_common_ptr.) + +If you allocated the jpeg_compress_struct structure from malloc(), freeing +it is your responsibility --- jpeg_destroy() won't. Ditto for the error +handler structure. + +Typical code: + + jpeg_destroy_compress(&cinfo); + + +8. Aborting. + +If you decide to abort a compression cycle before finishing, you can clean up +in either of two ways: + +* If you don't need the JPEG object any more, just call + jpeg_destroy_compress() or jpeg_destroy() to release memory. This is + legitimate at any point after calling jpeg_create_compress() --- in fact, + it's safe even if jpeg_create_compress() fails. + +* If you want to re-use the JPEG object, call jpeg_abort_compress(), or call + jpeg_abort() which works on both compression and decompression objects. + This will return the object to an idle state, releasing any working memory. + jpeg_abort() is allowed at any time after successful object creation. + +Note that cleaning up the data destination, if required, is your +responsibility; neither of these routines will call term_destination(). +(See "Compressed data handling", below, for more about that.) + +jpeg_destroy() and jpeg_abort() are the only safe calls to make on a JPEG +object that has reported an error by calling error_exit (see "Error handling" +for more info). The internal state of such an object is likely to be out of +whack. Either of these two routines will return the object to a known state. + + +Decompression details +--------------------- + +Here we revisit the JPEG decompression outline given in the overview. + +1. Allocate and initialize a JPEG decompression object. + +This is just like initialization for compression, as discussed above, +except that the object is a "struct jpeg_decompress_struct" and you +call jpeg_create_decompress(). Error handling is exactly the same. + +Typical code: + + struct jpeg_decompress_struct cinfo; + struct jpeg_error_mgr jerr; + ... + cinfo.err = jpeg_std_error(&jerr); + jpeg_create_decompress(&cinfo); + +(Both here and in the IJG code, we usually use variable name "cinfo" for +both compression and decompression objects.) + + +2. Specify the source of the compressed data (eg, a file). + +As previously mentioned, the JPEG library reads compressed data from a "data +source" module. The library includes one data source module which knows how +to read from a stdio stream. You can use your own source module if you want +to do something else, as discussed later. + +If you use the standard source module, you must open the source stdio stream +beforehand. Typical code for this step looks like: + + FILE * infile; + ... + if ((infile = fopen(filename, "rb")) == NULL) { + fprintf(stderr, "can't open %s\n", filename); + exit(1); + } + jpeg_stdio_src(&cinfo, infile); + +where the last line invokes the standard source module. + +WARNING: it is critical that the binary compressed data be read unchanged. +On non-Unix systems the stdio library may perform newline translation or +otherwise corrupt binary data. To suppress this behavior, you may need to use +a "b" option to fopen (as shown above), or use setmode() or another routine to +put the stdio stream in binary mode. See cjpeg.c and djpeg.c for code that +has been found to work on many systems. + +You may not change the data source between calling jpeg_read_header() and +jpeg_finish_decompress(). If you wish to read a series of JPEG images from +a single source file, you should repeat the jpeg_read_header() to +jpeg_finish_decompress() sequence without reinitializing either the JPEG +object or the data source module; this prevents buffered input data from +being discarded. + + +3. Call jpeg_read_header() to obtain image info. + +Typical code for this step is just + + jpeg_read_header(&cinfo, TRUE); + +This will read the source datastream header markers, up to the beginning +of the compressed data proper. On return, the image dimensions and other +info have been stored in the JPEG object. The application may wish to +consult this information before selecting decompression parameters. + +More complex code is necessary if + * A suspending data source is used --- in that case jpeg_read_header() + may return before it has read all the header data. See "I/O suspension", + below. The normal stdio source manager will NOT cause this to happen. + * Abbreviated JPEG files are to be processed --- see the section on + abbreviated datastreams. Standard applications that deal only in + interchange JPEG files need not be concerned with this case either. + +It is permissible to stop at this point if you just wanted to find out the +image dimensions and other header info for a JPEG file. In that case, +call jpeg_destroy() when you are done with the JPEG object, or call +jpeg_abort() to return it to an idle state before selecting a new data +source and reading another header. + + +4. Set parameters for decompression. + +jpeg_read_header() sets appropriate default decompression parameters based on +the properties of the image (in particular, its colorspace). However, you +may well want to alter these defaults before beginning the decompression. +For example, the default is to produce full color output from a color file. +If you want colormapped output you must ask for it. Other options allow the +returned image to be scaled and allow various speed/quality tradeoffs to be +selected. "Decompression parameter selection", below, gives details. + +If the defaults are appropriate, nothing need be done at this step. + +Note that all default values are set by each call to jpeg_read_header(). +If you reuse a decompression object, you cannot expect your parameter +settings to be preserved across cycles, as you can for compression. +You must set desired parameter values each time. + + +5. jpeg_start_decompress(...); + +Once the parameter values are satisfactory, call jpeg_start_decompress() to +begin decompression. This will initialize internal state, allocate working +memory, and prepare for returning data. + +Typical code is just + + jpeg_start_decompress(&cinfo); + +If you have requested a multi-pass operating mode, such as 2-pass color +quantization, jpeg_start_decompress() will do everything needed before data +output can begin. In this case jpeg_start_decompress() may take quite a while +to complete. With a single-scan (non progressive) JPEG file and default +decompression parameters, this will not happen; jpeg_start_decompress() will +return quickly. + +After this call, the final output image dimensions, including any requested +scaling, are available in the JPEG object; so is the selected colormap, if +colormapped output has been requested. Useful fields include + + output_width image width and height, as scaled + output_height + out_color_components # of color components in out_color_space + output_components # of color components returned per pixel + colormap the selected colormap, if any + actual_number_of_colors number of entries in colormap + +output_components is 1 (a colormap index) when quantizing colors; otherwise it +equals out_color_components. It is the number of JSAMPLE values that will be +emitted per pixel in the output arrays. + +Typically you will need to allocate data buffers to hold the incoming image. +You will need output_width * output_components JSAMPLEs per scanline in your +output buffer, and a total of output_height scanlines will be returned. + +Note: if you are using the JPEG library's internal memory manager to allocate +data buffers (as djpeg does), then the manager's protocol requires that you +request large buffers *before* calling jpeg_start_decompress(). This is a +little tricky since the output_XXX fields are not normally valid then. You +can make them valid by calling jpeg_calc_output_dimensions() after setting the +relevant parameters (scaling, output color space, and quantization flag). + + +6. while (scan lines remain to be read) + jpeg_read_scanlines(...); + +Now you can read the decompressed image data by calling jpeg_read_scanlines() +one or more times. At each call, you pass in the maximum number of scanlines +to be read (ie, the height of your working buffer); jpeg_read_scanlines() +will return up to that many lines. The return value is the number of lines +actually read. The format of the returned data is discussed under "Data +formats", above. Don't forget that grayscale and color JPEGs will return +different data formats! + +Image data is returned in top-to-bottom scanline order. If you must write +out the image in bottom-to-top order, you can use the JPEG library's virtual +array mechanism to invert the data efficiently. Examples of this can be +found in the sample application djpeg. + +The library maintains a count of the number of scanlines returned so far +in the output_scanline field of the JPEG object. Usually you can just use +this variable as the loop counter, so that the loop test looks like +"while (cinfo.output_scanline < cinfo.output_height)". (Note that the test +should NOT be against image_height, unless you never use scaling. The +image_height field is the height of the original unscaled image.) +The return value always equals the change in the value of output_scanline. + +If you don't use a suspending data source, it is safe to assume that +jpeg_read_scanlines() reads at least one scanline per call, until the +bottom of the image has been reached. + +If you use a buffer larger than one scanline, it is NOT safe to assume that +jpeg_read_scanlines() fills it. (The current implementation returns only a +few scanlines per call, no matter how large a buffer you pass.) So you must +always provide a loop that calls jpeg_read_scanlines() repeatedly until the +whole image has been read. + + +7. jpeg_finish_decompress(...); + +After all the image data has been read, call jpeg_finish_decompress() to +complete the decompression cycle. This causes working memory associated +with the JPEG object to be released. + +Typical code: + + jpeg_finish_decompress(&cinfo); + +If using the stdio source manager, don't forget to close the source stdio +stream if necessary. + +It is an error to call jpeg_finish_decompress() before reading the correct +total number of scanlines. If you wish to abort decompression, call +jpeg_abort() as discussed below. + +After completing a decompression cycle, you may dispose of the JPEG object as +discussed next, or you may use it to decompress another image. In that case +return to step 2 or 3 as appropriate. If you do not change the source +manager, the next image will be read from the same source. + + +8. Release the JPEG decompression object. + +When you are done with a JPEG decompression object, destroy it by calling +jpeg_destroy_decompress() or jpeg_destroy(). The previous discussion of +destroying compression objects applies here too. + +Typical code: + + jpeg_destroy_decompress(&cinfo); + + +9. Aborting. + +You can abort a decompression cycle by calling jpeg_destroy_decompress() or +jpeg_destroy() if you don't need the JPEG object any more, or +jpeg_abort_decompress() or jpeg_abort() if you want to reuse the object. +The previous discussion of aborting compression cycles applies here too. + + +Mechanics of usage: include files, linking, etc +----------------------------------------------- + +Applications using the JPEG library should include the header file jpeglib.h +to obtain declarations of data types and routines. Before including +jpeglib.h, include system headers that define at least the typedefs FILE and +size_t. On ANSI-conforming systems, including <stdio.h> is sufficient; on +older Unix systems, you may need <sys/types.h> to define size_t. + +If the application needs to refer to individual JPEG library error codes, also +include jerror.h to define those symbols. + +jpeglib.h indirectly includes the files jconfig.h and jmorecfg.h. If you are +installing the JPEG header files in a system directory, you will want to +install all four files: jpeglib.h, jerror.h, jconfig.h, jmorecfg.h. + +The most convenient way to include the JPEG code into your executable program +is to prepare a library file ("libjpeg.a", or a corresponding name on non-Unix +machines) and reference it at your link step. If you use only half of the +library (only compression or only decompression), only that much code will be +included from the library, unless your linker is hopelessly brain-damaged. +The supplied makefiles build libjpeg.a automatically (see install.doc). + +While you can build the JPEG library as a shared library if the whim strikes +you, we don't really recommend it. The trouble with shared libraries is that +at some point you'll probably try to substitute a new version of the library +without recompiling the calling applications. That generally doesn't work +because the parameter struct declarations usually change with each new +version. In other words, the library's API is *not* guaranteed binary +compatible across versions; we only try to ensure source-code compatibility. +(In hindsight, it might have been smarter to hide the parameter structs from +applications and introduce a ton of access functions instead. Too late now, +however.) + +On some systems your application may need to set up a signal handler to ensure +that temporary files are deleted if the program is interrupted. This is most +critical if you are on MS-DOS and use the jmemdos.c memory manager back end; +it will try to grab extended memory for temp files, and that space will NOT be +freed automatically. See cjpeg.c or djpeg.c for an example signal handler. + +It may be worth pointing out that the core JPEG library does not actually +require the stdio library: only the default source/destination managers and +error handler need it. You can use the library in a stdio-less environment +if you replace those modules and use jmemnobs.c (or another memory manager of +your own devising). More info about the minimum system library requirements +may be found in jinclude.h. + + +ADVANCED FEATURES +================= + +Compression parameter selection +------------------------------- + +This section describes all the optional parameters you can set for JPEG +compression, as well as the "helper" routines provided to assist in this +task. Proper setting of some parameters requires detailed understanding +of the JPEG standard; if you don't know what a parameter is for, it's best +not to mess with it! See REFERENCES in the README file for pointers to +more info about JPEG. + +It's a good idea to call jpeg_set_defaults() first, even if you plan to set +all the parameters; that way your code is more likely to work with future JPEG +libraries that have additional parameters. For the same reason, we recommend +you use a helper routine where one is provided, in preference to twiddling +cinfo fields directly. + +The helper routines are: + +jpeg_set_defaults (j_compress_ptr cinfo) + This routine sets all JPEG parameters to reasonable defaults, using + only the input image's color space (field in_color_space, which must + already be set in cinfo). Many applications will only need to use + this routine and perhaps jpeg_set_quality(). + +jpeg_set_colorspace (j_compress_ptr cinfo, J_COLOR_SPACE colorspace) + Sets the JPEG file's colorspace (field jpeg_color_space) as specified, + and sets other color-space-dependent parameters appropriately. See + "Special color spaces", below, before using this. A large number of + parameters, including all per-component parameters, are set by this + routine; if you want to twiddle individual parameters you should call + jpeg_set_colorspace() before rather than after. + +jpeg_default_colorspace (j_compress_ptr cinfo) + Selects an appropriate JPEG colorspace based on cinfo->in_color_space, + and calls jpeg_set_colorspace(). This is actually a subroutine of + jpeg_set_defaults(). It's broken out in case you want to change + just the colorspace-dependent JPEG parameters. + +jpeg_set_quality (j_compress_ptr cinfo, int quality, boolean force_baseline) + Constructs JPEG quantization tables appropriate for the indicated + quality setting. The quality value is expressed on the 0..100 scale + recommended by IJG (cjpeg's "-quality" switch uses this routine). + Note that the exact mapping from quality values to tables may change + in future IJG releases as more is learned about DCT quantization. + If the force_baseline parameter is TRUE, then the quantization table + entries are constrained to the range 1..255 for full JPEG baseline + compatibility. In the current implementation, this only makes a + difference for quality settings below 25, and it effectively prevents + very small/low quality files from being generated. The IJG decoder + is capable of reading the non-baseline files generated at low quality + settings when force_baseline is FALSE, but other decoders may not be. + +jpeg_set_linear_quality (j_compress_ptr cinfo, int scale_factor, + boolean force_baseline) + Same as jpeg_set_quality() except that the generated tables are the + sample tables given in the JPEC spec section K.1, multiplied by the + specified scale factor (which is expressed as a percentage; thus + scale_factor = 100 reproduces the spec's tables). Note that larger + scale factors give lower quality. This entry point is useful for + conforming to the Adobe PostScript DCT conventions, but we do not + recommend linear scaling as a user-visible quality scale otherwise. + force_baseline again constrains the computed table entries to 1..255. + +int jpeg_quality_scaling (int quality) + Converts a value on the IJG-recommended quality scale to a linear + scaling percentage. Note that this routine may change or go away + in future releases --- IJG may choose to adopt a scaling method that + can't be expressed as a simple scalar multiplier, in which case the + premise of this routine collapses. Caveat user. + +jpeg_add_quant_table (j_compress_ptr cinfo, int which_tbl, + const unsigned int *basic_table, + int scale_factor, boolean force_baseline) + Allows an arbitrary quantization table to be created. which_tbl + indicates which table slot to fill. basic_table points to an array + of 64 unsigned ints given in normal array order. These values are + multiplied by scale_factor/100 and then clamped to the range 1..65535 + (or to 1..255 if force_baseline is TRUE). + CAUTION: prior to library version 6a, jpeg_add_quant_table expected + the basic table to be given in JPEG zigzag order. If you need to + write code that works with either older or newer versions of this + routine, you must check the library version number. Something like + "#if JPEG_LIB_VERSION >= 61" is the right test. + +jpeg_simple_progression (j_compress_ptr cinfo) + Generates a default scan script for writing a progressive-JPEG file. + This is the recommended method of creating a progressive file, + unless you want to make a custom scan sequence. You must ensure that + the JPEG color space is set correctly before calling this routine. + +jpeg_simple_lossless (j_compress_ptr cinfo, int predictor, int point_transform) + Generates a default scan script for writing a lossless-JPEG file. + This is the recommended method of creating a lossless file, + unless you want to make a custom scan sequence. You must ensure that + the JPEG color space is set correctly before calling this routine. + + +Compression parameters (cinfo fields) include: + +J_DCT_METHOD dct_method + Selects the algorithm used for the DCT step. Choices are: + JDCT_ISLOW: slow but accurate integer algorithm + JDCT_IFAST: faster, less accurate integer method + JDCT_FLOAT: floating-point method + JDCT_DEFAULT: default method (normally JDCT_ISLOW) + JDCT_FASTEST: fastest method (normally JDCT_IFAST) + The FLOAT method is very slightly more accurate than the ISLOW method, + but may give different results on different machines due to varying + roundoff behavior. The integer methods should give the same results + on all machines. On machines with sufficiently fast FP hardware, the + floating-point method may also be the fastest. The IFAST method is + considerably less accurate than the other two; its use is not + recommended if high quality is a concern. JDCT_DEFAULT and + JDCT_FASTEST are macros configurable by each installation. + +J_COLOR_SPACE jpeg_color_space +int num_components + The JPEG color space and corresponding number of components; see + "Special color spaces", below, for more info. We recommend using + jpeg_set_color_space() if you want to change these. + +boolean optimize_coding + TRUE causes the compressor to compute optimal Huffman coding tables + for the image. This requires an extra pass over the data and + therefore costs a good deal of space and time. The default is + FALSE, which tells the compressor to use the supplied or default + Huffman tables. In most cases optimal tables save only a few percent + of file size compared to the default tables. Note that when this is + TRUE, you need not supply Huffman tables at all, and any you do + supply will be overwritten. + +unsigned int restart_interval +int restart_in_rows + To emit restart markers in the JPEG file, set one of these nonzero. + Set restart_interval to specify the exact interval in MCU blocks. + Set restart_in_rows to specify the interval in MCU rows. (If + restart_in_rows is not 0, then restart_interval is set after the + image width in MCUs is computed.) Defaults are zero (no restarts). + One restart marker per MCU row is often a good choice. + NOTE: the overhead of restart markers is higher in grayscale JPEG + files than in color files, and MUCH higher in progressive JPEGs. + If you use restarts, you may want to use larger intervals in those + cases. + +const jpeg_scan_info * scan_info +int num_scans + By default, scan_info is NULL; this causes the compressor to write a + single-scan sequential JPEG file. If not NULL, scan_info points to + an array of scan definition records of length num_scans. The + compressor will then write a JPEG file having one scan for each scan + definition record. This is used to generate noninterleaved or + progressive JPEG files. The library checks that the scan array + defines a valid JPEG scan sequence. (jpeg_simple_progression creates + a suitable scan definition array for progressive JPEG.) This is + discussed further under "Progressive JPEG support". + +int smoothing_factor + If non-zero, the input image is smoothed; the value should be 1 for + minimal smoothing to 100 for maximum smoothing. Consult jcsample.c + for details of the smoothing algorithm. The default is zero. + +boolean write_JFIF_header + If TRUE, a JFIF APP0 marker is emitted. jpeg_set_defaults() and + jpeg_set_colorspace() set this TRUE if a JFIF-legal JPEG color space + (ie, YCbCr or grayscale) is selected, otherwise FALSE. + +UINT8 JFIF_major_version +UINT8 JFIF_minor_version + The version number to be written into the JFIF marker. + jpeg_set_defaults() initializes the version to 1.01 (major=minor=1). + You should set it to 1.02 (major=1, minor=2) if you plan to write + any JFIF 1.02 extension markers. + +UINT8 density_unit +UINT16 X_density +UINT16 Y_density + The resolution information to be written into the JFIF marker; + not used otherwise. density_unit may be 0 for unknown, + 1 for dots/inch, or 2 for dots/cm. The default values are 0,1,1 + indicating square pixels of unknown size. + +boolean write_Adobe_marker + If TRUE, an Adobe APP14 marker is emitted. jpeg_set_defaults() and + jpeg_set_colorspace() set this TRUE if JPEG color space RGB, CMYK, + or YCCK is selected, otherwise FALSE. It is generally a bad idea + to set both write_JFIF_header and write_Adobe_marker. In fact, + you probably shouldn't change the default settings at all --- the + default behavior ensures that the JPEG file's color space can be + recognized by the decoder. + +JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS] + Pointers to coefficient quantization tables, one per table slot, + or NULL if no table is defined for a slot. Usually these should + be set via one of the above helper routines; jpeg_add_quant_table() + is general enough to define any quantization table. The other + routines will set up table slot 0 for luminance quality and table + slot 1 for chrominance. + +JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS] +JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS] + Pointers to Huffman coding tables, one per table slot, or NULL if + no table is defined for a slot. Slots 0 and 1 are filled with the + JPEG sample tables by jpeg_set_defaults(). If you need to allocate + more table structures, jpeg_alloc_huff_table() may be used. + Note that optimal Huffman tables can be computed for an image + by setting optimize_coding, as discussed above; there's seldom + any need to mess with providing your own Huffman tables. + +There are some additional cinfo fields which are not documented here +because you currently can't change them; for example, you can't set +arith_code TRUE because arithmetic coding is unsupported. + + +Per-component parameters are stored in the struct cinfo.comp_info[i] for +component number i. Note that components here refer to components of the +JPEG color space, *not* the source image color space. A suitably large +comp_info[] array is allocated by jpeg_set_defaults(); if you choose not +to use that routine, it's up to you to allocate the array. + +int component_id + The one-byte identifier code to be recorded in the JPEG file for + this component. For the standard color spaces, we recommend you + leave the default values alone. + +int h_samp_factor +int v_samp_factor + Horizontal and vertical sampling factors for the component; must + be 1..4 according to the JPEG standard. Note that larger sampling + factors indicate a higher-resolution component; many people find + this behavior quite unintuitive. The default values are 2,2 for + luminance components and 1,1 for chrominance components, except + for grayscale where 1,1 is used. + +int quant_tbl_no + Quantization table number for component. The default value is + 0 for luminance components and 1 for chrominance components. + +int dc_tbl_no +int ac_tbl_no + DC and AC entropy coding table numbers. The default values are + 0 for luminance components and 1 for chrominance components. + +int component_index + Must equal the component's index in comp_info[]. (Beginning in + release v6, the compressor library will fill this in automatically; + you don't have to.) + + +Decompression parameter selection +--------------------------------- + +Decompression parameter selection is somewhat simpler than compression +parameter selection, since all of the JPEG internal parameters are +recorded in the source file and need not be supplied by the application. +(Unless you are working with abbreviated files, in which case see +"Abbreviated datastreams", below.) Decompression parameters control +the postprocessing done on the image to deliver it in a format suitable +for the application's use. Many of the parameters control speed/quality +tradeoffs, in which faster decompression may be obtained at the price of +a poorer-quality image. The defaults select the highest quality (slowest) +processing. + +The following fields in the JPEG object are set by jpeg_read_header() and +may be useful to the application in choosing decompression parameters: + +JDIMENSION image_width Width and height of image +JDIMENSION image_height +int num_components Number of color components +J_COLOR_SPACE jpeg_color_space Colorspace of image +boolean saw_JFIF_marker TRUE if a JFIF APP0 marker was seen + UINT8 JFIF_major_version Version information from JFIF marker + UINT8 JFIF_minor_version + UINT8 density_unit Resolution data from JFIF marker + UINT16 X_density + UINT16 Y_density +boolean saw_Adobe_marker TRUE if an Adobe APP14 marker was seen + UINT8 Adobe_transform Color transform code from Adobe marker + +The JPEG color space, unfortunately, is something of a guess since the JPEG +standard proper does not provide a way to record it. In practice most files +adhere to the JFIF or Adobe conventions, and the decoder will recognize these +correctly. See "Special color spaces", below, for more info. + + +The decompression parameters that determine the basic properties of the +returned image are: + +J_COLOR_SPACE out_color_space + Output color space. jpeg_read_header() sets an appropriate default + based on jpeg_color_space; typically it will be RGB or grayscale. + The application can change this field to request output in a different + colorspace. For example, set it to JCS_GRAYSCALE to get grayscale + output from a color file. (This is useful for previewing: grayscale + output is faster than full color since the color components need not + be processed.) Note that not all possible color space transforms are + currently implemented; you may need to extend jdcolor.c if you want an + unusual conversion. + +unsigned int scale_num, scale_denom + Scale the image by the fraction scale_num/scale_denom. Default is + 1/1, or no scaling. Currently, the only supported scaling ratios + are 1/1, 1/2, 1/4, and 1/8. (The library design allows for arbitrary + scaling ratios but this is not likely to be implemented any time soon.) + Smaller scaling ratios permit significantly faster decoding since + fewer pixels need be processed and a simpler IDCT method can be used. + +boolean quantize_colors + If set TRUE, colormapped output will be delivered. Default is FALSE, + meaning that full-color output will be delivered. + +The next three parameters are relevant only if quantize_colors is TRUE. + +int desired_number_of_colors + Maximum number of colors to use in generating a library-supplied color + map (the actual number of colors is returned in a different field). + Default 256. Ignored when the application supplies its own color map. + +boolean two_pass_quantize + If TRUE, an extra pass over the image is made to select a custom color + map for the image. This usually looks a lot better than the one-size- + fits-all colormap that is used otherwise. Default is TRUE. Ignored + when the application supplies its own color map. + +J_DITHER_MODE dither_mode + Selects color dithering method. Supported values are: + JDITHER_NONE no dithering: fast, very low quality + JDITHER_ORDERED ordered dither: moderate speed and quality + JDITHER_FS Floyd-Steinberg dither: slow, high quality + Default is JDITHER_FS. (At present, ordered dither is implemented + only in the single-pass, standard-colormap case. If you ask for + ordered dither when two_pass_quantize is TRUE or when you supply + an external color map, you'll get F-S dithering.) + +When quantize_colors is TRUE, the target color map is described by the next +two fields. colormap is set to NULL by jpeg_read_header(). The application +can supply a color map by setting colormap non-NULL and setting +actual_number_of_colors to the map size. Otherwise, jpeg_start_decompress() +selects a suitable color map and sets these two fields itself. +[Implementation restriction: at present, an externally supplied colormap is +only accepted for 3-component output color spaces.] + +JSAMPARRAY colormap + The color map, represented as a 2-D pixel array of out_color_components + rows and actual_number_of_colors columns. Ignored if not quantizing. + CAUTION: if the JPEG library creates its own colormap, the storage + pointed to by this field is released by jpeg_finish_decompress(). + Copy the colormap somewhere else first, if you want to save it. + +int actual_number_of_colors + The number of colors in the color map. + +Additional decompression parameters that the application may set include: + +J_DCT_METHOD dct_method + Selects the algorithm used for the DCT step. Choices are the same + as described above for compression. + +boolean do_fancy_upsampling + If TRUE, do careful upsampling of chroma components. If FALSE, + a faster but sloppier method is used. Default is TRUE. The visual + impact of the sloppier method is often very small. + +boolean do_block_smoothing + If TRUE, interblock smoothing is applied in early stages of decoding + progressive JPEG files; if FALSE, not. Default is TRUE. Early + progression stages look "fuzzy" with smoothing, "blocky" without. + In any case, block smoothing ceases to be applied after the first few + AC coefficients are known to full accuracy, so it is relevant only + when using buffered-image mode for progressive images. + +boolean enable_1pass_quant +boolean enable_external_quant +boolean enable_2pass_quant + These are significant only in buffered-image mode, which is + described in its own section below. + + +The output image dimensions are given by the following fields. These are +computed from the source image dimensions and the decompression parameters +by jpeg_start_decompress(). You can also call jpeg_calc_output_dimensions() +to obtain the values that will result from the current parameter settings. +This can be useful if you are trying to pick a scaling ratio that will get +close to a desired target size. It's also important if you are using the +JPEG library's memory manager to allocate output buffer space, because you +are supposed to request such buffers *before* jpeg_start_decompress(). + +JDIMENSION output_width Actual dimensions of output image. +JDIMENSION output_height +int out_color_components Number of color components in out_color_space. +int output_components Number of color components returned. +int rec_outbuf_height Recommended height of scanline buffer. + +When quantizing colors, output_components is 1, indicating a single color map +index per pixel. Otherwise it equals out_color_components. The output arrays +are required to be output_width * output_components JSAMPLEs wide. + +rec_outbuf_height is the recommended minimum height (in scanlines) of the +buffer passed to jpeg_read_scanlines(). If the buffer is smaller, the +library will still work, but time will be wasted due to unnecessary data +copying. In high-quality modes, rec_outbuf_height is always 1, but some +faster, lower-quality modes set it to larger values (typically 2 to 4). +If you are going to ask for a high-speed processing mode, you may as well +go to the trouble of honoring rec_outbuf_height so as to avoid data copying. +(An output buffer larger than rec_outbuf_height lines is OK, but won't +provide any material speed improvement over that height.) + + +Special color spaces +-------------------- + +The JPEG standard itself is "color blind" and doesn't specify any particular +color space. It is customary to convert color data to a luminance/chrominance +color space before compressing, since this permits greater compression. The +existing de-facto JPEG file format standards specify YCbCr or grayscale data +(JFIF), or grayscale, RGB, YCbCr, CMYK, or YCCK (Adobe). For special +applications such as multispectral images, other color spaces can be used, +but it must be understood that such files will be unportable. + +The JPEG library can handle the most common colorspace conversions (namely +RGB <=> YCbCr and CMYK <=> YCCK). It can also deal with data of an unknown +color space, passing it through without conversion. If you deal extensively +with an unusual color space, you can easily extend the library to understand +additional color spaces and perform appropriate conversions. + +For compression, the source data's color space is specified by field +in_color_space. This is transformed to the JPEG file's color space given +by jpeg_color_space. jpeg_set_defaults() chooses a reasonable JPEG color +space depending on in_color_space, but you can override this by calling +jpeg_set_colorspace(). Of course you must select a supported transformation. +jccolor.c currently supports the following transformations: + RGB => YCbCr + RGB => GRAYSCALE + YCbCr => GRAYSCALE + CMYK => YCCK +plus the null transforms: GRAYSCALE => GRAYSCALE, RGB => RGB, +YCbCr => YCbCr, CMYK => CMYK, YCCK => YCCK, and UNKNOWN => UNKNOWN. + +The de-facto file format standards (JFIF and Adobe) specify APPn markers that +indicate the color space of the JPEG file. It is important to ensure that +these are written correctly, or omitted if the JPEG file's color space is not +one of the ones supported by the de-facto standards. jpeg_set_colorspace() +will set the compression parameters to include or omit the APPn markers +properly, so long as it is told the truth about the JPEG color space. +For example, if you are writing some random 3-component color space without +conversion, don't try to fake out the library by setting in_color_space and +jpeg_color_space to JCS_YCbCr; use JCS_UNKNOWN. You may want to write an +APPn marker of your own devising to identify the colorspace --- see "Special +markers", below. + +When told that the color space is UNKNOWN, the library will default to using +luminance-quality compression parameters for all color components. You may +well want to change these parameters. See the source code for +jpeg_set_colorspace(), in jcparam.c, for details. + +For decompression, the JPEG file's color space is given in jpeg_color_space, +and this is transformed to the output color space out_color_space. +jpeg_read_header's setting of jpeg_color_space can be relied on if the file +conforms to JFIF or Adobe conventions, but otherwise it is no better than a +guess. If you know the JPEG file's color space for certain, you can override +jpeg_read_header's guess by setting jpeg_color_space. jpeg_read_header also +selects a default output color space based on (its guess of) jpeg_color_space; +set out_color_space to override this. Again, you must select a supported +transformation. jdcolor.c currently supports + YCbCr => GRAYSCALE + YCbCr => RGB + GRAYSCALE => RGB + YCCK => CMYK +as well as the null transforms. (Since GRAYSCALE=>RGB is provided, an +application can force grayscale JPEGs to look like color JPEGs if it only +wants to handle one case.) + +The two-pass color quantizer, jquant2.c, is specialized to handle RGB data +(it weights distances appropriately for RGB colors). You'll need to modify +the code if you want to use it for non-RGB output color spaces. Note that +jquant2.c is used to map to an application-supplied colormap as well as for +the normal two-pass colormap selection process. + +CAUTION: it appears that Adobe Photoshop writes inverted data in CMYK JPEG +files: 0 represents 100% ink coverage, rather than 0% ink as you'd expect. +This is arguably a bug in Photoshop, but if you need to work with Photoshop +CMYK files, you will have to deal with it in your application. We cannot +"fix" this in the library by inverting the data during the CMYK<=>YCCK +transform, because that would break other applications, notably Ghostscript. +Photoshop versions prior to 3.0 write EPS files containing JPEG-encoded CMYK +data in the same inverted-YCCK representation used in bare JPEG files, but +the surrounding PostScript code performs an inversion using the PS image +operator. I am told that Photoshop 3.0 will write uninverted YCCK in +EPS/JPEG files, and will omit the PS-level inversion. (But the data +polarity used in bare JPEG files will not change in 3.0.) In either case, +the JPEG library must not invert the data itself, or else Ghostscript would +read these EPS files incorrectly. + + +Error handling +-------------- + +When the default error handler is used, any error detected inside the JPEG +routines will cause a message to be printed on stderr, followed by exit(). +You can supply your own error handling routines to override this behavior +and to control the treatment of nonfatal warnings and trace/debug messages. +The file example.c illustrates the most common case, which is to have the +application regain control after an error rather than exiting. + +The JPEG library never writes any message directly; it always goes through +the error handling routines. Three classes of messages are recognized: + * Fatal errors: the library cannot continue. + * Warnings: the library can continue, but the data is corrupt, and a + damaged output image is likely to result. + * Trace/informational messages. These come with a trace level indicating + the importance of the message; you can control the verbosity of the + program by adjusting the maximum trace level that will be displayed. + +You may, if you wish, simply replace the entire JPEG error handling module +(jerror.c) with your own code. However, you can avoid code duplication by +only replacing some of the routines depending on the behavior you need. +This is accomplished by calling jpeg_std_error() as usual, but then overriding +some of the method pointers in the jpeg_error_mgr struct, as illustrated by +example.c. + +All of the error handling routines will receive a pointer to the JPEG object +(a j_common_ptr which points to either a jpeg_compress_struct or a +jpeg_decompress_struct; if you need to tell which, test the is_decompressor +field). This struct includes a pointer to the error manager struct in its +"err" field. Frequently, custom error handler routines will need to access +additional data which is not known to the JPEG library or the standard error +handler. The most convenient way to do this is to embed either the JPEG +object or the jpeg_error_mgr struct in a larger structure that contains +additional fields; then casting the passed pointer provides access to the +additional fields. Again, see example.c for one way to do it. (Beginning +with IJG version 6b, there is also a void pointer "client_data" in each +JPEG object, which the application can also use to find related data. +The library does not touch client_data at all.) + +The individual methods that you might wish to override are: + +error_exit (j_common_ptr cinfo) + Receives control for a fatal error. Information sufficient to + generate the error message has been stored in cinfo->err; call + output_message to display it. Control must NOT return to the caller; + generally this routine will exit() or longjmp() somewhere. + Typically you would override this routine to get rid of the exit() + default behavior. Note that if you continue processing, you should + clean up the JPEG object with jpeg_abort() or jpeg_destroy(). + +output_message (j_common_ptr cinfo) + Actual output of any JPEG message. Override this to send messages + somewhere other than stderr. Note that this method does not know + how to generate a message, only where to send it. + +format_message (j_common_ptr cinfo, char * buffer) + Constructs a readable error message string based on the error info + stored in cinfo->err. This method is called by output_message. Few + applications should need to override this method. One possible + reason for doing so is to implement dynamic switching of error message + language. + +emit_message (j_common_ptr cinfo, int msg_level) + Decide whether or not to emit a warning or trace message; if so, + calls output_message. The main reason for overriding this method + would be to abort on warnings. msg_level is -1 for warnings, + 0 and up for trace messages. + +Only error_exit() and emit_message() are called from the rest of the JPEG +library; the other two are internal to the error handler. + +The actual message texts are stored in an array of strings which is pointed to +by the field err->jpeg_message_table. The messages are numbered from 0 to +err->last_jpeg_message, and it is these code numbers that are used in the +JPEG library code. You could replace the message texts (for instance, with +messages in French or German) by changing the message table pointer. See +jerror.h for the default texts. CAUTION: this table will almost certainly +change or grow from one library version to the next. + +It may be useful for an application to add its own message texts that are +handled by the same mechanism. The error handler supports a second "add-on" +message table for this purpose. To define an addon table, set the pointer +err->addon_message_table and the message numbers err->first_addon_message and +err->last_addon_message. If you number the addon messages beginning at 1000 +or so, you won't have to worry about conflicts with the library's built-in +messages. See the sample applications cjpeg/djpeg for an example of using +addon messages (the addon messages are defined in cderror.h). + +Actual invocation of the error handler is done via macros defined in jerror.h: + ERREXITn(...) for fatal errors + WARNMSn(...) for corrupt-data warnings + TRACEMSn(...) for trace and informational messages. +These macros store the message code and any additional parameters into the +error handler struct, then invoke the error_exit() or emit_message() method. +The variants of each macro are for varying numbers of additional parameters. +The additional parameters are inserted into the generated message using +standard printf() format codes. + +See jerror.h and jerror.c for further details. + + +Compressed data handling (source and destination managers) +---------------------------------------------------------- + +The JPEG compression library sends its compressed data to a "destination +manager" module. The default destination manager just writes the data to a +stdio stream, but you can provide your own manager to do something else. +Similarly, the decompression library calls a "source manager" to obtain the +compressed data; you can provide your own source manager if you want the data +to come from somewhere other than a stdio stream. + +In both cases, compressed data is processed a bufferload at a time: the +destination or source manager provides a work buffer, and the library invokes +the manager only when the buffer is filled or emptied. (You could define a +one-character buffer to force the manager to be invoked for each byte, but +that would be rather inefficient.) The buffer's size and location are +controlled by the manager, not by the library. For example, if you desired to +decompress a JPEG datastream that was all in memory, you could just make the +buffer pointer and length point to the original data in memory. Then the +buffer-reload procedure would be invoked only if the decompressor ran off the +end of the datastream, which would indicate an erroneous datastream. + +The work buffer is defined as an array of datatype JOCTET, which is generally +"char" or "unsigned char". On a machine where char is not exactly 8 bits +wide, you must define JOCTET as a wider data type and then modify the data +source and destination modules to transcribe the work arrays into 8-bit units +on external storage. + +A data destination manager struct contains a pointer and count defining the +next byte to write in the work buffer and the remaining free space: + + JOCTET * next_output_byte; /* => next byte to write in buffer */ + size_t free_in_buffer; /* # of byte spaces remaining in buffer */ + +The library increments the pointer and decrements the count until the buffer +is filled. The manager's empty_output_buffer method must reset the pointer +and count. The manager is expected to remember the buffer's starting address +and total size in private fields not visible to the library. + +A data destination manager provides three methods: + +init_destination (j_compress_ptr cinfo) + Initialize destination. This is called by jpeg_start_compress() + before any data is actually written. It must initialize + next_output_byte and free_in_buffer. free_in_buffer must be + initialized to a positive value. + +empty_output_buffer (j_compress_ptr cinfo) + This is called whenever the buffer has filled (free_in_buffer + reaches zero). In typical applications, it should write out the + *entire* buffer (use the saved start address and buffer length; + ignore the current state of next_output_byte and free_in_buffer). + Then reset the pointer & count to the start of the buffer, and + return TRUE indicating that the buffer has been dumped. + free_in_buffer must be set to a positive value when TRUE is + returned. A FALSE return should only be used when I/O suspension is + desired (this operating mode is discussed in the next section). + +term_destination (j_compress_ptr cinfo) + Terminate destination --- called by jpeg_finish_compress() after all + data has been written. In most applications, this must flush any + data remaining in the buffer. Use either next_output_byte or + free_in_buffer to determine how much data is in the buffer. + +term_destination() is NOT called by jpeg_abort() or jpeg_destroy(). If you +want the destination manager to be cleaned up during an abort, you must do it +yourself. + +You will also need code to create a jpeg_destination_mgr struct, fill in its +method pointers, and insert a pointer to the struct into the "dest" field of +the JPEG compression object. This can be done in-line in your setup code if +you like, but it's probably cleaner to provide a separate routine similar to +the jpeg_stdio_dest() routine of the supplied destination manager. + +Decompression source managers follow a parallel design, but with some +additional frammishes. The source manager struct contains a pointer and count +defining the next byte to read from the work buffer and the number of bytes +remaining: + + const JOCTET * next_input_byte; /* => next byte to read from buffer */ + size_t bytes_in_buffer; /* # of bytes remaining in buffer */ + +The library increments the pointer and decrements the count until the buffer +is emptied. The manager's fill_input_buffer method must reset the pointer and +count. In most applications, the manager must remember the buffer's starting +address and total size in private fields not visible to the library. + +A data source manager provides five methods: + +init_source (j_decompress_ptr cinfo) + Initialize source. This is called by jpeg_read_header() before any + data is actually read. Unlike init_destination(), it may leave + bytes_in_buffer set to 0 (in which case a fill_input_buffer() call + will occur immediately). + +fill_input_buffer (j_decompress_ptr cinfo) + This is called whenever bytes_in_buffer has reached zero and more + data is wanted. In typical applications, it should read fresh data + into the buffer (ignoring the current state of next_input_byte and + bytes_in_buffer), reset the pointer & count to the start of the + buffer, and return TRUE indicating that the buffer has been reloaded. + It is not necessary to fill the buffer entirely, only to obtain at + least one more byte. bytes_in_buffer MUST be set to a positive value + if TRUE is returned. A FALSE return should only be used when I/O + suspension is desired (this mode is discussed in the next section). + +skip_input_data (j_decompress_ptr cinfo, long num_bytes) + Skip num_bytes worth of data. The buffer pointer and count should + be advanced over num_bytes input bytes, refilling the buffer as + needed. This is used to skip over a potentially large amount of + uninteresting data (such as an APPn marker). In some applications + it may be possible to optimize away the reading of the skipped data, + but it's not clear that being smart is worth much trouble; large + skips are uncommon. bytes_in_buffer may be zero on return. + A zero or negative skip count should be treated as a no-op. + +resync_to_restart (j_decompress_ptr cinfo, int desired) + This routine is called only when the decompressor has failed to find + a restart (RSTn) marker where one is expected. Its mission is to + find a suitable point for resuming decompression. For most + applications, we recommend that you just use the default resync + procedure, jpeg_resync_to_restart(). However, if you are able to back + up in the input data stream, or if you have a-priori knowledge about + the likely location of restart markers, you may be able to do better. + Read the read_restart_marker() and jpeg_resync_to_restart() routines + in jdmarker.c if you think you'd like to implement your own resync + procedure. + +term_source (j_decompress_ptr cinfo) + Terminate source --- called by jpeg_finish_decompress() after all + data has been read. Often a no-op. + +For both fill_input_buffer() and skip_input_data(), there is no such thing +as an EOF return. If the end of the file has been reached, the routine has +a choice of exiting via ERREXIT() or inserting fake data into the buffer. +In most cases, generating a warning message and inserting a fake EOI marker +is the best course of action --- this will allow the decompressor to output +however much of the image is there. In pathological cases, the decompressor +may swallow the EOI and again demand data ... just keep feeding it fake EOIs. +jdatasrc.c illustrates the recommended error recovery behavior. + +term_source() is NOT called by jpeg_abort() or jpeg_destroy(). If you want +the source manager to be cleaned up during an abort, you must do it yourself. + +You will also need code to create a jpeg_source_mgr struct, fill in its method +pointers, and insert a pointer to the struct into the "src" field of the JPEG +decompression object. This can be done in-line in your setup code if you +like, but it's probably cleaner to provide a separate routine similar to the +jpeg_stdio_src() routine of the supplied source manager. + +For more information, consult the stdio source and destination managers +in jdatasrc.c and jdatadst.c. + + +I/O suspension +-------------- + +Some applications need to use the JPEG library as an incremental memory-to- +memory filter: when the compressed data buffer is filled or emptied, they want +control to return to the outer loop, rather than expecting that the buffer can +be emptied or reloaded within the data source/destination manager subroutine. +The library supports this need by providing an "I/O suspension" mode, which we +describe in this section. + +The I/O suspension mode is not a panacea: nothing is guaranteed about the +maximum amount of time spent in any one call to the library, so it will not +eliminate response-time problems in single-threaded applications. If you +need guaranteed response time, we suggest you "bite the bullet" and implement +a real multi-tasking capability. + +To use I/O suspension, cooperation is needed between the calling application +and the data source or destination manager; you will always need a custom +source/destination manager. (Please read the previous section if you haven't +already.) The basic idea is that the empty_output_buffer() or +fill_input_buffer() routine is a no-op, merely returning FALSE to indicate +that it has done nothing. Upon seeing this, the JPEG library suspends +operation and returns to its caller. The surrounding application is +responsible for emptying or refilling the work buffer before calling the +JPEG library again. + +Compression suspension: + +For compression suspension, use an empty_output_buffer() routine that returns +FALSE; typically it will not do anything else. This will cause the +compressor to return to the caller of jpeg_write_scanlines(), with the return +value indicating that not all the supplied scanlines have been accepted. +The application must make more room in the output buffer, adjust the output +buffer pointer/count appropriately, and then call jpeg_write_scanlines() +again, pointing to the first unconsumed scanline. + +When forced to suspend, the compressor will backtrack to a convenient stopping +point (usually the start of the current MCU); it will regenerate some output +data when restarted. Therefore, although empty_output_buffer() is only +called when the buffer is filled, you should NOT write out the entire buffer +after a suspension. Write only the data up to the current position of +next_output_byte/free_in_buffer. The data beyond that point will be +regenerated after resumption. + +Because of the backtracking behavior, a good-size output buffer is essential +for efficiency; you don't want the compressor to suspend often. (In fact, an +overly small buffer could lead to infinite looping, if a single MCU required +more data than would fit in the buffer.) We recommend a buffer of at least +several Kbytes. You may want to insert explicit code to ensure that you don't +call jpeg_write_scanlines() unless there is a reasonable amount of space in +the output buffer; in other words, flush the buffer before trying to compress +more data. + +The compressor does not allow suspension while it is trying to write JPEG +markers at the beginning and end of the file. This means that: + * At the beginning of a compression operation, there must be enough free + space in the output buffer to hold the header markers (typically 600 or + so bytes). The recommended buffer size is bigger than this anyway, so + this is not a problem as long as you start with an empty buffer. However, + this restriction might catch you if you insert large special markers, such + as a JFIF thumbnail image, without flushing the buffer afterwards. + * When you call jpeg_finish_compress(), there must be enough space in the + output buffer to emit any buffered data and the final EOI marker. In the + current implementation, half a dozen bytes should suffice for this, but + for safety's sake we recommend ensuring that at least 100 bytes are free + before calling jpeg_finish_compress(). + +A more significant restriction is that jpeg_finish_compress() cannot suspend. +This means you cannot use suspension with multi-pass operating modes, namely +Huffman code optimization and multiple-scan output. Those modes write the +whole file during jpeg_finish_compress(), which will certainly result in +buffer overrun. (Note that this restriction applies only to compression, +not decompression. The decompressor supports input suspension in all of its +operating modes.) + +Decompression suspension: + +For decompression suspension, use a fill_input_buffer() routine that simply +returns FALSE (except perhaps during error recovery, as discussed below). +This will cause the decompressor to return to its caller with an indication +that suspension has occurred. This can happen at four places: + * jpeg_read_header(): will return JPEG_SUSPENDED. + * jpeg_start_decompress(): will return FALSE, rather than its usual TRUE. + * jpeg_read_scanlines(): will return the number of scanlines already + completed (possibly 0). + * jpeg_finish_decompress(): will return FALSE, rather than its usual TRUE. +The surrounding application must recognize these cases, load more data into +the input buffer, and repeat the call. In the case of jpeg_read_scanlines(), +increment the passed pointers past any scanlines successfully read. + +Just as with compression, the decompressor will typically backtrack to a +convenient restart point before suspending. When fill_input_buffer() is +called, next_input_byte/bytes_in_buffer point to the current restart point, +which is where the decompressor will backtrack to if FALSE is returned. +The data beyond that position must NOT be discarded if you suspend; it needs +to be re-read upon resumption. In most implementations, you'll need to shift +this data down to the start of your work buffer and then load more data after +it. Again, this behavior means that a several-Kbyte work buffer is essential +for decent performance; furthermore, you should load a reasonable amount of +new data before resuming decompression. (If you loaded, say, only one new +byte each time around, you could waste a LOT of cycles.) + +The skip_input_data() source manager routine requires special care in a +suspension scenario. This routine is NOT granted the ability to suspend the +decompressor; it can decrement bytes_in_buffer to zero, but no more. If the +requested skip distance exceeds the amount of data currently in the input +buffer, then skip_input_data() must set bytes_in_buffer to zero and record the +additional skip distance somewhere else. The decompressor will immediately +call fill_input_buffer(), which should return FALSE, which will cause a +suspension return. The surrounding application must then arrange to discard +the recorded number of bytes before it resumes loading the input buffer. +(Yes, this design is rather baroque, but it avoids complexity in the far more +common case where a non-suspending source manager is used.) + +If the input data has been exhausted, we recommend that you emit a warning +and insert dummy EOI markers just as a non-suspending data source manager +would do. This can be handled either in the surrounding application logic or +within fill_input_buffer(); the latter is probably more efficient. If +fill_input_buffer() knows that no more data is available, it can set the +pointer/count to point to a dummy EOI marker and then return TRUE just as +though it had read more data in a non-suspending situation. + +The decompressor does not attempt to suspend within standard JPEG markers; +instead it will backtrack to the start of the marker and reprocess the whole +marker next time. Hence the input buffer must be large enough to hold the +longest standard marker in the file. Standard JPEG markers should normally +not exceed a few hundred bytes each (DHT tables are typically the longest). +We recommend at least a 2K buffer for performance reasons, which is much +larger than any correct marker is likely to be. For robustness against +damaged marker length counts, you may wish to insert a test in your +application for the case that the input buffer is completely full and yet +the decoder has suspended without consuming any data --- otherwise, if this +situation did occur, it would lead to an endless loop. (The library can't +provide this test since it has no idea whether "the buffer is full", or +even whether there is a fixed-size input buffer.) + +The input buffer would need to be 64K to allow for arbitrary COM or APPn +markers, but these are handled specially: they are either saved into allocated +memory, or skipped over by calling skip_input_data(). In the former case, +suspension is handled correctly, and in the latter case, the problem of +buffer overrun is placed on skip_input_data's shoulders, as explained above. +Note that if you provide your own marker handling routine for large markers, +you should consider how to deal with buffer overflow. + +Multiple-buffer management: + +In some applications it is desirable to store the compressed data in a linked +list of buffer areas, so as to avoid data copying. This can be handled by +having empty_output_buffer() or fill_input_buffer() set the pointer and count +to reference the next available buffer; FALSE is returned only if no more +buffers are available. Although seemingly straightforward, there is a +pitfall in this approach: the backtrack that occurs when FALSE is returned +could back up into an earlier buffer. For example, when fill_input_buffer() +is called, the current pointer & count indicate the backtrack restart point. +Since fill_input_buffer() will set the pointer and count to refer to a new +buffer, the restart position must be saved somewhere else. Suppose a second +call to fill_input_buffer() occurs in the same library call, and no +additional input data is available, so fill_input_buffer must return FALSE. +If the JPEG library has not moved the pointer/count forward in the current +buffer, then *the correct restart point is the saved position in the prior +buffer*. Prior buffers may be discarded only after the library establishes +a restart point within a later buffer. Similar remarks apply for output into +a chain of buffers. + +The library will never attempt to backtrack over a skip_input_data() call, +so any skipped data can be permanently discarded. You still have to deal +with the case of skipping not-yet-received data, however. + +It's much simpler to use only a single buffer; when fill_input_buffer() is +called, move any unconsumed data (beyond the current pointer/count) down to +the beginning of this buffer and then load new data into the remaining buffer +space. This approach requires a little more data copying but is far easier +to get right. + + +Progressive JPEG support +------------------------ + +Progressive JPEG rearranges the stored data into a series of scans of +increasing quality. In situations where a JPEG file is transmitted across a +slow communications link, a decoder can generate a low-quality image very +quickly from the first scan, then gradually improve the displayed quality as +more scans are received. The final image after all scans are complete is +identical to that of a regular (sequential) JPEG file of the same quality +setting. Progressive JPEG files are often slightly smaller than equivalent +sequential JPEG files, but the possibility of incremental display is the main +reason for using progressive JPEG. + +The IJG encoder library generates progressive JPEG files when given a +suitable "scan script" defining how to divide the data into scans. +Creation of progressive JPEG files is otherwise transparent to the encoder. +Progressive JPEG files can also be read transparently by the decoder library. +If the decoding application simply uses the library as defined above, it +will receive a final decoded image without any indication that the file was +progressive. Of course, this approach does not allow incremental display. +To perform incremental display, an application needs to use the decoder +library's "buffered-image" mode, in which it receives a decoded image +multiple times. + +Each displayed scan requires about as much work to decode as a full JPEG +image of the same size, so the decoder must be fairly fast in relation to the +data transmission rate in order to make incremental display useful. However, +it is possible to skip displaying the image and simply add the incoming bits +to the decoder's coefficient buffer. This is fast because only Huffman +decoding need be done, not IDCT, upsampling, colorspace conversion, etc. +The IJG decoder library allows the application to switch dynamically between +displaying the image and simply absorbing the incoming bits. A properly +coded application can automatically adapt the number of display passes to +suit the time available as the image is received. Also, a final +higher-quality display cycle can be performed from the buffered data after +the end of the file is reached. + +Progressive compression: + +To create a progressive JPEG file (or a multiple-scan sequential JPEG file), +set the scan_info cinfo field to point to an array of scan descriptors, and +perform compression as usual. Instead of constructing your own scan list, +you can call the jpeg_simple_progression() helper routine to create a +recommended progression sequence; this method should be used by all +applications that don't want to get involved in the nitty-gritty of +progressive scan sequence design. (If you want to provide user control of +scan sequences, you may wish to borrow the scan script reading code found +in rdswitch.c, so that you can read scan script files just like cjpeg's.) +When scan_info is not NULL, the compression library will store DCT'd data +into a buffer array as jpeg_write_scanlines() is called, and will emit all +the requested scans during jpeg_finish_compress(). This implies that +multiple-scan output cannot be created with a suspending data destination +manager, since jpeg_finish_compress() does not support suspension. We +should also note that the compressor currently forces Huffman optimization +mode when creating a progressive JPEG file, because the default Huffman +tables are unsuitable for progressive files. + +Progressive decompression: + +When buffered-image mode is not used, the decoder library will read all of +a multi-scan file during jpeg_start_decompress(), so that it can provide a +final decoded image. (Here "multi-scan" means either progressive or +multi-scan sequential.) This makes multi-scan files transparent to the +decoding application. However, existing applications that used suspending +input with version 5 of the IJG library will need to be modified to check +for a suspension return from jpeg_start_decompress(). + +To perform incremental display, an application must use the library's +buffered-image mode. This is described in the next section. + + +Buffered-image mode +------------------- + +In buffered-image mode, the library stores the partially decoded image in a +coefficient buffer, from which it can be read out as many times as desired. +This mode is typically used for incremental display of progressive JPEG files, +but it can be used with any JPEG file. Each scan of a progressive JPEG file +adds more data (more detail) to the buffered image. The application can +display in lockstep with the source file (one display pass per input scan), +or it can allow input processing to outrun display processing. By making +input and display processing run independently, it is possible for the +application to adapt progressive display to a wide range of data transmission +rates. + +The basic control flow for buffered-image decoding is + + jpeg_create_decompress() + set data source + jpeg_read_header() + set overall decompression parameters + cinfo.buffered_image = TRUE; /* select buffered-image mode */ + jpeg_start_decompress() + for (each output pass) { + adjust output decompression parameters if required + jpeg_start_output() /* start a new output pass */ + for (all scanlines in image) { + jpeg_read_scanlines() + display scanlines + } + jpeg_finish_output() /* terminate output pass */ + } + jpeg_finish_decompress() + jpeg_destroy_decompress() + +This differs from ordinary unbuffered decoding in that there is an additional +level of looping. The application can choose how many output passes to make +and how to display each pass. + +The simplest approach to displaying progressive images is to do one display +pass for each scan appearing in the input file. In this case the outer loop +condition is typically + while (! jpeg_input_complete(&cinfo)) +and the start-output call should read + jpeg_start_output(&cinfo, cinfo.input_scan_number); +The second parameter to jpeg_start_output() indicates which scan of the input +file is to be displayed; the scans are numbered starting at 1 for this +purpose. (You can use a loop counter starting at 1 if you like, but using +the library's input scan counter is easier.) The library automatically reads +data as necessary to complete each requested scan, and jpeg_finish_output() +advances to the next scan or end-of-image marker (hence input_scan_number +will be incremented by the time control arrives back at jpeg_start_output()). +With this technique, data is read from the input file only as needed, and +input and output processing run in lockstep. + +After reading the final scan and reaching the end of the input file, the +buffered image remains available; it can be read additional times by +repeating the jpeg_start_output()/jpeg_read_scanlines()/jpeg_finish_output() +sequence. For example, a useful technique is to use fast one-pass color +quantization for display passes made while the image is arriving, followed by +a final display pass using two-pass quantization for highest quality. This +is done by changing the library parameters before the final output pass. +Changing parameters between passes is discussed in detail below. + +In general the last scan of a progressive file cannot be recognized as such +until after it is read, so a post-input display pass is the best approach if +you want special processing in the final pass. + +When done with the image, be sure to call jpeg_finish_decompress() to release +the buffered image (or just use jpeg_destroy_decompress()). + +If input data arrives faster than it can be displayed, the application can +cause the library to decode input data in advance of what's needed to produce +output. This is done by calling the routine jpeg_consume_input(). +The return value is one of the following: + JPEG_REACHED_SOS: reached an SOS marker (the start of a new scan) + JPEG_REACHED_EOI: reached the EOI marker (end of image) + JPEG_ROW_COMPLETED: completed reading one MCU row of compressed data + JPEG_SCAN_COMPLETED: completed reading last MCU row of current scan + JPEG_SUSPENDED: suspended before completing any of the above +(JPEG_SUSPENDED can occur only if a suspending data source is used.) This +routine can be called at any time after initializing the JPEG object. It +reads some additional data and returns when one of the indicated significant +events occurs. (If called after the EOI marker is reached, it will +immediately return JPEG_REACHED_EOI without attempting to read more data.) + +The library's output processing will automatically call jpeg_consume_input() +whenever the output processing overtakes the input; thus, simple lockstep +display requires no direct calls to jpeg_consume_input(). But by adding +calls to jpeg_consume_input(), you can absorb data in advance of what is +being displayed. This has two benefits: + * You can limit buildup of unprocessed data in your input buffer. + * You can eliminate extra display passes by paying attention to the + state of the library's input processing. + +The first of these benefits only requires interspersing calls to +jpeg_consume_input() with your display operations and any other processing +you may be doing. To avoid wasting cycles due to backtracking, it's best to +call jpeg_consume_input() only after a hundred or so new bytes have arrived. +This is discussed further under "I/O suspension", above. (Note: the JPEG +library currently is not thread-safe. You must not call jpeg_consume_input() +from one thread of control if a different library routine is working on the +same JPEG object in another thread.) + +When input arrives fast enough that more than one new scan is available +before you start a new output pass, you may as well skip the output pass +corresponding to the completed scan. This occurs for free if you pass +cinfo.input_scan_number as the target scan number to jpeg_start_output(). +The input_scan_number field is simply the index of the scan currently being +consumed by the input processor. You can ensure that this is up-to-date by +emptying the input buffer just before calling jpeg_start_output(): call +jpeg_consume_input() repeatedly until it returns JPEG_SUSPENDED or +JPEG_REACHED_EOI. + +The target scan number passed to jpeg_start_output() is saved in the +cinfo.output_scan_number field. The library's output processing calls +jpeg_consume_input() whenever the current input scan number and row within +that scan is less than or equal to the current output scan number and row. +Thus, input processing can "get ahead" of the output processing but is not +allowed to "fall behind". You can achieve several different effects by +manipulating this interlock rule. For example, if you pass a target scan +number greater than the current input scan number, the output processor will +wait until that scan starts to arrive before producing any output. (To avoid +an infinite loop, the target scan number is automatically reset to the last +scan number when the end of image is reached. Thus, if you specify a large +target scan number, the library will just absorb the entire input file and +then perform an output pass. This is effectively the same as what +jpeg_start_decompress() does when you don't select buffered-image mode.) +When you pass a target scan number equal to the current input scan number, +the image is displayed no faster than the current input scan arrives. The +final possibility is to pass a target scan number less than the current input +scan number; this disables the input/output interlock and causes the output +processor to simply display whatever it finds in the image buffer, without +waiting for input. (However, the library will not accept a target scan +number less than one, so you can't avoid waiting for the first scan.) + +When data is arriving faster than the output display processing can advance +through the image, jpeg_consume_input() will store data into the buffered +image beyond the point at which the output processing is reading data out +again. If the input arrives fast enough, it may "wrap around" the buffer to +the point where the input is more than one whole scan ahead of the output. +If the output processing simply proceeds through its display pass without +paying attention to the input, the effect seen on-screen is that the lower +part of the image is one or more scans better in quality than the upper part. +Then, when the next output scan is started, you have a choice of what target +scan number to use. The recommended choice is to use the current input scan +number at that time, which implies that you've skipped the output scans +corresponding to the input scans that were completed while you processed the +previous output scan. In this way, the decoder automatically adapts its +speed to the arriving data, by skipping output scans as necessary to keep up +with the arriving data. + +When using this strategy, you'll want to be sure that you perform a final +output pass after receiving all the data; otherwise your last display may not +be full quality across the whole screen. So the right outer loop logic is +something like this: + do { + absorb any waiting input by calling jpeg_consume_input() + final_pass = jpeg_input_complete(&cinfo); + adjust output decompression parameters if required + jpeg_start_output(&cinfo, cinfo.input_scan_number); + ... + jpeg_finish_output() + } while (! final_pass); +rather than quitting as soon as jpeg_input_complete() returns TRUE. This +arrangement makes it simple to use higher-quality decoding parameters +for the final pass. But if you don't want to use special parameters for +the final pass, the right loop logic is like this: + for (;;) { + absorb any waiting input by calling jpeg_consume_input() + jpeg_start_output(&cinfo, cinfo.input_scan_number); + ... + jpeg_finish_output() + if (jpeg_input_complete(&cinfo) && + cinfo.input_scan_number == cinfo.output_scan_number) + break; + } +In this case you don't need to know in advance whether an output pass is to +be the last one, so it's not necessary to have reached EOF before starting +the final output pass; rather, what you want to test is whether the output +pass was performed in sync with the final input scan. This form of the loop +will avoid an extra output pass whenever the decoder is able (or nearly able) +to keep up with the incoming data. + +When the data transmission speed is high, you might begin a display pass, +then find that much or all of the file has arrived before you can complete +the pass. (You can detect this by noting the JPEG_REACHED_EOI return code +from jpeg_consume_input(), or equivalently by testing jpeg_input_complete().) +In this situation you may wish to abort the current display pass and start a +new one using the newly arrived information. To do so, just call +jpeg_finish_output() and then start a new pass with jpeg_start_output(). + +A variant strategy is to abort and restart display if more than one complete +scan arrives during an output pass; this can be detected by noting +JPEG_REACHED_SOS returns and/or examining cinfo.input_scan_number. This +idea should be employed with caution, however, since the display process +might never get to the bottom of the image before being aborted, resulting +in the lower part of the screen being several passes worse than the upper. +In most cases it's probably best to abort an output pass only if the whole +file has arrived and you want to begin the final output pass immediately. + +When receiving data across a communication link, we recommend always using +the current input scan number for the output target scan number; if a +higher-quality final pass is to be done, it should be started (aborting any +incomplete output pass) as soon as the end of file is received. However, +many other strategies are possible. For example, the application can examine +the parameters of the current input scan and decide whether to display it or +not. If the scan contains only chroma data, one might choose not to use it +as the target scan, expecting that the scan will be small and will arrive +quickly. To skip to the next scan, call jpeg_consume_input() until it +returns JPEG_REACHED_SOS or JPEG_REACHED_EOI. Or just use the next higher +number as the target scan for jpeg_start_output(); but that method doesn't +let you inspect the next scan's parameters before deciding to display it. + + +In buffered-image mode, jpeg_start_decompress() never performs input and +thus never suspends. An application that uses input suspension with +buffered-image mode must be prepared for suspension returns from these +routines: +* jpeg_start_output() performs input only if you request 2-pass quantization + and the target scan isn't fully read yet. (This is discussed below.) +* jpeg_read_scanlines(), as always, returns the number of scanlines that it + was able to produce before suspending. +* jpeg_finish_output() will read any markers following the target scan, + up to the end of the file or the SOS marker that begins another scan. + (But it reads no input if jpeg_consume_input() has already reached the + end of the file or a SOS marker beyond the target output scan.) +* jpeg_finish_decompress() will read until the end of file, and thus can + suspend if the end hasn't already been reached (as can be tested by + calling jpeg_input_complete()). +jpeg_start_output(), jpeg_finish_output(), and jpeg_finish_decompress() +all return TRUE if they completed their tasks, FALSE if they had to suspend. +In the event of a FALSE return, the application must load more input data +and repeat the call. Applications that use non-suspending data sources need +not check the return values of these three routines. + + +It is possible to change decoding parameters between output passes in the +buffered-image mode. The decoder library currently supports only very +limited changes of parameters. ONLY THE FOLLOWING parameter changes are +allowed after jpeg_start_decompress() is called: +* dct_method can be changed before each call to jpeg_start_output(). + For example, one could use a fast DCT method for early scans, changing + to a higher quality method for the final scan. +* dither_mode can be changed before each call to jpeg_start_output(); + of course this has no impact if not using color quantization. Typically + one would use ordered dither for initial passes, then switch to + Floyd-Steinberg dither for the final pass. Caution: changing dither mode + can cause more memory to be allocated by the library. Although the amount + of memory involved is not large (a scanline or so), it may cause the + initial max_memory_to_use specification to be exceeded, which in the worst + case would result in an out-of-memory failure. +* do_block_smoothing can be changed before each call to jpeg_start_output(). + This setting is relevant only when decoding a progressive JPEG image. + During the first DC-only scan, block smoothing provides a very "fuzzy" look + instead of the very "blocky" look seen without it; which is better seems a + matter of personal taste. But block smoothing is nearly always a win + during later stages, especially when decoding a successive-approximation + image: smoothing helps to hide the slight blockiness that otherwise shows + up on smooth gradients until the lowest coefficient bits are sent. +* Color quantization mode can be changed under the rules described below. + You *cannot* change between full-color and quantized output (because that + would alter the required I/O buffer sizes), but you can change which + quantization method is used. + +When generating color-quantized output, changing quantization method is a +very useful way of switching between high-speed and high-quality display. +The library allows you to change among its three quantization methods: +1. Single-pass quantization to a fixed color cube. + Selected by cinfo.two_pass_quantize = FALSE and cinfo.colormap = NULL. +2. Single-pass quantization to an application-supplied colormap. + Selected by setting cinfo.colormap to point to the colormap (the value of + two_pass_quantize is ignored); also set cinfo.actual_number_of_colors. +3. Two-pass quantization to a colormap chosen specifically for the image. + Selected by cinfo.two_pass_quantize = TRUE and cinfo.colormap = NULL. + (This is the default setting selected by jpeg_read_header, but it is + probably NOT what you want for the first pass of progressive display!) +These methods offer successively better quality and lesser speed. However, +only the first method is available for quantizing in non-RGB color spaces. + +IMPORTANT: because the different quantizer methods have very different +working-storage requirements, the library requires you to indicate which +one(s) you intend to use before you call jpeg_start_decompress(). (If we did +not require this, the max_memory_to_use setting would be a complete fiction.) +You do this by setting one or more of these three cinfo fields to TRUE: + enable_1pass_quant Fixed color cube colormap + enable_external_quant Externally-supplied colormap + enable_2pass_quant Two-pass custom colormap +All three are initialized FALSE by jpeg_read_header(). But +jpeg_start_decompress() automatically sets TRUE the one selected by the +current two_pass_quantize and colormap settings, so you only need to set the +enable flags for any other quantization methods you plan to change to later. + +After setting the enable flags correctly at jpeg_start_decompress() time, you +can change to any enabled quantization method by setting two_pass_quantize +and colormap properly just before calling jpeg_start_output(). The following +special rules apply: +1. You must explicitly set cinfo.colormap to NULL when switching to 1-pass + or 2-pass mode from a different mode, or when you want the 2-pass + quantizer to be re-run to generate a new colormap. +2. To switch to an external colormap, or to change to a different external + colormap than was used on the prior pass, you must call + jpeg_new_colormap() after setting cinfo.colormap. +NOTE: if you want to use the same colormap as was used in the prior pass, +you should not do either of these things. This will save some nontrivial +switchover costs. +(These requirements exist because cinfo.colormap will always be non-NULL +after completing a prior output pass, since both the 1-pass and 2-pass +quantizers set it to point to their output colormaps. Thus you have to +do one of these two things to notify the library that something has changed. +Yup, it's a bit klugy, but it's necessary to do it this way for backwards +compatibility.) + +Note that in buffered-image mode, the library generates any requested colormap +during jpeg_start_output(), not during jpeg_start_decompress(). + +When using two-pass quantization, jpeg_start_output() makes a pass over the +buffered image to determine the optimum color map; it therefore may take a +significant amount of time, whereas ordinarily it does little work. The +progress monitor hook is called during this pass, if defined. It is also +important to realize that if the specified target scan number is greater than +or equal to the current input scan number, jpeg_start_output() will attempt +to consume input as it makes this pass. If you use a suspending data source, +you need to check for a FALSE return from jpeg_start_output() under these +conditions. The combination of 2-pass quantization and a not-yet-fully-read +target scan is the only case in which jpeg_start_output() will consume input. + + +Application authors who support buffered-image mode may be tempted to use it +for all JPEG images, even single-scan ones. This will work, but it is +inefficient: there is no need to create an image-sized coefficient buffer for +single-scan images. Requesting buffered-image mode for such an image wastes +memory. Worse, it can cost time on large images, since the buffered data has +to be swapped out or written to a temporary file. If you are concerned about +maximum performance on baseline JPEG files, you should use buffered-image +mode only when the incoming file actually has multiple scans. This can be +tested by calling jpeg_has_multiple_scans(), which will return a correct +result at any time after jpeg_read_header() completes. + +It is also worth noting that when you use jpeg_consume_input() to let input +processing get ahead of output processing, the resulting pattern of access to +the coefficient buffer is quite nonsequential. It's best to use the memory +manager jmemnobs.c if you can (ie, if you have enough real or virtual main +memory). If not, at least make sure that max_memory_to_use is set as high as +possible. If the JPEG memory manager has to use a temporary file, you will +probably see a lot of disk traffic and poor performance. (This could be +improved with additional work on the memory manager, but we haven't gotten +around to it yet.) + +In some applications it may be convenient to use jpeg_consume_input() for all +input processing, including reading the initial markers; that is, you may +wish to call jpeg_consume_input() instead of jpeg_read_header() during +startup. This works, but note that you must check for JPEG_REACHED_SOS and +JPEG_REACHED_EOI return codes as the equivalent of jpeg_read_header's codes. +Once the first SOS marker has been reached, you must call +jpeg_start_decompress() before jpeg_consume_input() will consume more input; +it'll just keep returning JPEG_REACHED_SOS until you do. If you read a +tables-only file this way, jpeg_consume_input() will return JPEG_REACHED_EOI +without ever returning JPEG_REACHED_SOS; be sure to check for this case. +If this happens, the decompressor will not read any more input until you call +jpeg_abort() to reset it. It is OK to call jpeg_consume_input() even when not +using buffered-image mode, but in that case it's basically a no-op after the +initial markers have been read: it will just return JPEG_SUSPENDED. + + +Abbreviated datastreams and multiple images +------------------------------------------- + +A JPEG compression or decompression object can be reused to process multiple +images. This saves a small amount of time per image by eliminating the +"create" and "destroy" operations, but that isn't the real purpose of the +feature. Rather, reuse of an object provides support for abbreviated JPEG +datastreams. Object reuse can also simplify processing a series of images in +a single input or output file. This section explains these features. + +A JPEG file normally contains several hundred bytes worth of quantization +and Huffman tables. In a situation where many images will be stored or +transmitted with identical tables, this may represent an annoying overhead. +The JPEG standard therefore permits tables to be omitted. The standard +defines three classes of JPEG datastreams: + * "Interchange" datastreams contain an image and all tables needed to decode + the image. These are the usual kind of JPEG file. + * "Abbreviated image" datastreams contain an image, but are missing some or + all of the tables needed to decode that image. + * "Abbreviated table specification" (henceforth "tables-only") datastreams + contain only table specifications. +To decode an abbreviated image, it is necessary to load the missing table(s) +into the decoder beforehand. This can be accomplished by reading a separate +tables-only file. A variant scheme uses a series of images in which the first +image is an interchange (complete) datastream, while subsequent ones are +abbreviated and rely on the tables loaded by the first image. It is assumed +that once the decoder has read a table, it will remember that table until a +new definition for the same table number is encountered. + +It is the application designer's responsibility to figure out how to associate +the correct tables with an abbreviated image. While abbreviated datastreams +can be useful in a closed environment, their use is strongly discouraged in +any situation where data exchange with other applications might be needed. +Caveat designer. + +The JPEG library provides support for reading and writing any combination of +tables-only datastreams and abbreviated images. In both compression and +decompression objects, a quantization or Huffman table will be retained for +the lifetime of the object, unless it is overwritten by a new table definition. + + +To create abbreviated image datastreams, it is only necessary to tell the +compressor not to emit some or all of the tables it is using. Each +quantization and Huffman table struct contains a boolean field "sent_table", +which normally is initialized to FALSE. For each table used by the image, the +header-writing process emits the table and sets sent_table = TRUE unless it is +already TRUE. (In normal usage, this prevents outputting the same table +definition multiple times, as would otherwise occur because the chroma +components typically share tables.) Thus, setting this field to TRUE before +calling jpeg_start_compress() will prevent the table from being written at +all. + +If you want to create a "pure" abbreviated image file containing no tables, +just call "jpeg_suppress_tables(&cinfo, TRUE)" after constructing all the +tables. If you want to emit some but not all tables, you'll need to set the +individual sent_table fields directly. + +To create an abbreviated image, you must also call jpeg_start_compress() +with a second parameter of FALSE, not TRUE. Otherwise jpeg_start_compress() +will force all the sent_table fields to FALSE. (This is a safety feature to +prevent abbreviated images from being created accidentally.) + +To create a tables-only file, perform the same parameter setup that you +normally would, but instead of calling jpeg_start_compress() and so on, call +jpeg_write_tables(&cinfo). This will write an abbreviated datastream +containing only SOI, DQT and/or DHT markers, and EOI. All the quantization +and Huffman tables that are currently defined in the compression object will +be emitted unless their sent_tables flag is already TRUE, and then all the +sent_tables flags will be set TRUE. + +A sure-fire way to create matching tables-only and abbreviated image files +is to proceed as follows: + + create JPEG compression object + set JPEG parameters + set destination to tables-only file + jpeg_write_tables(&cinfo); + set destination to image file + jpeg_start_compress(&cinfo, FALSE); + write data... + jpeg_finish_compress(&cinfo); + +Since the JPEG parameters are not altered between writing the table file and +the abbreviated image file, the same tables are sure to be used. Of course, +you can repeat the jpeg_start_compress() ... jpeg_finish_compress() sequence +many times to produce many abbreviated image files matching the table file. + +You cannot suppress output of the computed Huffman tables when Huffman +optimization is selected. (If you could, there'd be no way to decode the +image...) Generally, you don't want to set optimize_coding = TRUE when +you are trying to produce abbreviated files. + +In some cases you might want to compress an image using tables which are +not stored in the application, but are defined in an interchange or +tables-only file readable by the application. This can be done by setting up +a JPEG decompression object to read the specification file, then copying the +tables into your compression object. See jpeg_copy_critical_parameters() +for an example of copying quantization tables. + + +To read abbreviated image files, you simply need to load the proper tables +into the decompression object before trying to read the abbreviated image. +If the proper tables are stored in the application program, you can just +allocate the table structs and fill in their contents directly. For example, +to load a fixed quantization table into table slot "n": + + if (cinfo.quant_tbl_ptrs[n] == NULL) + cinfo.quant_tbl_ptrs[n] = jpeg_alloc_quant_table((j_common_ptr) &cinfo); + quant_ptr = cinfo.quant_tbl_ptrs[n]; /* quant_ptr is JQUANT_TBL* */ + for (i = 0; i < 64; i++) { + /* Qtable[] is desired quantization table, in natural array order */ + quant_ptr->quantval[i] = Qtable[i]; + } + +Code to load a fixed Huffman table is typically (for AC table "n"): + + if (cinfo.ac_huff_tbl_ptrs[n] == NULL) + cinfo.ac_huff_tbl_ptrs[n] = jpeg_alloc_huff_table((j_common_ptr) &cinfo); + huff_ptr = cinfo.ac_huff_tbl_ptrs[n]; /* huff_ptr is JHUFF_TBL* */ + for (i = 1; i <= 16; i++) { + /* counts[i] is number of Huffman codes of length i bits, i=1..16 */ + huff_ptr->bits[i] = counts[i]; + } + for (i = 0; i < 256; i++) { + /* symbols[] is the list of Huffman symbols, in code-length order */ + huff_ptr->huffval[i] = symbols[i]; + } + +(Note that trying to set cinfo.quant_tbl_ptrs[n] to point directly at a +constant JQUANT_TBL object is not safe. If the incoming file happened to +contain a quantization table definition, your master table would get +overwritten! Instead allocate a working table copy and copy the master table +into it, as illustrated above. Ditto for Huffman tables, of course.) + +You might want to read the tables from a tables-only file, rather than +hard-wiring them into your application. The jpeg_read_header() call is +sufficient to read a tables-only file. You must pass a second parameter of +FALSE to indicate that you do not require an image to be present. Thus, the +typical scenario is + + create JPEG decompression object + set source to tables-only file + jpeg_read_header(&cinfo, FALSE); + set source to abbreviated image file + jpeg_read_header(&cinfo, TRUE); + set decompression parameters + jpeg_start_decompress(&cinfo); + read data... + jpeg_finish_decompress(&cinfo); + +In some cases, you may want to read a file without knowing whether it contains +an image or just tables. In that case, pass FALSE and check the return value +from jpeg_read_header(): it will be JPEG_HEADER_OK if an image was found, +JPEG_HEADER_TABLES_ONLY if only tables were found. (A third return value, +JPEG_SUSPENDED, is possible when using a suspending data source manager.) +Note that jpeg_read_header() will not complain if you read an abbreviated +image for which you haven't loaded the missing tables; the missing-table check +occurs later, in jpeg_start_decompress(). + + +It is possible to read a series of images from a single source file by +repeating the jpeg_read_header() ... jpeg_finish_decompress() sequence, +without releasing/recreating the JPEG object or the data source module. +(If you did reinitialize, any partial bufferload left in the data source +buffer at the end of one image would be discarded, causing you to lose the +start of the next image.) When you use this method, stored tables are +automatically carried forward, so some of the images can be abbreviated images +that depend on tables from earlier images. + +If you intend to write a series of images into a single destination file, +you might want to make a specialized data destination module that doesn't +flush the output buffer at term_destination() time. This would speed things +up by some trifling amount. Of course, you'd need to remember to flush the +buffer after the last image. You can make the later images be abbreviated +ones by passing FALSE to jpeg_start_compress(). + + +Special markers +--------------- + +Some applications may need to insert or extract special data in the JPEG +datastream. The JPEG standard provides marker types "COM" (comment) and +"APP0" through "APP15" (application) to hold application-specific data. +Unfortunately, the use of these markers is not specified by the standard. +COM markers are fairly widely used to hold user-supplied text. The JFIF file +format spec uses APP0 markers with specified initial strings to hold certain +data. Adobe applications use APP14 markers beginning with the string "Adobe" +for miscellaneous data. Other APPn markers are rarely seen, but might +contain almost anything. + +If you wish to store user-supplied text, we recommend you use COM markers +and place readable 7-bit ASCII text in them. Newline conventions are not +standardized --- expect to find LF (Unix style), CR/LF (DOS style), or CR +(Mac style). A robust COM reader should be able to cope with random binary +garbage, including nulls, since some applications generate COM markers +containing non-ASCII junk. (But yours should not be one of them.) + +For program-supplied data, use an APPn marker, and be sure to begin it with an +identifying string so that you can tell whether the marker is actually yours. +It's probably best to avoid using APP0 or APP14 for any private markers. +(NOTE: the upcoming SPIFF standard will use APP8 markers; we recommend you +not use APP8 markers for any private purposes, either.) + +Keep in mind that at most 65533 bytes can be put into one marker, but you +can have as many markers as you like. + +By default, the IJG compression library will write a JFIF APP0 marker if the +selected JPEG colorspace is grayscale or YCbCr, or an Adobe APP14 marker if +the selected colorspace is RGB, CMYK, or YCCK. You can disable this, but +we don't recommend it. The decompression library will recognize JFIF and +Adobe markers and will set the JPEG colorspace properly when one is found. + + +You can write special markers immediately following the datastream header by +calling jpeg_write_marker() after jpeg_start_compress() and before the first +call to jpeg_write_scanlines(). When you do this, the markers appear after +the SOI and the JFIF APP0 and Adobe APP14 markers (if written), but before +all else. Specify the marker type parameter as "JPEG_COM" for COM or +"JPEG_APP0 + n" for APPn. (Actually, jpeg_write_marker will let you write +any marker type, but we don't recommend writing any other kinds of marker.) +For example, to write a user comment string pointed to by comment_text: + jpeg_write_marker(cinfo, JPEG_COM, comment_text, strlen(comment_text)); + +If it's not convenient to store all the marker data in memory at once, +you can instead call jpeg_write_m_header() followed by multiple calls to +jpeg_write_m_byte(). If you do it this way, it's your responsibility to +call jpeg_write_m_byte() exactly the number of times given in the length +parameter to jpeg_write_m_header(). (This method lets you empty the +output buffer partway through a marker, which might be important when +using a suspending data destination module. In any case, if you are using +a suspending destination, you should flush its buffer after inserting +any special markers. See "I/O suspension".) + +Or, if you prefer to synthesize the marker byte sequence yourself, +you can just cram it straight into the data destination module. + +If you are writing JFIF 1.02 extension markers (thumbnail images), don't +forget to set cinfo.JFIF_minor_version = 2 so that the encoder will write the +correct JFIF version number in the JFIF header marker. The library's default +is to write version 1.01, but that's wrong if you insert any 1.02 extension +markers. (We could probably get away with just defaulting to 1.02, but there +used to be broken decoders that would complain about unknown minor version +numbers. To reduce compatibility risks it's safest not to write 1.02 unless +you are actually using 1.02 extensions.) + + +When reading, two methods of handling special markers are available: +1. You can ask the library to save the contents of COM and/or APPn markers +into memory, and then examine them at your leisure afterwards. +2. You can supply your own routine to process COM and/or APPn markers +on-the-fly as they are read. +The first method is simpler to use, especially if you are using a suspending +data source; writing a marker processor that copes with input suspension is +not easy (consider what happens if the marker is longer than your available +input buffer). However, the second method conserves memory since the marker +data need not be kept around after it's been processed. + +For either method, you'd normally set up marker handling after creating a +decompression object and before calling jpeg_read_header(), because the +markers of interest will typically be near the head of the file and so will +be scanned by jpeg_read_header. Once you've established a marker handling +method, it will be used for the life of that decompression object +(potentially many datastreams), unless you change it. Marker handling is +determined separately for COM markers and for each APPn marker code. + + +To save the contents of special markers in memory, call + jpeg_save_markers(cinfo, marker_code, length_limit) +where marker_code is the marker type to save, JPEG_COM or JPEG_APP0+n. +(To arrange to save all the special marker types, you need to call this +routine 17 times, for COM and APP0-APP15.) If the incoming marker is longer +than length_limit data bytes, only length_limit bytes will be saved; this +parameter allows you to avoid chewing up memory when you only need to see the +first few bytes of a potentially large marker. If you want to save all the +data, set length_limit to 0xFFFF; that is enough since marker lengths are only +16 bits. As a special case, setting length_limit to 0 prevents that marker +type from being saved at all. (That is the default behavior, in fact.) + +After jpeg_read_header() completes, you can examine the special markers by +following the cinfo->marker_list pointer chain. All the special markers in +the file appear in this list, in order of their occurrence in the file (but +omitting any markers of types you didn't ask for). Both the original data +length and the saved data length are recorded for each list entry; the latter +will not exceed length_limit for the particular marker type. Note that these +lengths exclude the marker length word, whereas the stored representation +within the JPEG file includes it. (Hence the maximum data length is really +only 65533.) + +It is possible that additional special markers appear in the file beyond the +SOS marker at which jpeg_read_header stops; if so, the marker list will be +extended during reading of the rest of the file. This is not expected to be +common, however. If you are short on memory you may want to reset the length +limit to zero for all marker types after finishing jpeg_read_header, to +ensure that the max_memory_to_use setting cannot be exceeded due to addition +of later markers. + +The marker list remains stored until you call jpeg_finish_decompress or +jpeg_abort, at which point the memory is freed and the list is set to empty. +(jpeg_destroy also releases the storage, of course.) + +Note that the library is internally interested in APP0 and APP14 markers; +if you try to set a small nonzero length limit on these types, the library +will silently force the length up to the minimum it wants. (But you can set +a zero length limit to prevent them from being saved at all.) Also, in a +16-bit environment, the maximum length limit may be constrained to less than +65533 by malloc() limitations. It is therefore best not to assume that the +effective length limit is exactly what you set it to be. + + +If you want to supply your own marker-reading routine, you do it by calling +jpeg_set_marker_processor(). A marker processor routine must have the +signature + boolean jpeg_marker_parser_method (j_decompress_ptr cinfo) +Although the marker code is not explicitly passed, the routine can find it +in cinfo->unread_marker. At the time of call, the marker proper has been +read from the data source module. The processor routine is responsible for +reading the marker length word and the remaining parameter bytes, if any. +Return TRUE to indicate success. (FALSE should be returned only if you are +using a suspending data source and it tells you to suspend. See the standard +marker processors in jdmarker.c for appropriate coding methods if you need to +use a suspending data source.) + +If you override the default APP0 or APP14 processors, it is up to you to +recognize JFIF and Adobe markers if you want colorspace recognition to occur +properly. We recommend copying and extending the default processors if you +want to do that. (A better idea is to save these marker types for later +examination by calling jpeg_save_markers(); that method doesn't interfere +with the library's own processing of these markers.) + +jpeg_set_marker_processor() and jpeg_save_markers() are mutually exclusive +--- if you call one it overrides any previous call to the other, for the +particular marker type specified. + +A simple example of an external COM processor can be found in djpeg.c. +Also, see jpegtran.c for an example of using jpeg_save_markers. + + +Raw (downsampled) image data +---------------------------- + +Some applications need to supply already-downsampled image data to the JPEG +compressor, or to receive raw downsampled data from the decompressor. The +library supports this requirement by allowing the application to write or +read raw data, bypassing the normal preprocessing or postprocessing steps. +The interface is different from the standard one and is somewhat harder to +use. If your interest is merely in bypassing color conversion, we recommend +that you use the standard interface and simply set jpeg_color_space = +in_color_space (or jpeg_color_space = out_color_space for decompression). +The mechanism described in this section is necessary only to supply or +receive downsampled image data, in which not all components have the same +dimensions. + + +To compress raw data, you must supply the data in the colorspace to be used +in the JPEG file (please read the earlier section on Special color spaces) +and downsampled to the sampling factors specified in the JPEG parameters. +You must supply the data in the format used internally by the JPEG library, +namely a JSAMPIMAGE array. This is an array of pointers to two-dimensional +arrays, each of type JSAMPARRAY. Each 2-D array holds the values for one +color component. This structure is necessary since the components are of +different sizes. If the image dimensions are not a multiple of the MCU size, +you must also pad the data correctly (usually, this is done by replicating +the last column and/or row). The data must be padded to a multiple of a DCT +block in each component: that is, each downsampled row must contain a +multiple of 8 valid samples, and there must be a multiple of 8 sample rows +for each component. (For applications such as conversion of digital TV +images, the standard image size is usually a multiple of the DCT block size, +so that no padding need actually be done.) + +The procedure for compression of raw data is basically the same as normal +compression, except that you call jpeg_write_raw_data() in place of +jpeg_write_scanlines(). Before calling jpeg_start_compress(), you must do +the following: + * Set cinfo->raw_data_in to TRUE. (It is set FALSE by jpeg_set_defaults().) + This notifies the library that you will be supplying raw data. + * Ensure jpeg_color_space is correct --- an explicit jpeg_set_colorspace() + call is a good idea. Note that since color conversion is bypassed, + in_color_space is ignored, except that jpeg_set_defaults() uses it to + choose the default jpeg_color_space setting. + * Ensure the sampling factors, cinfo->comp_info[i].h_samp_factor and + cinfo->comp_info[i].v_samp_factor, are correct. Since these indicate the + dimensions of the data you are supplying, it's wise to set them + explicitly, rather than assuming the library's defaults are what you want. + +To pass raw data to the library, call jpeg_write_raw_data() in place of +jpeg_write_scanlines(). The two routines work similarly except that +jpeg_write_raw_data takes a JSAMPIMAGE data array rather than JSAMPARRAY. +The scanlines count passed to and returned from jpeg_write_raw_data is +measured in terms of the component with the largest v_samp_factor. + +jpeg_write_raw_data() processes one MCU row per call, which is to say +v_samp_factor*DCTSIZE sample rows of each component. The passed num_lines +value must be at least max_v_samp_factor*DCTSIZE, and the return value will +be exactly that amount (or possibly some multiple of that amount, in future +library versions). This is true even on the last call at the bottom of the +image; don't forget to pad your data as necessary. + +The required dimensions of the supplied data can be computed for each +component as + cinfo->comp_info[i].width_in_blocks*DCTSIZE samples per row + cinfo->comp_info[i].height_in_blocks*DCTSIZE rows in image +after jpeg_start_compress() has initialized those fields. If the valid data +is smaller than this, it must be padded appropriately. For some sampling +factors and image sizes, additional dummy DCT blocks are inserted to make +the image a multiple of the MCU dimensions. The library creates such dummy +blocks itself; it does not read them from your supplied data. Therefore you +need never pad by more than DCTSIZE samples. An example may help here. +Assume 2h2v downsampling of YCbCr data, that is + cinfo->comp_info[0].h_samp_factor = 2 for Y + cinfo->comp_info[0].v_samp_factor = 2 + cinfo->comp_info[1].h_samp_factor = 1 for Cb + cinfo->comp_info[1].v_samp_factor = 1 + cinfo->comp_info[2].h_samp_factor = 1 for Cr + cinfo->comp_info[2].v_samp_factor = 1 +and suppose that the nominal image dimensions (cinfo->image_width and +cinfo->image_height) are 101x101 pixels. Then jpeg_start_compress() will +compute downsampled_width = 101 and width_in_blocks = 13 for Y, +downsampled_width = 51 and width_in_blocks = 7 for Cb and Cr (and the same +for the height fields). You must pad the Y data to at least 13*8 = 104 +columns and rows, the Cb/Cr data to at least 7*8 = 56 columns and rows. The +MCU height is max_v_samp_factor = 2 DCT rows so you must pass at least 16 +scanlines on each call to jpeg_write_raw_data(), which is to say 16 actual +sample rows of Y and 8 each of Cb and Cr. A total of 7 MCU rows are needed, +so you must pass a total of 7*16 = 112 "scanlines". The last DCT block row +of Y data is dummy, so it doesn't matter what you pass for it in the data +arrays, but the scanlines count must total up to 112 so that all of the Cb +and Cr data gets passed. + +Output suspension is supported with raw-data compression: if the data +destination module suspends, jpeg_write_raw_data() will return 0. +In this case the same data rows must be passed again on the next call. + + +Decompression with raw data output implies bypassing all postprocessing: +you cannot ask for rescaling or color quantization, for instance. More +seriously, you must deal with the color space and sampling factors present in +the incoming file. If your application only handles, say, 2h1v YCbCr data, +you must check for and fail on other color spaces or other sampling factors. +The library will not convert to a different color space for you. + +To obtain raw data output, set cinfo->raw_data_out = TRUE before +jpeg_start_decompress() (it is set FALSE by jpeg_read_header()). Be sure to +verify that the color space and sampling factors are ones you can handle. +Then call jpeg_read_raw_data() in place of jpeg_read_scanlines(). The +decompression process is otherwise the same as usual. + +jpeg_read_raw_data() returns one MCU row per call, and thus you must pass a +buffer of at least max_v_samp_factor*DCTSIZE scanlines (scanline counting is +the same as for raw-data compression). The buffer you pass must be large +enough to hold the actual data plus padding to DCT-block boundaries. As with +compression, any entirely dummy DCT blocks are not processed so you need not +allocate space for them, but the total scanline count includes them. The +above example of computing buffer dimensions for raw-data compression is +equally valid for decompression. + +Input suspension is supported with raw-data decompression: if the data source +module suspends, jpeg_read_raw_data() will return 0. You can also use +buffered-image mode to read raw data in multiple passes. + + +Really raw data: DCT coefficients +--------------------------------- + +It is possible to read or write the contents of a JPEG file as raw DCT +coefficients. This facility is mainly intended for use in lossless +transcoding between different JPEG file formats. Other possible applications +include lossless cropping of a JPEG image, lossless reassembly of a +multi-strip or multi-tile TIFF/JPEG file into a single JPEG datastream, etc. + +To read the contents of a JPEG file as DCT coefficients, open the file and do +jpeg_read_header() as usual. But instead of calling jpeg_start_decompress() +and jpeg_read_scanlines(), call jpeg_read_coefficients(). This will read the +entire image into a set of virtual coefficient-block arrays, one array per +component. The return value is a pointer to an array of virtual-array +descriptors. Each virtual array can be accessed directly using the JPEG +memory manager's access_virt_barray method (see Memory management, below, +and also read structure.doc's discussion of virtual array handling). Or, +for simple transcoding to a different JPEG file format, the array list can +just be handed directly to jpeg_write_coefficients(). + +Each block in the block arrays contains quantized coefficient values in +normal array order (not JPEG zigzag order). The block arrays contain only +DCT blocks containing real data; any entirely-dummy blocks added to fill out +interleaved MCUs at the right or bottom edges of the image are discarded +during reading and are not stored in the block arrays. (The size of each +block array can be determined from the width_in_blocks and height_in_blocks +fields of the component's comp_info entry.) This is also the data format +expected by jpeg_write_coefficients(). + +When you are done using the virtual arrays, call jpeg_finish_decompress() +to release the array storage and return the decompression object to an idle +state; or just call jpeg_destroy() if you don't need to reuse the object. + +If you use a suspending data source, jpeg_read_coefficients() will return +NULL if it is forced to suspend; a non-NULL return value indicates successful +completion. You need not test for a NULL return value when using a +non-suspending data source. + +It is also possible to call jpeg_read_coefficients() to obtain access to the +decoder's coefficient arrays during a normal decode cycle in buffered-image +mode. This frammish might be useful for progressively displaying an incoming +image and then re-encoding it without loss. To do this, decode in buffered- +image mode as discussed previously, then call jpeg_read_coefficients() after +the last jpeg_finish_output() call. The arrays will be available for your use +until you call jpeg_finish_decompress(). + + +To write the contents of a JPEG file as DCT coefficients, you must provide +the DCT coefficients stored in virtual block arrays. You can either pass +block arrays read from an input JPEG file by jpeg_read_coefficients(), or +allocate virtual arrays from the JPEG compression object and fill them +yourself. In either case, jpeg_write_coefficients() is substituted for +jpeg_start_compress() and jpeg_write_scanlines(). Thus the sequence is + * Create compression object + * Set all compression parameters as necessary + * Request virtual arrays if needed + * jpeg_write_coefficients() + * jpeg_finish_compress() + * Destroy or re-use compression object +jpeg_write_coefficients() is passed a pointer to an array of virtual block +array descriptors; the number of arrays is equal to cinfo.num_components. + +The virtual arrays need only have been requested, not realized, before +jpeg_write_coefficients() is called. A side-effect of +jpeg_write_coefficients() is to realize any virtual arrays that have been +requested from the compression object's memory manager. Thus, when obtaining +the virtual arrays from the compression object, you should fill the arrays +after calling jpeg_write_coefficients(). The data is actually written out +when you call jpeg_finish_compress(); jpeg_write_coefficients() only writes +the file header. + +When writing raw DCT coefficients, it is crucial that the JPEG quantization +tables and sampling factors match the way the data was encoded, or the +resulting file will be invalid. For transcoding from an existing JPEG file, +we recommend using jpeg_copy_critical_parameters(). This routine initializes +all the compression parameters to default values (like jpeg_set_defaults()), +then copies the critical information from a source decompression object. +The decompression object should have just been used to read the entire +JPEG input file --- that is, it should be awaiting jpeg_finish_decompress(). + +jpeg_write_coefficients() marks all tables stored in the compression object +as needing to be written to the output file (thus, it acts like +jpeg_start_compress(cinfo, TRUE)). This is for safety's sake, to avoid +emitting abbreviated JPEG files by accident. If you really want to emit an +abbreviated JPEG file, call jpeg_suppress_tables(), or set the tables' +individual sent_table flags, between calling jpeg_write_coefficients() and +jpeg_finish_compress(). + + +Progress monitoring +------------------- + +Some applications may need to regain control from the JPEG library every so +often. The typical use of this feature is to produce a percent-done bar or +other progress display. (For a simple example, see cjpeg.c or djpeg.c.) +Although you do get control back frequently during the data-transferring pass +(the jpeg_read_scanlines or jpeg_write_scanlines loop), any additional passes +will occur inside jpeg_finish_compress or jpeg_start_decompress; those +routines may take a long time to execute, and you don't get control back +until they are done. + +You can define a progress-monitor routine which will be called periodically +by the library. No guarantees are made about how often this call will occur, +so we don't recommend you use it for mouse tracking or anything like that. +At present, a call will occur once per MCU row, scanline, or sample row +group, whichever unit is convenient for the current processing mode; so the +wider the image, the longer the time between calls. During the data +transferring pass, only one call occurs per call of jpeg_read_scanlines or +jpeg_write_scanlines, so don't pass a large number of scanlines at once if +you want fine resolution in the progress count. (If you really need to use +the callback mechanism for time-critical tasks like mouse tracking, you could +insert additional calls inside some of the library's inner loops.) + +To establish a progress-monitor callback, create a struct jpeg_progress_mgr, +fill in its progress_monitor field with a pointer to your callback routine, +and set cinfo->progress to point to the struct. The callback will be called +whenever cinfo->progress is non-NULL. (This pointer is set to NULL by +jpeg_create_compress or jpeg_create_decompress; the library will not change +it thereafter. So if you allocate dynamic storage for the progress struct, +make sure it will live as long as the JPEG object does. Allocating from the +JPEG memory manager with lifetime JPOOL_PERMANENT will work nicely.) You +can use the same callback routine for both compression and decompression. + +The jpeg_progress_mgr struct contains four fields which are set by the library: + long pass_counter; /* work units completed in this pass */ + long pass_limit; /* total number of work units in this pass */ + int completed_passes; /* passes completed so far */ + int total_passes; /* total number of passes expected */ +During any one pass, pass_counter increases from 0 up to (not including) +pass_limit; the step size is usually but not necessarily 1. The pass_limit +value may change from one pass to another. The expected total number of +passes is in total_passes, and the number of passes already completed is in +completed_passes. Thus the fraction of work completed may be estimated as + completed_passes + (pass_counter/pass_limit) + -------------------------------------------- + total_passes +ignoring the fact that the passes may not be equal amounts of work. + +When decompressing, pass_limit can even change within a pass, because it +depends on the number of scans in the JPEG file, which isn't always known in +advance. The computed fraction-of-work-done may jump suddenly (if the library +discovers it has overestimated the number of scans) or even decrease (in the +opposite case). It is not wise to put great faith in the work estimate. + +When using the decompressor's buffered-image mode, the progress monitor work +estimate is likely to be completely unhelpful, because the library has no way +to know how many output passes will be demanded of it. Currently, the library +sets total_passes based on the assumption that there will be one more output +pass if the input file end hasn't yet been read (jpeg_input_complete() isn't +TRUE), but no more output passes if the file end has been reached when the +output pass is started. This means that total_passes will rise as additional +output passes are requested. If you have a way of determining the input file +size, estimating progress based on the fraction of the file that's been read +will probably be more useful than using the library's value. + + +Memory management +----------------- + +This section covers some key facts about the JPEG library's built-in memory +manager. For more info, please read structure.doc's section about the memory +manager, and consult the source code if necessary. + +All memory and temporary file allocation within the library is done via the +memory manager. If necessary, you can replace the "back end" of the memory +manager to control allocation yourself (for example, if you don't want the +library to use malloc() and free() for some reason). + +Some data is allocated "permanently" and will not be freed until the JPEG +object is destroyed. Most data is allocated "per image" and is freed by +jpeg_finish_compress, jpeg_finish_decompress, or jpeg_abort. You can call the +memory manager yourself to allocate structures that will automatically be +freed at these times. Typical code for this is + ptr = (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, size); +Use JPOOL_PERMANENT to get storage that lasts as long as the JPEG object. +Use alloc_large instead of alloc_small for anything bigger than a few Kbytes. +There are also alloc_sarray and alloc_barray routines that automatically +build 2-D sample or block arrays. + +The library's minimum space requirements to process an image depend on the +image's width, but not on its height, because the library ordinarily works +with "strip" buffers that are as wide as the image but just a few rows high. +Some operating modes (eg, two-pass color quantization) require full-image +buffers. Such buffers are treated as "virtual arrays": only the current strip +need be in memory, and the rest can be swapped out to a temporary file. + +If you use the simplest memory manager back end (jmemnobs.c), then no +temporary files are used; virtual arrays are simply malloc()'d. Images bigger +than memory can be processed only if your system supports virtual memory. +The other memory manager back ends support temporary files of various flavors +and thus work in machines without virtual memory. They may also be useful on +Unix machines if you need to process images that exceed available swap space. + +When using temporary files, the library will make the in-memory buffers for +its virtual arrays just big enough to stay within a "maximum memory" setting. +Your application can set this limit by setting cinfo->mem->max_memory_to_use +after creating the JPEG object. (Of course, there is still a minimum size for +the buffers, so the max-memory setting is effective only if it is bigger than +the minimum space needed.) If you allocate any large structures yourself, you +must allocate them before jpeg_start_compress() or jpeg_start_decompress() in +order to have them counted against the max memory limit. Also keep in mind +that space allocated with alloc_small() is ignored, on the assumption that +it's too small to be worth worrying about; so a reasonable safety margin +should be left when setting max_memory_to_use. + +If you use the jmemname.c or jmemdos.c memory manager back end, it is +important to clean up the JPEG object properly to ensure that the temporary +files get deleted. (This is especially crucial with jmemdos.c, where the +"temporary files" may be extended-memory segments; if they are not freed, +DOS will require a reboot to recover the memory.) Thus, with these memory +managers, it's a good idea to provide a signal handler that will trap any +early exit from your program. The handler should call either jpeg_abort() +or jpeg_destroy() for any active JPEG objects. A handler is not needed with +jmemnobs.c, and shouldn't be necessary with jmemansi.c or jmemmac.c either, +since the C library is supposed to take care of deleting files made with +tmpfile(). + + +Memory usage +------------ + +Working memory requirements while performing compression or decompression +depend on image dimensions, image characteristics (such as colorspace and +JPEG process), and operating mode (application-selected options). + +As of v6b, the decompressor requires: + 1. About 24K in more-or-less-fixed-size data. This varies a bit depending + on operating mode and image characteristics (particularly color vs. + grayscale), but it doesn't depend on image dimensions. + 2. Strip buffers (of size proportional to the image width) for IDCT and + upsampling results. The worst case for commonly used sampling factors + is about 34 bytes * width in pixels for a color image. A grayscale image + only needs about 8 bytes per pixel column. + 3. A full-image DCT coefficient buffer is needed to decode a multi-scan JPEG + file (including progressive JPEGs), or whenever you select buffered-image + mode. This takes 2 bytes/coefficient. At typical 2x2 sampling, that's + 3 bytes per pixel for a color image. Worst case (1x1 sampling) requires + 6 bytes/pixel. For grayscale, figure 2 bytes/pixel. + 4. To perform 2-pass color quantization, the decompressor also needs a + 128K color lookup table and a full-image pixel buffer (3 bytes/pixel). +This does not count any memory allocated by the application, such as a +buffer to hold the final output image. + +The above figures are valid for 8-bit JPEG data precision and a machine with +32-bit ints. For 12-bit JPEG data, double the size of the strip buffers and +quantization pixel buffer. The "fixed-size" data will be somewhat smaller +with 16-bit ints, larger with 64-bit ints. Also, CMYK or other unusual +color spaces will require different amounts of space. + +The full-image coefficient and pixel buffers, if needed at all, do not +have to be fully RAM resident; you can have the library use temporary +files instead when the total memory usage would exceed a limit you set. +(But if your OS supports virtual memory, it's probably better to just use +jmemnobs and let the OS do the swapping.) + +The compressor's memory requirements are similar, except that it has no need +for color quantization. Also, it needs a full-image DCT coefficient buffer +if Huffman-table optimization is asked for, even if progressive mode is not +requested. + +If you need more detailed information about memory usage in a particular +situation, you can enable the MEM_STATS code in jmemmgr.c. + + +Library compile-time options +---------------------------- + +A number of compile-time options are available by modifying jmorecfg.h. + +The JPEG standard provides for both the baseline 8-bit DCT process and +a 12-bit DCT process. The IJG code supports 12-bit lossy JPEG if you define +BITS_IN_JSAMPLE as 12 rather than 8. Note that this causes JSAMPLE to be +larger than a char, so it affects the surrounding application's image data. +The sample applications cjpeg and djpeg can support 12-bit mode only for PPM +and GIF file formats; you must disable the other file formats to compile a +12-bit cjpeg or djpeg. (install.doc has more information about that.) +At present, a 12-bit library can handle *only* 12-bit images, not both +precisions. (If you need to include both 8- and 12-bit libraries in a single +application, you could probably do it by defining NEED_SHORT_EXTERNAL_NAMES +for just one of the copies. You'd have to access the 8-bit and 12-bit copies +from separate application source files. This is untested ... if you try it, +we'd like to hear whether it works!) + +Note that a 12-bit library always compresses in Huffman optimization mode, +in order to generate valid Huffman tables. This is necessary because our +default Huffman tables only cover 8-bit data. If you need to output 12-bit +files in one pass, you'll have to supply suitable default Huffman tables. +You may also want to supply your own DCT quantization tables; the existing +quality-scaling code has been developed for 8-bit use, and probably doesn't +generate especially good tables for 12-bit. + +The maximum number of components (color channels) in the image is determined +by MAX_COMPONENTS. The JPEG standard allows up to 255 components, but we +expect that few applications will need more than four or so. + +On machines with unusual data type sizes, you may be able to improve +performance or reduce memory space by tweaking the various typedefs in +jmorecfg.h. In particular, on some RISC CPUs, access to arrays of "short"s +is quite slow; consider trading memory for speed by making JCOEF, INT16, and +UINT16 be "int" or "unsigned int". UINT8 is also a candidate to become int. +You probably don't want to make JSAMPLE be int unless you have lots of memory +to burn. + +You can reduce the size of the library by compiling out various optional +functions. To do this, undefine xxx_SUPPORTED symbols as necessary. + +You can also save a few K by not having text error messages in the library; +the standard error message table occupies about 5Kb. This is particularly +reasonable for embedded applications where there's no good way to display +a message anyway. To do this, remove the creation of the message table +(jpeg_std_message_table[]) from jerror.c, and alter format_message to do +something reasonable without it. You could output the numeric value of the +message code number, for example. If you do this, you can also save a couple +more K by modifying the TRACEMSn() macros in jerror.h to expand to nothing; +you don't need trace capability anyway, right? + + +Portability considerations +-------------------------- + +The JPEG library has been written to be extremely portable; the sample +applications cjpeg and djpeg are slightly less so. This section summarizes +the design goals in this area. (If you encounter any bugs that cause the +library to be less portable than is claimed here, we'd appreciate hearing +about them.) + +The code works fine on ANSI C, C++, and pre-ANSI C compilers, using any of +the popular system include file setups, and some not-so-popular ones too. +See install.doc for configuration procedures. + +The code is not dependent on the exact sizes of the C data types. As +distributed, we make the assumptions that + char is at least 8 bits wide + short is at least 16 bits wide + int is at least 16 bits wide + long is at least 32 bits wide +(These are the minimum requirements of the ANSI C standard.) Wider types will +work fine, although memory may be used inefficiently if char is much larger +than 8 bits or short is much bigger than 16 bits. The code should work +equally well with 16- or 32-bit ints. + +In a system where these assumptions are not met, you may be able to make the +code work by modifying the typedefs in jmorecfg.h. However, you will probably +have difficulty if int is less than 16 bits wide, since references to plain +int abound in the code. + +char can be either signed or unsigned, although the code runs faster if an +unsigned char type is available. If char is wider than 8 bits, you will need +to redefine JOCTET and/or provide custom data source/destination managers so +that JOCTET represents exactly 8 bits of data on external storage. + +The JPEG library proper does not assume ASCII representation of characters. +But some of the image file I/O modules in cjpeg/djpeg do have ASCII +dependencies in file-header manipulation; so does cjpeg's select_file_type() +routine. + +The JPEG library does not rely heavily on the C library. In particular, C +stdio is used only by the data source/destination modules and the error +handler, all of which are application-replaceable. (cjpeg/djpeg are more +heavily dependent on stdio.) malloc and free are called only from the memory +manager "back end" module, so you can use a different memory allocator by +replacing that one file. + +The code generally assumes that C names must be unique in the first 15 +characters. However, global function names can be made unique in the +first 6 characters by defining NEED_SHORT_EXTERNAL_NAMES. + +More info about porting the code may be gleaned by reading jconfig.doc, +jmorecfg.h, and jinclude.h. + + +Notes for MS-DOS implementors +----------------------------- + +The IJG code is designed to work efficiently in 80x86 "small" or "medium" +memory models (i.e., data pointers are 16 bits unless explicitly declared +"far"; code pointers can be either size). You may be able to use small +model to compile cjpeg or djpeg by itself, but you will probably have to use +medium model for any larger application. This won't make much difference in +performance. You *will* take a noticeable performance hit if you use a +large-data memory model (perhaps 10%-25%), and you should avoid "huge" model +if at all possible. + +The JPEG library typically needs 2Kb-3Kb of stack space. It will also +malloc about 20K-30K of near heap space while executing (and lots of far +heap, but that doesn't count in this calculation). This figure will vary +depending on selected operating mode, and to a lesser extent on image size. +There is also about 5Kb-6Kb of constant data which will be allocated in the +near data segment (about 4Kb of this is the error message table). +Thus you have perhaps 20K available for other modules' static data and near +heap space before you need to go to a larger memory model. The C library's +static data will account for several K of this, but that still leaves a good +deal for your needs. (If you are tight on space, you could reduce the sizes +of the I/O buffers allocated by jdatasrc.c and jdatadst.c, say from 4K to +1K. Another possibility is to move the error message table to far memory; +this should be doable with only localized hacking on jerror.c.) + +About 2K of the near heap space is "permanent" memory that will not be +released until you destroy the JPEG object. This is only an issue if you +save a JPEG object between compression or decompression operations. + +Far data space may also be a tight resource when you are dealing with large +images. The most memory-intensive case is decompression with two-pass color +quantization, or single-pass quantization to an externally supplied color +map. This requires a 128Kb color lookup table plus strip buffers amounting +to about 40 bytes per column for typical sampling ratios (eg, about 25600 +bytes for a 640-pixel-wide image). You may not be able to process wide +images if you have large data structures of your own. + +Of course, all of these concerns vanish if you use a 32-bit flat-memory-model +compiler, such as DJGPP or Watcom C. We highly recommend flat model if you +can use it; the JPEG library is significantly faster in flat model. diff --git a/Utilities/ITK/Utilities/itkjpeg/mangle_jpeg12bits.h b/Utilities/ITK/Utilities/itkjpeg/mangle_jpeg12bits.h new file mode 100644 index 0000000000000000000000000000000000000000..d2189c7b091e70be4b0039f6ca8b62203427bc80 --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/mangle_jpeg12bits.h @@ -0,0 +1,141 @@ +#ifndef itk_jpeg12_mangle_h +#define itk_jpeg12_mangle_h + +/* + +This header file mangles all symbols exported from the jpeg library. +It is included in all files while building the jpeg library. Due to +namespace pollution, no jpeg headers should be included in .h files in +GDCM. This also allows us to generate two jpeg library (8bits and 12bits). + +The following command was used to obtain the symbol list: + +nm libitkitk_jpeg12.a | grep " [R|T] " | colrm 1 11 | sort + +(actually copy/paste from jpeg8bits) +*/ + + + +#define jcopy_block_row itk_jpeg12_jcopy_block_row +#define jcopy_sample_rows itk_jpeg12_jcopy_sample_rows +#define jdiv_round_up itk_jpeg12_jdiv_round_up +#define jinit_1pass_quantizer itk_jpeg12_jinit_1pass_quantizer +#define jinit_2pass_quantizer itk_jpeg12_jinit_2pass_quantizer +#define jinit_arith_decoder itk_jpeg12_jinit_arith_decoder +#define jinit_arith_encoder itk_jpeg12_jinit_arith_encoder +#define jinit_c_codec itk_jpeg12_jinit_c_codec +#define jinit_c_coef_controller itk_jpeg12_jinit_c_coef_controller +#define jinit_c_diff_controller itk_jpeg12_jinit_c_diff_controller +#define jinit_c_main_controller itk_jpeg12_jinit_c_main_controller +#define jinit_c_master_control itk_jpeg12_jinit_c_master_control +#define jinit_c_prep_controller itk_jpeg12_jinit_c_prep_controller +#define jinit_c_scaler itk_jpeg12_jinit_c_scaler +#define jinit_color_converter itk_jpeg12_jinit_color_converter +#define jinit_color_deconverter itk_jpeg12_jinit_color_deconverter +#define jinit_compress_master itk_jpeg12_jinit_compress_master +#define jinit_d_codec itk_jpeg12_jinit_d_codec +#define jinit_d_coef_controller itk_jpeg12_jinit_d_coef_controller +#define jinit_d_diff_controller itk_jpeg12_jinit_d_diff_controller +#define jinit_d_main_controller itk_jpeg12_jinit_d_main_controller +#define jinit_d_post_controller itk_jpeg12_jinit_d_post_controller +#define jinit_d_scaler itk_jpeg12_jinit_d_scaler +#define jinit_differencer itk_jpeg12_jinit_differencer +#define jinit_downsampler itk_jpeg12_jinit_downsampler +#define jinit_forward_dct itk_jpeg12_jinit_forward_dct +#define jinit_input_controller itk_jpeg12_jinit_input_controller +#define jinit_inverse_dct itk_jpeg12_jinit_inverse_dct +#define jinit_lhuff_decoder itk_jpeg12_jinit_lhuff_decoder +#define jinit_lhuff_encoder itk_jpeg12_jinit_lhuff_encoder +#define jinit_lossless_c_codec itk_jpeg12_jinit_lossless_c_codec +#define jinit_lossless_d_codec itk_jpeg12_jinit_lossless_d_codec +#define jinit_lossy_c_codec itk_jpeg12_jinit_lossy_c_codec +#define jinit_lossy_d_codec itk_jpeg12_jinit_lossy_d_codec +#define jinit_marker_reader itk_jpeg12_jinit_marker_reader +#define jinit_marker_writer itk_jpeg12_jinit_marker_writer +#define jinit_master_decompress itk_jpeg12_jinit_master_decompress +#define jinit_memory_mgr itk_jpeg12_jinit_memory_mgr +#define jinit_merged_upsampler itk_jpeg12_jinit_merged_upsampler +#define jinit_phuff_decoder itk_jpeg12_jinit_phuff_decoder +#define jinit_phuff_encoder itk_jpeg12_jinit_phuff_encoder +#define jinit_shuff_decoder itk_jpeg12_jinit_shuff_decoder +#define jinit_shuff_encoder itk_jpeg12_jinit_shuff_encoder +#define jinit_undifferencer itk_jpeg12_jinit_undifferencer +#define jinit_upsampler itk_jpeg12_jinit_upsampler +#define jpeg_CreateCompress itk_jpeg12_jpeg_CreateCompress +#define jpeg_CreateDecompress itk_jpeg12_jpeg_CreateDecompress +#define jpeg_abort itk_jpeg12_jpeg_abort +#define jpeg_abort_compress itk_jpeg12_jpeg_abort_compress +#define jpeg_abort_decompress itk_jpeg12_jpeg_abort_decompress +#define jpeg_add_quant_table itk_jpeg12_jpeg_add_quant_table +#define jpeg_alloc_huff_table itk_jpeg12_jpeg_alloc_huff_table +#define jpeg_alloc_quant_table itk_jpeg12_jpeg_alloc_quant_table +#define jpeg_calc_output_dimensions itk_jpeg12_jpeg_calc_output_dimensions +#define jpeg_consume_input itk_jpeg12_jpeg_consume_input +#define jpeg_copy_critical_parameters itk_jpeg12_jpeg_copy_critical_parameters +#define jpeg_default_colorspace itk_jpeg12_jpeg_default_colorspace +#define jpeg_destroy itk_jpeg12_jpeg_destroy +#define jpeg_destroy_compress itk_jpeg12_jpeg_destroy_compress +#define jpeg_destroy_decompress itk_jpeg12_jpeg_destroy_decompress +#define jpeg_fdct_float itk_jpeg12_jpeg_fdct_float +#define jpeg_fdct_ifast itk_jpeg12_jpeg_fdct_ifast +#define jpeg_fdct_islow itk_jpeg12_jpeg_fdct_islow +#define jpeg_fill_bit_buffer itk_jpeg12_jpeg_fill_bit_buffer +#define jpeg_finish_compress itk_jpeg12_jpeg_finish_compress +#define jpeg_finish_decompress itk_jpeg12_jpeg_finish_decompress +#define jpeg_finish_output itk_jpeg12_jpeg_finish_output +#define jpeg_free_large itk_jpeg12_jpeg_free_large +#define jpeg_free_small itk_jpeg12_jpeg_free_small +#define jpeg_gen_optimal_table itk_jpeg12_jpeg_gen_optimal_table +#define jpeg_get_large itk_jpeg12_jpeg_get_large +#define jpeg_get_small itk_jpeg12_jpeg_get_small +#define jpeg_has_multiple_scans itk_jpeg12_jpeg_has_multiple_scans +#define jpeg_huff_decode itk_jpeg12_jpeg_huff_decode +#define jpeg_idct_1x1 itk_jpeg12_jpeg_idct_1x1 +#define jpeg_idct_2x2 itk_jpeg12_jpeg_idct_2x2 +#define jpeg_idct_4x4 itk_jpeg12_jpeg_idct_4x4 +#define jpeg_idct_float itk_jpeg12_jpeg_idct_float +#define jpeg_idct_ifast itk_jpeg12_jpeg_idct_ifast +#define jpeg_idct_islow itk_jpeg12_jpeg_idct_islow +#define jpeg_input_complete itk_jpeg12_jpeg_input_complete +#define jpeg_make_c_derived_tbl itk_jpeg12_jpeg_make_c_derived_tbl +#define jpeg_make_d_derived_tbl itk_jpeg12_jpeg_make_d_derived_tbl +#define jpeg_mem_available itk_jpeg12_jpeg_mem_available +#define jpeg_mem_init itk_jpeg12_jpeg_mem_init +#define jpeg_mem_term itk_jpeg12_jpeg_mem_term +#define jpeg_natural_order itk_jpeg12_jpeg_natural_order +#define jpeg_new_colormap itk_jpeg12_jpeg_new_colormap +#define jpeg_open_backing_store itk_jpeg12_jpeg_open_backing_store +#define jpeg_quality_scaling itk_jpeg12_jpeg_quality_scaling +#define jpeg_read_coefficients itk_jpeg12_jpeg_read_coefficients +#define jpeg_read_header itk_jpeg12_jpeg_read_header +#define jpeg_read_raw_data itk_jpeg12_jpeg_read_raw_data +#define jpeg_read_scanlines itk_jpeg12_jpeg_read_scanlines +#define jpeg_resync_to_restart itk_jpeg12_jpeg_resync_to_restart +#define jpeg_save_markers itk_jpeg12_jpeg_save_markers +#define jpeg_set_colorspace itk_jpeg12_jpeg_set_colorspace +#define jpeg_set_defaults itk_jpeg12_jpeg_set_defaults +#define jpeg_set_linear_quality itk_jpeg12_jpeg_set_linear_quality +#define jpeg_set_marker_processor itk_jpeg12_jpeg_set_marker_processor +#define jpeg_set_quality itk_jpeg12_jpeg_set_quality +#define jpeg_simple_lossless itk_jpeg12_jpeg_simple_lossless +#define jpeg_simple_progression itk_jpeg12_jpeg_simple_progression +#define jpeg_start_compress itk_jpeg12_jpeg_start_compress +#define jpeg_start_decompress itk_jpeg12_jpeg_start_decompress +#define jpeg_start_output itk_jpeg12_jpeg_start_output +#define jpeg_std_error itk_jpeg12_jpeg_std_error +#define jpeg_std_message_table itk_jpeg12_jpeg_std_message_table +#define jpeg_stdio_dest itk_jpeg12_jpeg_stdio_dest +#define jpeg_stdio_src itk_jpeg12_jpeg_stdio_src +#define jpeg_suppress_tables itk_jpeg12_jpeg_suppress_tables +#define jpeg_write_coefficients itk_jpeg12_jpeg_write_coefficients +#define jpeg_write_m_byte itk_jpeg12_jpeg_write_m_byte +#define jpeg_write_m_header itk_jpeg12_jpeg_write_m_header +#define jpeg_write_marker itk_jpeg12_jpeg_write_marker +#define jpeg_write_raw_data itk_jpeg12_jpeg_write_raw_data +#define jpeg_write_scanlines itk_jpeg12_jpeg_write_scanlines +#define jpeg_write_tables itk_jpeg12_jpeg_write_tables +#define jround_up itk_jpeg12_jround_up +#define jzero_far itk_jpeg12_jzero_far + +#endif diff --git a/Utilities/ITK/Utilities/itkjpeg/mangle_jpeg16bits.h b/Utilities/ITK/Utilities/itkjpeg/mangle_jpeg16bits.h new file mode 100644 index 0000000000000000000000000000000000000000..a0f1450c8f577ca9a2dfeb27274f729f94284d83 --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/mangle_jpeg16bits.h @@ -0,0 +1,141 @@ +#ifndef itk_jpeg16_mangle_h +#define itk_jpeg16_mangle_h + +/* + +This header file mangles all symbols exported from the jpeg library. +It is included in all files while building the jpeg library. Due to +namespace pollution, no jpeg headers should be included in .h files in +GDCM. This also allows us to generate three jpeg library (8, 12 and 16bits). + +The following command was used to obtain the symbol list: + +nm libitkitk_jpeg16.a | grep " [R|T] " | colrm 1 11 | sort + +(actually copy/paste from jpeg8bits) +*/ + + + +#define jcopy_block_row itk_jpeg16_jcopy_block_row +#define jcopy_sample_rows itk_jpeg16_jcopy_sample_rows +#define jdiv_round_up itk_jpeg16_jdiv_round_up +#define jinit_1pass_quantizer itk_jpeg16_jinit_1pass_quantizer +#define jinit_2pass_quantizer itk_jpeg16_jinit_2pass_quantizer +#define jinit_arith_decoder itk_jpeg16_jinit_arith_decoder +#define jinit_arith_encoder itk_jpeg16_jinit_arith_encoder +#define jinit_c_codec itk_jpeg16_jinit_c_codec +#define jinit_c_coef_controller itk_jpeg16_jinit_c_coef_controller +#define jinit_c_diff_controller itk_jpeg16_jinit_c_diff_controller +#define jinit_c_main_controller itk_jpeg16_jinit_c_main_controller +#define jinit_c_master_control itk_jpeg16_jinit_c_master_control +#define jinit_c_prep_controller itk_jpeg16_jinit_c_prep_controller +#define jinit_c_scaler itk_jpeg16_jinit_c_scaler +#define jinit_color_converter itk_jpeg16_jinit_color_converter +#define jinit_color_deconverter itk_jpeg16_jinit_color_deconverter +#define jinit_compress_master itk_jpeg16_jinit_compress_master +#define jinit_d_codec itk_jpeg16_jinit_d_codec +#define jinit_d_coef_controller itk_jpeg16_jinit_d_coef_controller +#define jinit_d_diff_controller itk_jpeg16_jinit_d_diff_controller +#define jinit_d_main_controller itk_jpeg16_jinit_d_main_controller +#define jinit_d_post_controller itk_jpeg16_jinit_d_post_controller +#define jinit_d_scaler itk_jpeg16_jinit_d_scaler +#define jinit_differencer itk_jpeg16_jinit_differencer +#define jinit_downsampler itk_jpeg16_jinit_downsampler +#define jinit_forward_dct itk_jpeg16_jinit_forward_dct +#define jinit_input_controller itk_jpeg16_jinit_input_controller +#define jinit_inverse_dct itk_jpeg16_jinit_inverse_dct +#define jinit_lhuff_decoder itk_jpeg16_jinit_lhuff_decoder +#define jinit_lhuff_encoder itk_jpeg16_jinit_lhuff_encoder +#define jinit_lossless_c_codec itk_jpeg16_jinit_lossless_c_codec +#define jinit_lossless_d_codec itk_jpeg16_jinit_lossless_d_codec +#define jinit_lossy_c_codec itk_jpeg16_jinit_lossy_c_codec +#define jinit_lossy_d_codec itk_jpeg16_jinit_lossy_d_codec +#define jinit_marker_reader itk_jpeg16_jinit_marker_reader +#define jinit_marker_writer itk_jpeg16_jinit_marker_writer +#define jinit_master_decompress itk_jpeg16_jinit_master_decompress +#define jinit_memory_mgr itk_jpeg16_jinit_memory_mgr +#define jinit_merged_upsampler itk_jpeg16_jinit_merged_upsampler +#define jinit_phuff_decoder itk_jpeg16_jinit_phuff_decoder +#define jinit_phuff_encoder itk_jpeg16_jinit_phuff_encoder +#define jinit_shuff_decoder itk_jpeg16_jinit_shuff_decoder +#define jinit_shuff_encoder itk_jpeg16_jinit_shuff_encoder +#define jinit_undifferencer itk_jpeg16_jinit_undifferencer +#define jinit_upsampler itk_jpeg16_jinit_upsampler +#define jpeg_CreateCompress itk_jpeg16_jpeg_CreateCompress +#define jpeg_CreateDecompress itk_jpeg16_jpeg_CreateDecompress +#define jpeg_abort itk_jpeg16_jpeg_abort +#define jpeg_abort_compress itk_jpeg16_jpeg_abort_compress +#define jpeg_abort_decompress itk_jpeg16_jpeg_abort_decompress +#define jpeg_add_quant_table itk_jpeg16_jpeg_add_quant_table +#define jpeg_alloc_huff_table itk_jpeg16_jpeg_alloc_huff_table +#define jpeg_alloc_quant_table itk_jpeg16_jpeg_alloc_quant_table +#define jpeg_calc_output_dimensions itk_jpeg16_jpeg_calc_output_dimensions +#define jpeg_consume_input itk_jpeg16_jpeg_consume_input +#define jpeg_copy_critical_parameters itk_jpeg16_jpeg_copy_critical_parameters +#define jpeg_default_colorspace itk_jpeg16_jpeg_default_colorspace +#define jpeg_destroy itk_jpeg16_jpeg_destroy +#define jpeg_destroy_compress itk_jpeg16_jpeg_destroy_compress +#define jpeg_destroy_decompress itk_jpeg16_jpeg_destroy_decompress +#define jpeg_fdct_float itk_jpeg16_jpeg_fdct_float +#define jpeg_fdct_ifast itk_jpeg16_jpeg_fdct_ifast +#define jpeg_fdct_islow itk_jpeg16_jpeg_fdct_islow +#define jpeg_fill_bit_buffer itk_jpeg16_jpeg_fill_bit_buffer +#define jpeg_finish_compress itk_jpeg16_jpeg_finish_compress +#define jpeg_finish_decompress itk_jpeg16_jpeg_finish_decompress +#define jpeg_finish_output itk_jpeg16_jpeg_finish_output +#define jpeg_free_large itk_jpeg16_jpeg_free_large +#define jpeg_free_small itk_jpeg16_jpeg_free_small +#define jpeg_gen_optimal_table itk_jpeg16_jpeg_gen_optimal_table +#define jpeg_get_large itk_jpeg16_jpeg_get_large +#define jpeg_get_small itk_jpeg16_jpeg_get_small +#define jpeg_has_multiple_scans itk_jpeg16_jpeg_has_multiple_scans +#define jpeg_huff_decode itk_jpeg16_jpeg_huff_decode +#define jpeg_idct_1x1 itk_jpeg16_jpeg_idct_1x1 +#define jpeg_idct_2x2 itk_jpeg16_jpeg_idct_2x2 +#define jpeg_idct_4x4 itk_jpeg16_jpeg_idct_4x4 +#define jpeg_idct_float itk_jpeg16_jpeg_idct_float +#define jpeg_idct_ifast itk_jpeg16_jpeg_idct_ifast +#define jpeg_idct_islow itk_jpeg16_jpeg_idct_islow +#define jpeg_input_complete itk_jpeg16_jpeg_input_complete +#define jpeg_make_c_derived_tbl itk_jpeg16_jpeg_make_c_derived_tbl +#define jpeg_make_d_derived_tbl itk_jpeg16_jpeg_make_d_derived_tbl +#define jpeg_mem_available itk_jpeg16_jpeg_mem_available +#define jpeg_mem_init itk_jpeg16_jpeg_mem_init +#define jpeg_mem_term itk_jpeg16_jpeg_mem_term +#define jpeg_natural_order itk_jpeg16_jpeg_natural_order +#define jpeg_new_colormap itk_jpeg16_jpeg_new_colormap +#define jpeg_open_backing_store itk_jpeg16_jpeg_open_backing_store +#define jpeg_quality_scaling itk_jpeg16_jpeg_quality_scaling +#define jpeg_read_coefficients itk_jpeg16_jpeg_read_coefficients +#define jpeg_read_header itk_jpeg16_jpeg_read_header +#define jpeg_read_raw_data itk_jpeg16_jpeg_read_raw_data +#define jpeg_read_scanlines itk_jpeg16_jpeg_read_scanlines +#define jpeg_resync_to_restart itk_jpeg16_jpeg_resync_to_restart +#define jpeg_save_markers itk_jpeg16_jpeg_save_markers +#define jpeg_set_colorspace itk_jpeg16_jpeg_set_colorspace +#define jpeg_set_defaults itk_jpeg16_jpeg_set_defaults +#define jpeg_set_linear_quality itk_jpeg16_jpeg_set_linear_quality +#define jpeg_set_marker_processor itk_jpeg16_jpeg_set_marker_processor +#define jpeg_set_quality itk_jpeg16_jpeg_set_quality +#define jpeg_simple_lossless itk_jpeg16_jpeg_simple_lossless +#define jpeg_simple_progression itk_jpeg16_jpeg_simple_progression +#define jpeg_start_compress itk_jpeg16_jpeg_start_compress +#define jpeg_start_decompress itk_jpeg16_jpeg_start_decompress +#define jpeg_start_output itk_jpeg16_jpeg_start_output +#define jpeg_std_error itk_jpeg16_jpeg_std_error +#define jpeg_std_message_table itk_jpeg16_jpeg_std_message_table +#define jpeg_stdio_dest itk_jpeg16_jpeg_stdio_dest +#define jpeg_stdio_src itk_jpeg16_jpeg_stdio_src +#define jpeg_suppress_tables itk_jpeg16_jpeg_suppress_tables +#define jpeg_write_coefficients itk_jpeg16_jpeg_write_coefficients +#define jpeg_write_m_byte itk_jpeg16_jpeg_write_m_byte +#define jpeg_write_m_header itk_jpeg16_jpeg_write_m_header +#define jpeg_write_marker itk_jpeg16_jpeg_write_marker +#define jpeg_write_raw_data itk_jpeg16_jpeg_write_raw_data +#define jpeg_write_scanlines itk_jpeg16_jpeg_write_scanlines +#define jpeg_write_tables itk_jpeg16_jpeg_write_tables +#define jround_up itk_jpeg16_jround_up +#define jzero_far itk_jpeg16_jzero_far + +#endif diff --git a/Utilities/ITK/Utilities/itkjpeg/mangle_jpeg8bits.h b/Utilities/ITK/Utilities/itkjpeg/mangle_jpeg8bits.h new file mode 100644 index 0000000000000000000000000000000000000000..226aa54b904fa6443cc960ade8541da6f8a119b2 --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/mangle_jpeg8bits.h @@ -0,0 +1,139 @@ +#ifndef itk_jpeg8_mangle_h +#define itk_jpeg8_mangle_h + +/* + +This header file mangles all symbols exported from the jpeg library. +It is included in all files while building the jpeg library. Due to +namespace pollution, no jpeg headers should be included in .h files in +GDCM. This also allows us to generate two jpeg library (8bits and 12bits). + +The following command was used to obtain the symbol list: + +nm libitkitk_jpeg8.a | grep " [R|T] " | colrm 1 11 | sort +*/ + + +#define jcopy_block_row itk_jpeg8_jcopy_block_row +#define jcopy_sample_rows itk_jpeg8_jcopy_sample_rows +#define jdiv_round_up itk_jpeg8_jdiv_round_up +#define jinit_1pass_quantizer itk_jpeg8_jinit_1pass_quantizer +#define jinit_2pass_quantizer itk_jpeg8_jinit_2pass_quantizer +#define jinit_arith_decoder itk_jpeg8_jinit_arith_decoder +#define jinit_arith_encoder itk_jpeg8_jinit_arith_encoder +#define jinit_c_codec itk_jpeg8_jinit_c_codec +#define jinit_c_coef_controller itk_jpeg8_jinit_c_coef_controller +#define jinit_c_diff_controller itk_jpeg8_jinit_c_diff_controller +#define jinit_c_main_controller itk_jpeg8_jinit_c_main_controller +#define jinit_c_master_control itk_jpeg8_jinit_c_master_control +#define jinit_c_prep_controller itk_jpeg8_jinit_c_prep_controller +#define jinit_c_scaler itk_jpeg8_jinit_c_scaler +#define jinit_color_converter itk_jpeg8_jinit_color_converter +#define jinit_color_deconverter itk_jpeg8_jinit_color_deconverter +#define jinit_compress_master itk_jpeg8_jinit_compress_master +#define jinit_d_codec itk_jpeg8_jinit_d_codec +#define jinit_d_coef_controller itk_jpeg8_jinit_d_coef_controller +#define jinit_d_diff_controller itk_jpeg8_jinit_d_diff_controller +#define jinit_d_main_controller itk_jpeg8_jinit_d_main_controller +#define jinit_d_post_controller itk_jpeg8_jinit_d_post_controller +#define jinit_d_scaler itk_jpeg8_jinit_d_scaler +#define jinit_differencer itk_jpeg8_jinit_differencer +#define jinit_downsampler itk_jpeg8_jinit_downsampler +#define jinit_forward_dct itk_jpeg8_jinit_forward_dct +#define jinit_input_controller itk_jpeg8_jinit_input_controller +#define jinit_inverse_dct itk_jpeg8_jinit_inverse_dct +#define jinit_lhuff_decoder itk_jpeg8_jinit_lhuff_decoder +#define jinit_lhuff_encoder itk_jpeg8_jinit_lhuff_encoder +#define jinit_lossless_c_codec itk_jpeg8_jinit_lossless_c_codec +#define jinit_lossless_d_codec itk_jpeg8_jinit_lossless_d_codec +#define jinit_lossy_c_codec itk_jpeg8_jinit_lossy_c_codec +#define jinit_lossy_d_codec itk_jpeg8_jinit_lossy_d_codec +#define jinit_marker_reader itk_jpeg8_jinit_marker_reader +#define jinit_marker_writer itk_jpeg8_jinit_marker_writer +#define jinit_master_decompress itk_jpeg8_jinit_master_decompress +#define jinit_memory_mgr itk_jpeg8_jinit_memory_mgr +#define jinit_merged_upsampler itk_jpeg8_jinit_merged_upsampler +#define jinit_phuff_decoder itk_jpeg8_jinit_phuff_decoder +#define jinit_phuff_encoder itk_jpeg8_jinit_phuff_encoder +#define jinit_shuff_decoder itk_jpeg8_jinit_shuff_decoder +#define jinit_shuff_encoder itk_jpeg8_jinit_shuff_encoder +#define jinit_undifferencer itk_jpeg8_jinit_undifferencer +#define jinit_upsampler itk_jpeg8_jinit_upsampler +#define jpeg_CreateCompress itk_jpeg8_jpeg_CreateCompress +#define jpeg_CreateDecompress itk_jpeg8_jpeg_CreateDecompress +#define jpeg_abort itk_jpeg8_jpeg_abort +#define jpeg_abort_compress itk_jpeg8_jpeg_abort_compress +#define jpeg_abort_decompress itk_jpeg8_jpeg_abort_decompress +#define jpeg_add_quant_table itk_jpeg8_jpeg_add_quant_table +#define jpeg_alloc_huff_table itk_jpeg8_jpeg_alloc_huff_table +#define jpeg_alloc_quant_table itk_jpeg8_jpeg_alloc_quant_table +#define jpeg_calc_output_dimensions itk_jpeg8_jpeg_calc_output_dimensions +#define jpeg_consume_input itk_jpeg8_jpeg_consume_input +#define jpeg_copy_critical_parameters itk_jpeg8_jpeg_copy_critical_parameters +#define jpeg_default_colorspace itk_jpeg8_jpeg_default_colorspace +#define jpeg_destroy itk_jpeg8_jpeg_destroy +#define jpeg_destroy_compress itk_jpeg8_jpeg_destroy_compress +#define jpeg_destroy_decompress itk_jpeg8_jpeg_destroy_decompress +#define jpeg_fdct_float itk_jpeg8_jpeg_fdct_float +#define jpeg_fdct_ifast itk_jpeg8_jpeg_fdct_ifast +#define jpeg_fdct_islow itk_jpeg8_jpeg_fdct_islow +#define jpeg_fill_bit_buffer itk_jpeg8_jpeg_fill_bit_buffer +#define jpeg_finish_compress itk_jpeg8_jpeg_finish_compress +#define jpeg_finish_decompress itk_jpeg8_jpeg_finish_decompress +#define jpeg_finish_output itk_jpeg8_jpeg_finish_output +#define jpeg_free_large itk_jpeg8_jpeg_free_large +#define jpeg_free_small itk_jpeg8_jpeg_free_small +#define jpeg_gen_optimal_table itk_jpeg8_jpeg_gen_optimal_table +#define jpeg_get_large itk_jpeg8_jpeg_get_large +#define jpeg_get_small itk_jpeg8_jpeg_get_small +#define jpeg_has_multiple_scans itk_jpeg8_jpeg_has_multiple_scans +#define jpeg_huff_decode itk_jpeg8_jpeg_huff_decode +#define jpeg_idct_1x1 itk_jpeg8_jpeg_idct_1x1 +#define jpeg_idct_2x2 itk_jpeg8_jpeg_idct_2x2 +#define jpeg_idct_4x4 itk_jpeg8_jpeg_idct_4x4 +#define jpeg_idct_float itk_jpeg8_jpeg_idct_float +#define jpeg_idct_ifast itk_jpeg8_jpeg_idct_ifast +#define jpeg_idct_islow itk_jpeg8_jpeg_idct_islow +#define jpeg_input_complete itk_jpeg8_jpeg_input_complete +#define jpeg_make_c_derived_tbl itk_jpeg8_jpeg_make_c_derived_tbl +#define jpeg_make_d_derived_tbl itk_jpeg8_jpeg_make_d_derived_tbl +#define jpeg_mem_available itk_jpeg8_jpeg_mem_available +#define jpeg_mem_init itk_jpeg8_jpeg_mem_init +#define jpeg_mem_term itk_jpeg8_jpeg_mem_term +#define jpeg_natural_order itk_jpeg8_jpeg_natural_order +#define jpeg_new_colormap itk_jpeg8_jpeg_new_colormap +#define jpeg_open_backing_store itk_jpeg8_jpeg_open_backing_store +#define jpeg_quality_scaling itk_jpeg8_jpeg_quality_scaling +#define jpeg_read_coefficients itk_jpeg8_jpeg_read_coefficients +#define jpeg_read_header itk_jpeg8_jpeg_read_header +#define jpeg_read_raw_data itk_jpeg8_jpeg_read_raw_data +#define jpeg_read_scanlines itk_jpeg8_jpeg_read_scanlines +#define jpeg_resync_to_restart itk_jpeg8_jpeg_resync_to_restart +#define jpeg_save_markers itk_jpeg8_jpeg_save_markers +#define jpeg_set_colorspace itk_jpeg8_jpeg_set_colorspace +#define jpeg_set_defaults itk_jpeg8_jpeg_set_defaults +#define jpeg_set_linear_quality itk_jpeg8_jpeg_set_linear_quality +#define jpeg_set_marker_processor itk_jpeg8_jpeg_set_marker_processor +#define jpeg_set_quality itk_jpeg8_jpeg_set_quality +#define jpeg_simple_lossless itk_jpeg8_jpeg_simple_lossless +#define jpeg_simple_progression itk_jpeg8_jpeg_simple_progression +#define jpeg_start_compress itk_jpeg8_jpeg_start_compress +#define jpeg_start_decompress itk_jpeg8_jpeg_start_decompress +#define jpeg_start_output itk_jpeg8_jpeg_start_output +#define jpeg_std_error itk_jpeg8_jpeg_std_error +#define jpeg_std_message_table itk_jpeg8_jpeg_std_message_table +#define jpeg_stdio_dest itk_jpeg8_jpeg_stdio_dest +#define jpeg_stdio_src itk_jpeg8_jpeg_stdio_src +#define jpeg_suppress_tables itk_jpeg8_jpeg_suppress_tables +#define jpeg_write_coefficients itk_jpeg8_jpeg_write_coefficients +#define jpeg_write_m_byte itk_jpeg8_jpeg_write_m_byte +#define jpeg_write_m_header itk_jpeg8_jpeg_write_m_header +#define jpeg_write_marker itk_jpeg8_jpeg_write_marker +#define jpeg_write_raw_data itk_jpeg8_jpeg_write_raw_data +#define jpeg_write_scanlines itk_jpeg8_jpeg_write_scanlines +#define jpeg_write_tables itk_jpeg8_jpeg_write_tables +#define jround_up itk_jpeg8_jround_up +#define jzero_far itk_jpeg8_jzero_far + + +#endif diff --git a/Utilities/ITK/Utilities/itkjpeg/structure.doc b/Utilities/ITK/Utilities/itkjpeg/structure.doc new file mode 100644 index 0000000000000000000000000000000000000000..3d62accff5442de5a39ac56c45da3c361d757aa7 --- /dev/null +++ b/Utilities/ITK/Utilities/itkjpeg/structure.doc @@ -0,0 +1,1042 @@ +IJG JPEG LIBRARY: SYSTEM ARCHITECTURE + +Copyright (C) 1991-1995, Thomas G. Lane. +This file is part of the Independent JPEG Group's software. +For conditions of distribution and use, see the accompanying README file. + + +This file provides an overview of the architecture of the IJG JPEG software; +that is, the functions of the various modules in the system and the interfaces +between modules. For more precise details about any data structure or calling +convention, see the include files and comments in the source code. + +We assume that the reader is already somewhat familiar with the JPEG standard. +The README file includes references for learning about JPEG. The file +libjpeg.doc describes the library from the viewpoint of an application +programmer using the library; it's best to read that file before this one. +Also, the file coderules.doc describes the coding style conventions we use. + +In this document, JPEG-specific terminology follows the JPEG standard: + A "component" means a color channel, e.g., Red or Luminance. + A "sample" is a single component value (i.e., one number in the image data). + A "coefficient" is a frequency coefficient (a DCT transform output number). + A "block" is an 8x8 group of samples or coefficients. + A "data unit" is an abstract data type which is either a block for lossy + (DCT-based) codecs or a sample for lossless (predictive) codecs. + An "MCU" (minimum coded unit) is an interleaved set of data units of size + determined by the sampling factors, or a single data unit in a + noninterleaved scan. +We do not use the terms "pixel" and "sample" interchangeably. When we say +pixel, we mean an element of the full-size image, while a sample is an element +of the downsampled image. Thus the number of samples may vary across +components while the number of pixels does not. (This terminology is not used +rigorously throughout the code, but it is used in places where confusion would +otherwise result.) + + +*** System features *** + +The IJG distribution contains two parts: + * A subroutine library for JPEG compression and decompression. + * cjpeg/djpeg, two sample applications that use the library to transform + JFIF JPEG files to and from several other image formats. +cjpeg/djpeg are of no great intellectual complexity: they merely add a simple +command-line user interface and I/O routines for several uncompressed image +formats. This document concentrates on the library itself. + +We desire the library to be capable of supporting all JPEG baseline, extended +sequential, and progressive DCT processes, as well as the lossless (spatial) +process. Hierarchical processes are not supported. + +Within these limits, any set of compression parameters allowed by the JPEG +spec should be readable for decompression. (We can be more restrictive about +what formats we can generate.) Although the system design allows for all +parameter values, some uncommon settings are not yet implemented and may +never be; nonintegral sampling ratios are the prime example. Furthermore, +we treat 8-bit vs. 12-bit data precision as a compile-time switch, not a +run-time option, because most machines can store 8-bit pixels much more +compactly than 12-bit. + +For legal reasons, JPEG arithmetic coding is not currently supported, but +extending the library to include it would be straightforward. + +By itself, the library handles only interchange JPEG datastreams --- in +particular the widely used JFIF file format. The library can be used by +surrounding code to process interchange or abbreviated JPEG datastreams that +are embedded in more complex file formats. (For example, libtiff uses this +library to implement JPEG compression within the TIFF file format.) + +The library includes a substantial amount of code that is not covered by the +JPEG standard but is necessary for typical applications of JPEG. These +functions preprocess the image before JPEG compression or postprocess it after +decompression. They include colorspace conversion, downsampling/upsampling, +and color quantization. This code can be omitted if not needed. + +A wide range of quality vs. speed tradeoffs are possible in JPEG processing, +and even more so in decompression postprocessing. The decompression library +provides multiple implementations that cover most of the useful tradeoffs, +ranging from very-high-quality down to fast-preview operation. On the +compression side we have generally not provided low-quality choices, since +compression is normally less time-critical. It should be understood that the +low-quality modes may not meet the JPEG standard's accuracy requirements; +nonetheless, they are useful for viewers. + + +*** Portability issues *** + +Portability is an essential requirement for the library. The key portability +issues that show up at the level of system architecture are: + +1. Memory usage. We want the code to be able to run on PC-class machines +with limited memory. Images should therefore be processed sequentially (in +strips), to avoid holding the whole image in memory at once. Where a +full-image buffer is necessary, we should be able to use either virtual memory +or temporary files. + +2. Near/far pointer distinction. To run efficiently on 80x86 machines, the +code should distinguish "small" objects (kept in near data space) from +"large" ones (kept in far data space). This is an annoying restriction, but +fortunately it does not impact code quality for less brain-damaged machines, +and the source code clutter turns out to be minimal with sufficient use of +pointer typedefs. + +3. Data precision. We assume that "char" is at least 8 bits, "short" and +"int" at least 16, "long" at least 32. The code will work fine with larger +data sizes, although memory may be used inefficiently in some cases. However, +the JPEG compressed datastream must ultimately appear on external storage as a +sequence of 8-bit bytes if it is to conform to the standard. This may pose a +problem on machines where char is wider than 8 bits. The library represents +compressed data as an array of values of typedef JOCTET. If no data type +exactly 8 bits wide is available, custom data source and data destination +modules must be written to unpack and pack the chosen JOCTET datatype into +8-bit external representation. + + +*** System overview *** + +The compressor and decompressor are each divided into two main sections: +the JPEG compressor or decompressor proper, and the preprocessing or +postprocessing functions. The interface between these two sections is the +image data that the official JPEG spec regards as its input or output: this +data is in the colorspace to be used for compression, and it is downsampled +to the sampling factors to be used. The preprocessing and postprocessing +steps are responsible for converting a normal image representation to or from +this form. (Those few applications that want to deal with YCbCr downsampled +data can skip the preprocessing or postprocessing step.) + +Looking more closely, the compressor library contains the following main +elements: + + Preprocessing: + * Color space conversion (e.g., RGB to YCbCr). + * Edge expansion and downsampling. Optionally, this step can do simple + smoothing --- this is often helpful for low-quality source data. + Lossy JPEG proper: + * MCU assembly, DCT, quantization. + * Entropy coding (sequential or progressive, Huffman or arithmetic). + Lossless JPEG proper: + * Point transform. + * Prediction, differencing. + * Entropy coding (Huffman or arithmetic) + +In addition to these modules we need overall control, marker generation, +and support code (memory management & error handling). There is also a +module responsible for physically writing the output data --- typically +this is just an interface to fwrite(), but some applications may need to +do something else with the data. + +The decompressor library contains the following main elements: + + Lossy JPEG proper: + * Entropy decoding (sequential or progressive, Huffman or arithmetic). + * Dequantization, inverse DCT, MCU disassembly. + Lossless JPEG proper: + * Entropy decoding (Huffman or arithmetic). + * Prediction, undifferencing. + * Point transform, sample size scaling. + Postprocessing: + * Upsampling. Optionally, this step may be able to do more general + rescaling of the image. + * Color space conversion (e.g., YCbCr to RGB). This step may also + provide gamma adjustment [ currently it does not ]. + * Optional color quantization (e.g., reduction to 256 colors). + * Optional color precision reduction (e.g., 24-bit to 15-bit color). + [This feature is not currently implemented.] + +We also need overall control, marker parsing, and a data source module. +The support code (memory management & error handling) can be shared with +the compression half of the library. + +There may be several implementations of each of these elements, particularly +in the decompressor, where a wide range of speed/quality tradeoffs is very +useful. It must be understood that some of the best speedups involve +merging adjacent steps in the pipeline. For example, upsampling, color space +conversion, and color quantization might all be done at once when using a +low-quality ordered-dither technique. The system architecture is designed to +allow such merging where appropriate. + + +Note: it is convenient to regard edge expansion (padding to block boundaries) +as a preprocessing/postprocessing function, even though the JPEG spec includes +it in compression/decompression. We do this because downsampling/upsampling +can be simplified a little if they work on padded data: it's not necessary to +have special cases at the right and bottom edges. Therefore the interface +buffer is always an integral number of blocks wide and high, and we expect +compression preprocessing to pad the source data properly. Padding will occur +only to the next block (8-sample) boundary. In an interleaved-scan situation, +additional dummy blocks may be used to fill out MCUs, but the MCU assembly and +disassembly logic will create or discard these blocks internally. (This is +advantageous for speed reasons, since we avoid DCTing the dummy blocks. +It also permits a small reduction in file size, because the compressor can +choose dummy block contents so as to minimize their size in compressed form. +Finally, it makes the interface buffer specification independent of whether +the file is actually interleaved or not.) Applications that wish to deal +directly with the downsampled data must provide similar buffering and padding +for odd-sized images. + + +*** Poor man's object-oriented programming *** + +It should be clear by now that we have a lot of quasi-independent processing +steps, many of which have several possible behaviors. To avoid cluttering the +code with lots of switch statements, we use a simple form of object-style +programming to separate out the different possibilities. + +For example, two different color quantization algorithms could be implemented +as two separate modules that present the same external interface; at runtime, +the calling code will access the proper module indirectly through an "object". + +We can get the limited features we need while staying within portable C. +The basic tool is a function pointer. An "object" is just a struct +containing one or more function pointer fields, each of which corresponds to +a method name in real object-oriented languages. During initialization we +fill in the function pointers with references to whichever module we have +determined we need to use in this run. Then invocation of the module is done +by indirecting through a function pointer; on most machines this is no more +expensive than a switch statement, which would be the only other way of +making the required run-time choice. The really significant benefit, of +course, is keeping the source code clean and well structured. + +We can also arrange to have private storage that varies between different +implementations of the same kind of object. We do this by making all the +module-specific object structs be separately allocated entities, which will +be accessed via pointers in the master compression or decompression struct. +The "public" fields or methods for a given kind of object are specified by +a commonly known struct. But a module's initialization code can allocate +a larger struct that contains the common struct as its first member, plus +additional private fields. With appropriate pointer casting, the module's +internal functions can access these private fields. (For a simple example, +see jdatadst.c, which implements the external interface specified by struct +jpeg_destination_mgr, but adds extra fields.) + +(Of course this would all be a lot easier if we were using C++, but we are +not yet prepared to assume that everyone has a C++ compiler.) + +An important benefit of this scheme is that it is easy to provide multiple +versions of any method, each tuned to a particular case. While a lot of +precalculation might be done to select an optimal implementation of a method, +the cost per invocation is constant. For example, the upsampling step might +have a "generic" method, plus one or more "hardwired" methods for the most +popular sampling factors; the hardwired methods would be faster because they'd +use straight-line code instead of for-loops. The cost to determine which +method to use is paid only once, at startup, and the selection criteria are +hidden from the callers of the method. + +This plan differs a little bit from usual object-oriented structures, in that +only one instance of each object class will exist during execution. The +reason for having the class structure is that on different runs we may create +different instances (choose to execute different modules). You can think of +the term "method" as denoting the common interface presented by a particular +set of interchangeable functions, and "object" as denoting a group of related +methods, or the total shared interface behavior of a group of modules. + + +*** Overall control structure *** + +We previously mentioned the need for overall control logic in the compression +and decompression libraries. In IJG implementations prior to v5, overall +control was mostly provided by "pipeline control" modules, which proved to be +large, unwieldy, and hard to understand. To improve the situation, the +control logic has been subdivided into multiple modules. The control modules +consist of: + +1. Master control for module selection and initialization. This has two +responsibilities: + + 1A. Startup initialization at the beginning of image processing. + The individual processing modules to be used in this run are selected + and given initialization calls. + + 1B. Per-pass control. This determines how many passes will be performed + and calls each active processing module to configure itself + appropriately at the beginning of each pass. End-of-pass processing, + where necessary, is also invoked from the master control module. + + Method selection is partially distributed, in that a particular processing + module may contain several possible implementations of a particular method, + which it will select among when given its initialization call. The master + control code need only be concerned with decisions that affect more than + one module. + +2. Data buffering control. A separate control module exists for each + inter-processing-step data buffer. This module is responsible for + invoking the processing steps that write or read that data buffer. + +Each buffer controller sees the world as follows: + +input data => processing step A => buffer => processing step B => output data + | | | + ------------------ controller ------------------ + +The controller knows the dataflow requirements of steps A and B: how much data +they want to accept in one chunk and how much they output in one chunk. Its +function is to manage its buffer and call A and B at the proper times. + +A data buffer control module may itself be viewed as a processing step by a +higher-level control module; thus the control modules form a binary tree with +elementary processing steps at the leaves of the tree. + +The control modules are objects. A considerable amount of flexibility can +be had by replacing implementations of a control module. For example: +* Merging of adjacent steps in the pipeline is done by replacing a control + module and its pair of processing-step modules with a single processing- + step module. (Hence the possible merges are determined by the tree of + control modules.) +* In some processing modes, a given interstep buffer need only be a "strip" + buffer large enough to accommodate the desired data chunk sizes. In other + modes, a full-image buffer is needed and several passes are required. + The control module determines which kind of buffer is used and manipulates + virtual array buffers as needed. One or both processing steps may be + unaware of the multi-pass behavior. + +In theory, we might be able to make all of the data buffer controllers +interchangeable and provide just one set of implementations for all. In +practice, each one contains considerable special-case processing for its +particular job. The buffer controller concept should be regarded as an +overall system structuring principle, not as a complete description of the +task performed by any one controller. + + +*** Codec object structure *** + +As noted above, this library supports both the lossy (DCT-based) and lossless +JPEG processes. Because these processes have little in common with one another +(and their implementations share very little code), we need to provide a way to +isloate the underlying JPEG process from the rest of the library. This is +accomplished by introducing an abstract "codec object" which acts a generic +interface to the JPEG (de)compressor proper. + +Using the power of the object-oriented scheme described above, we build the +lossy and lossless modules as two separate implementations of the codec object. +Switching between lossy and lossless processes then becomes as trivial as +assigning the appropriate method pointers during initialization of the library. + + +*** Compression object structure *** + +Here is a sketch of the logical structure of the JPEG compression library: + + |-- Colorspace conversion + |-- Preprocessing controller --| + | |-- Downsampling + | +Main controller --| + | /--> Lossy codec + | / + |-- Compression codec < *OR* + \ + \--> Lossless codec + + +where the lossy codec looks like: + + |-- Forward DCT, quantize +<-- Coefficient controller --| + |-- Entropy encoding + + +and the lossless codec looks like: + + |-- Point transformation + | +<-- Difference controller --|-- Prediction, differencing + | + |-- Lossless entropy encoding + + +This sketch also describes the flow of control (subroutine calls) during +typical image data processing. Each of the components shown in the diagram is +an "object" which may have several different implementations available. One +or more source code files contain the actual implementation(s) of each object. + +The objects shown above are: + +* Main controller: buffer controller for the subsampled-data buffer, which + holds the preprocessed input data. This controller invokes preprocessing to + fill the subsampled-data buffer, and JPEG compression to empty it. There is + usually no need for a full-image buffer here; a strip buffer is adequate. + +* Preprocessing controller: buffer controller for the downsampling input data + buffer, which lies between colorspace conversion and downsampling. Note + that a unified conversion/downsampling module would probably replace this + controller entirely. + +* Colorspace conversion: converts application image data into the desired + JPEG color space; also changes the data from pixel-interleaved layout to + separate component planes. Processes one pixel row at a time. + +* Downsampling: performs reduction of chroma components as required. + Optionally may perform pixel-level smoothing as well. Processes a "row + group" at a time, where a row group is defined as Vmax pixel rows of each + component before downsampling, and Vk sample rows afterwards (remember Vk + differs across components). Some downsampling or smoothing algorithms may + require context rows above and below the current row group; the + preprocessing controller is responsible for supplying these rows via proper + buffering. The downsampler is responsible for edge expansion at the right + edge (i.e., extending each sample row to a multiple of 8 samples); but the + preprocessing controller is responsible for vertical edge expansion (i.e., + duplicating the bottom sample row as needed to make a multiple of 8 rows). + +* Coefficient controller: buffer controller for the DCT-coefficient data. + This controller handles MCU assembly, including insertion of dummy DCT + blocks when needed at the right or bottom edge. When performing + Huffman-code optimization or emitting a multiscan JPEG file, this + controller is responsible for buffering the full image. The equivalent of + one fully interleaved MCU row of subsampled data is processed per call, + even when the JPEG file is noninterleaved. + +* Forward DCT and quantization: Perform DCT, quantize, and emit coefficients. + Works on one or more DCT blocks at a time. (Note: the coefficients are now + emitted in normal array order, which the entropy encoder is expected to + convert to zigzag order as necessary. Prior versions of the IJG code did + the conversion to zigzag order within the quantization step.) + +* Entropy encoding: Perform Huffman or arithmetic entropy coding and emit the + coded data to the data destination module. Works on one MCU per call. + For progressive JPEG, the same DCT blocks are fed to the entropy coder + during each pass, and the coder must emit the appropriate subset of + coefficients. + +* Difference controller: buffer controller for the spatial difference data. + When emitting a multiscan JPEG file, this controller is responsible for + buffering the full image. The equivalent of one fully interleaved MCU row + of subsampled data is processed per call, even when the JPEG file is + noninterleaved. + +* Point transformation: Scale the data down by the point transformation + parameter. + +* Prediction and differencing: Calculate the predictor and subtract it + from the input. Works on one scanline per call. The difference + controller supplies the prior scanline which is used for prediction. + +* Lossless entropy encoding: Perform Huffman or arithmetic entropy coding and + emit the coded data to the data destination module. This module handles MCU + assembly. Works on one MCU-row per call. + +In addition to the above objects, the compression library includes these +objects: + +* Master control: determines the number of passes required, controls overall + and per-pass initialization of the other modules. + +* Marker writing: generates JPEG markers (except for RSTn, which is emitted + by the entropy encoder when needed). + +* Data destination manager: writes the output JPEG datastream to its final + destination (e.g., a file). The destination manager supplied with the + library knows how to write to a stdio stream; for other behaviors, the + surrounding application may provide its own destination manager. + +* Memory manager: allocates and releases memory, controls virtual arrays + (with backing store management, where required). + +* Error handler: performs formatting and output of error and trace messages; + determines handling of nonfatal errors. The surrounding application may + override some or all of this object's methods to change error handling. + +* Progress monitor: supports output of "percent-done" progress reports. + This object represents an optional callback to the surrounding application: + if wanted, it must be supplied by the application. + +The error handler, destination manager, and progress monitor objects are +defined as separate objects in order to simplify application-specific +customization of the JPEG library. A surrounding application may override +individual methods or supply its own all-new implementation of one of these +objects. The object interfaces for these objects are therefore treated as +part of the application interface of the library, whereas the other objects +are internal to the library. + +The error handler and memory manager are shared by JPEG compression and +decompression; the progress monitor, if used, may be shared as well. + + +*** Decompression object structure *** + +Here is a sketch of the logical structure of the JPEG decompression library: + + /--> Lossy codec + / + |-- Decompression codec < *OR* + | \ + | \--> Lossless codec +Main controller --| + | + | |-- Upsampling + |-- Postprocessing controller --| |-- Colorspace conversion + |-- Color quantization + |-- Color precision reduction + + +where the lossy codec looks like: + + |-- Entropy decoding +<-- Coefficient controller --| + |-- Dequantize, Inverse DCT + + +and the lossless codec looks like: + + |-- Lossless entropy decoding + | +<-- Difference controller --|-- Prediction, undifferencing + | + |-- Point transformation, sample size scaling + + +As before, this diagram also represents typical control flow. The objects +shown are: + +* Main controller: buffer controller for the subsampled-data buffer, which + holds the output of JPEG decompression proper. This controller's primary + task is to feed the postprocessing procedure. Some upsampling algorithms + may require context rows above and below the current row group; when this + is true, the main controller is responsible for managing its buffer so as + to make context rows available. In the current design, the main buffer is + always a strip buffer; a full-image buffer is never required. + +* Coefficient controller: buffer controller for the DCT-coefficient data. + This controller handles MCU disassembly, including deletion of any dummy + DCT blocks at the right or bottom edge. When reading a multiscan JPEG + file, this controller is responsible for buffering the full image. + (Buffering DCT coefficients, rather than samples, is necessary to support + progressive JPEG.) The equivalent of one fully interleaved MCU row of + subsampled data is processed per call, even when the source JPEG file is + noninterleaved. + +* Entropy decoding: Read coded data from the data source module and perform + Huffman or arithmetic entropy decoding. Works on one MCU per call. + For progressive JPEG decoding, the coefficient controller supplies the prior + coefficients of each MCU (initially all zeroes), which the entropy decoder + modifies in each scan. + +* Dequantization and inverse DCT: like it says. Note that the coefficients + buffered by the coefficient controller have NOT been dequantized; we + merge dequantization and inverse DCT into a single step for speed reasons. + When scaled-down output is asked for, simplified DCT algorithms may be used + that emit only 1x1, 2x2, or 4x4 samples per DCT block, not the full 8x8. + Works on one DCT block at a time. + +* Difference controller: buffer controller for the spatial difference data. + When reading a multiscan JPEG file, this controller is responsible for + buffering the full image. The equivalent of one fully interleaved MCU row + is processed per call, even when the source JPEG file is noninterleaved. + +* Lossless entropy decoding: Read coded data from the data source module and + perform Huffman or arithmetic entropy decoding. Works on one MCU-row per + call. + +* Prediction and undifferencing: Calculate the predictor and add it to the + decoded difference. Works on one scanline per call. The difference + controller supplies the prior scanline which is used for prediction. + +* Point transform and sample size scaling: Scale the data up by the point + transformation parameter and scale it down to fit into the compiled-in + sample size. + +* Postprocessing controller: buffer controller for the color quantization + input buffer, when quantization is in use. (Without quantization, this + controller just calls the upsampler.) For two-pass quantization, this + controller is responsible for buffering the full-image data. + +* Upsampling: restores chroma components to full size. (May support more + general output rescaling, too. Note that if undersized DCT outputs have + been emitted by the DCT module, this module must adjust so that properly + sized outputs are created.) Works on one row group at a time. This module + also calls the color conversion module, so its top level is effectively a + buffer controller for the upsampling->color conversion buffer. However, in + all but the highest-quality operating modes, upsampling and color + conversion are likely to be merged into a single step. + +* Colorspace conversion: convert from JPEG color space to output color space, + and change data layout from separate component planes to pixel-interleaved. + Works on one pixel row at a time. + +* Color quantization: reduce the data to colormapped form, using either an + externally specified colormap or an internally generated one. This module + is not used for full-color output. Works on one pixel row at a time; may + require two passes to generate a color map. Note that the output will + always be a single component representing colormap indexes. In the current + design, the output values are JSAMPLEs, so an 8-bit compilation cannot + quantize to more than 256 colors. This is unlikely to be a problem in + practice. + +* Color reduction: this module handles color precision reduction, e.g., + generating 15-bit color (5 bits/primary) from JPEG's 24-bit output. + Not quite clear yet how this should be handled... should we merge it with + colorspace conversion??? + +Note that some high-speed operating modes might condense the entire +postprocessing sequence to a single module (upsample, color convert, and +quantize in one step). + +In addition to the above objects, the decompression library includes these +objects: + +* Master control: determines the number of passes required, controls overall + and per-pass initialization of the other modules. This is subdivided into + input and output control: jdinput.c controls only input-side processing, + while jdmaster.c handles overall initialization and output-side control. + +* Marker reading: decodes JPEG markers (except for RSTn). + +* Data source manager: supplies the input JPEG datastream. The source + manager supplied with the library knows how to read from a stdio stream; + for other behaviors, the surrounding application may provide its own source + manager. + +* Memory manager: same as for compression library. + +* Error handler: same as for compression library. + +* Progress monitor: same as for compression library. + +As with compression, the data source manager, error handler, and progress +monitor are candidates for replacement by a surrounding application. + + +*** Decompression input and output separation *** + +To support efficient incremental display of progressive JPEG files, the +decompressor is divided into two sections that can run independently: + +1. Data input includes marker parsing, entropy decoding, and input into the + coefficient controller's DCT coefficient buffer. Note that this + processing is relatively cheap and fast. + +2. Data output reads from the DCT coefficient buffer and performs the IDCT + and all postprocessing steps. + +For a progressive JPEG file, the data input processing is allowed to get +arbitrarily far ahead of the data output processing. (This occurs only +if the application calls jpeg_consume_input(); otherwise input and output +run in lockstep, since the input section is called only when the output +section needs more data.) In this way the application can avoid making +extra display passes when data is arriving faster than the display pass +can run. Furthermore, it is possible to abort an output pass without +losing anything, since the coefficient buffer is read-only as far as the +output section is concerned. See libjpeg.doc for more detail. + +A full-image coefficient array is only created if the JPEG file has multiple +scans (or if the application specifies buffered-image mode anyway). When +reading a single-scan file, the coefficient controller normally creates only +a one-MCU buffer, so input and output processing must run in lockstep in this +case. jpeg_consume_input() is effectively a no-op in this situation. + +The main impact of dividing the decompressor in this fashion is that we must +be very careful with shared variables in the cinfo data structure. Each +variable that can change during the course of decompression must be +classified as belonging to data input or data output, and each section must +look only at its own variables. For example, the data output section may not +depend on any of the variables that describe the current scan in the JPEG +file, because these may change as the data input section advances into a new +scan. + +The progress monitor is (somewhat arbitrarily) defined to treat input of the +file as one pass when buffered-image mode is not used, and to ignore data +input work completely when buffered-image mode is used. Note that the +library has no reliable way to predict the number of passes when dealing +with a progressive JPEG file, nor can it predict the number of output passes +in buffered-image mode. So the work estimate is inherently bogus anyway. + +No comparable division is currently made in the compression library, because +there isn't any real need for it. + + +*** Data formats *** + +Arrays of pixel sample values use the following data structure: + + typedef something JSAMPLE; a pixel component value, 0..MAXJSAMPLE + typedef JSAMPLE *JSAMPROW; ptr to a row of samples + typedef JSAMPROW *JSAMPARRAY; ptr to a list of rows + typedef JSAMPARRAY *JSAMPIMAGE; ptr to a list of color-component arrays + +The basic element type JSAMPLE will typically be one of unsigned char, +(signed) char, or short. Short will be used if samples wider than 8 bits are +to be supported (this is a compile-time option). Otherwise, unsigned char is +used if possible. If the compiler only supports signed chars, then it is +necessary to mask off the value when reading. Thus, all reads of JSAMPLE +values must be coded as "GETJSAMPLE(value)", where the macro will be defined +as "((value) & 0xFF)" on signed-char machines and "((int) (value))" elsewhere. + +With these conventions, JSAMPLE values can be assumed to be >= 0. This helps +simplify correct rounding during downsampling, etc. The JPEG standard's +specification that sample values run from -128..127 is accommodated by +subtracting 128 just as the sample value is copied into the source array for +the DCT step (this will be an array of signed ints). Similarly, during +decompression the output of the IDCT step will be immediately shifted back to +0..255. (NB: different values are required when 12-bit samples are in use. +The code is written in terms of MAXJSAMPLE and CENTERJSAMPLE, which will be +defined as 255 and 128 respectively in an 8-bit implementation, and as 4095 +and 2048 in a 12-bit implementation.) + +We use a pointer per row, rather than a two-dimensional JSAMPLE array. This +choice costs only a small amount of memory and has several benefits: +* Code using the data structure doesn't need to know the allocated width of + the rows. This simplifies edge expansion/compression, since we can work + in an array that's wider than the logical picture width. +* Indexing doesn't require multiplication; this is a performance win on many + machines. +* Arrays with more than 64K total elements can be supported even on machines + where malloc() cannot allocate chunks larger than 64K. +* The rows forming a component array may be allocated at different times + without extra copying. This trick allows some speedups in smoothing steps + that need access to the previous and next rows. + +Note that each color component is stored in a separate array; we don't use the +traditional layout in which the components of a pixel are stored together. +This simplifies coding of modules that work on each component independently, +because they don't need to know how many components there are. Furthermore, +we can read or write each component to a temporary file independently, which +is helpful when dealing with noninterleaved JPEG files. + +In general, a specific sample value is accessed by code such as + GETJSAMPLE(image[colorcomponent][row][col]) +where col is measured from the image left edge, but row is measured from the +first sample row currently in memory. Either of the first two indexings can +be precomputed by copying the relevant pointer. + + +Since most image-processing applications prefer to work on images in which +the components of a pixel are stored together, the data passed to or from the +surrounding application uses the traditional convention: a single pixel is +represented by N consecutive JSAMPLE values, and an image row is an array of +(# of color components)*(image width) JSAMPLEs. One or more rows of data can +be represented by a pointer of type JSAMPARRAY in this scheme. This scheme is +converted to component-wise storage inside the JPEG library. (Applications +that want to skip JPEG preprocessing or postprocessing will have to contend +with component-wise storage.) + + +Arrays of DCT-coefficient values use the following data structure: + + typedef short JCOEF; a 16-bit signed integer + typedef JCOEF JBLOCK[DCTSIZE2]; an 8x8 block of coefficients + typedef JBLOCK *JBLOCKROW; ptr to one horizontal row of 8x8 blocks + typedef JBLOCKROW *JBLOCKARRAY; ptr to a list of such rows + typedef JBLOCKARRAY *JBLOCKIMAGE; ptr to a list of color component arrays + +The underlying type is at least a 16-bit signed integer; while "short" is big +enough on all machines of interest, on some machines it is preferable to use +"int" for speed reasons, despite the storage cost. Coefficients are grouped +into 8x8 blocks (but we always use #defines DCTSIZE and DCTSIZE2 rather than +"8" and "64"). + +The contents of a coefficient block may be in either "natural" or zigzagged +order, and may be true values or divided by the quantization coefficients, +depending on where the block is in the processing pipeline. In the current +library, coefficient blocks are kept in natural order everywhere; the entropy +codecs zigzag or dezigzag the data as it is written or read. The blocks +contain quantized coefficients everywhere outside the DCT/IDCT subsystems. +(This latter decision may need to be revisited to support variable +quantization a la JPEG Part 3.) + +Notice that the allocation unit is now a row of 8x8 blocks, corresponding to +eight rows of samples. Otherwise the structure is much the same as for +samples, and for the same reasons. + +On machines where malloc() can't handle a request bigger than 64Kb, this data +structure limits us to rows of less than 512 JBLOCKs, or a picture width of +4000+ pixels. This seems an acceptable restriction. + + +On 80x86 machines, the bottom-level pointer types (JSAMPROW and JBLOCKROW) +must be declared as "far" pointers, but the upper levels can be "near" +(implying that the pointer lists are allocated in the DS segment). +We use a #define symbol FAR, which expands to the "far" keyword when +compiling on 80x86 machines and to nothing elsewhere. + + +*** Suspendable processing *** + +In some applications it is desirable to use the JPEG library as an +incremental, memory-to-memory filter. In this situation the data source or +destination may be a limited-size buffer, and we can't rely on being able to +empty or refill the buffer at arbitrary times. Instead the application would +like to have control return from the library at buffer overflow/underrun, and +then resume compression or decompression at a later time. + +This scenario is supported for simple cases. (For anything more complex, we +recommend that the application "bite the bullet" and develop real multitasking +capability.) The libjpeg.doc file goes into more detail about the usage and +limitations of this capability; here we address the implications for library +structure. + +The essence of the problem is that the entropy codec (coder or decoder) must +be prepared to stop at arbitrary times. In turn, the controllers that call +the entropy codec must be able to stop before having produced or consumed all +the data that they normally would handle in one call. That part is reasonably +straightforward: we make the controller call interfaces include "progress +counters" which indicate the number of data chunks successfully processed, and +we require callers to test the counter rather than just assume all of the data +was processed. + +Rather than trying to restart at an arbitrary point, the current Huffman +codecs are designed to restart at the beginning of the current MCU after a +suspension due to buffer overflow/underrun. At the start of each call, the +codec's internal state is loaded from permanent storage (in the JPEG object +structures) into local variables. On successful completion of the MCU, the +permanent state is updated. (This copying is not very expensive, and may even +lead to *improved* performance if the local variables can be registerized.) +If a suspension occurs, the codec simply returns without updating the state, +thus effectively reverting to the start of the MCU. Note that this implies +leaving some data unprocessed in the source/destination buffer (ie, the +compressed partial MCU). The data source/destination module interfaces are +specified so as to make this possible. This also implies that the data buffer +must be large enough to hold a worst-case compressed MCU; a couple thousand +bytes should be enough. + +In a successive-approximation AC refinement scan, the progressive Huffman +decoder has to be able to undo assignments of newly nonzero coefficients if it +suspends before the MCU is complete, since decoding requires distinguishing +previously-zero and previously-nonzero coefficients. This is a bit tedious +but probably won't have much effect on performance. Other variants of Huffman +decoding need not worry about this, since they will just store the same values +again if forced to repeat the MCU. + +This approach would probably not work for an arithmetic codec, since its +modifiable state is quite large and couldn't be copied cheaply. Instead it +would have to suspend and resume exactly at the point of the buffer end. + +The JPEG marker reader is designed to cope with suspension at an arbitrary +point. It does so by backing up to the start of the marker parameter segment, +so the data buffer must be big enough to hold the largest marker of interest. +Again, a couple KB should be adequate. (A special "skip" convention is used +to bypass COM and APPn markers, so these can be larger than the buffer size +without causing problems; otherwise a 64K buffer would be needed in the worst +case.) + +The JPEG marker writer currently does *not* cope with suspension. I feel that +this is not necessary; it is much easier simply to require the application to +ensure there is enough buffer space before starting. (An empty 2K buffer is +more than sufficient for the header markers; and ensuring there are a dozen or +two bytes available before calling jpeg_finish_compress() will suffice for the +trailer.) This would not work for writing multi-scan JPEG files, but +we simply do not intend to support that capability with suspension. + + +*** Memory manager services *** + +The JPEG library's memory manager controls allocation and deallocation of +memory, and it manages large "virtual" data arrays on machines where the +operating system does not provide virtual memory. Note that the same +memory manager serves both compression and decompression operations. + +In all cases, allocated objects are tied to a particular compression or +decompression master record, and they will be released when that master +record is destroyed. + +The memory manager does not provide explicit deallocation of objects. +Instead, objects are created in "pools" of free storage, and a whole pool +can be freed at once. This approach helps prevent storage-leak bugs, and +it speeds up operations whenever malloc/free are slow (as they often are). +The pools can be regarded as lifetime identifiers for objects. Two +pools/lifetimes are defined: + * JPOOL_PERMANENT lasts until master record is destroyed + * JPOOL_IMAGE lasts until done with image (JPEG datastream) +Permanent lifetime is used for parameters and tables that should be carried +across from one datastream to another; this includes all application-visible +parameters. Image lifetime is used for everything else. (A third lifetime, +JPOOL_PASS = one processing pass, was originally planned. However it was +dropped as not being worthwhile. The actual usage patterns are such that the +peak memory usage would be about the same anyway; and having per-pass storage +substantially complicates the virtual memory allocation rules --- see below.) + +The memory manager deals with three kinds of object: +1. "Small" objects. Typically these require no more than 10K-20K total. +2. "Large" objects. These may require tens to hundreds of K depending on + image size. Semantically they behave the same as small objects, but we + distinguish them for two reasons: + * On MS-DOS machines, large objects are referenced by FAR pointers, + small objects by NEAR pointers. + * Pool allocation heuristics may differ for large and small objects. + Note that individual "large" objects cannot exceed the size allowed by + type size_t, which may be 64K or less on some machines. +3. "Virtual" objects. These are large 2-D arrays of JSAMPLEs or JBLOCKs + (typically large enough for the entire image being processed). The + memory manager provides stripwise access to these arrays. On machines + without virtual memory, the rest of the array may be swapped out to a + temporary file. + +(Note: JSAMPARRAY and JBLOCKARRAY data structures are a combination of large +objects for the data proper and small objects for the row pointers. For +convenience and speed, the memory manager provides single routines to create +these structures. Similarly, virtual arrays include a small control block +and a JSAMPARRAY or JBLOCKARRAY working buffer, all created with one call.) + +In the present implementation, virtual arrays are only permitted to have image +lifespan. (Permanent lifespan would not be reasonable, and pass lifespan is +not very useful since a virtual array's raison d'etre is to store data for +multiple passes through the image.) We also expect that only "small" objects +will be given permanent lifespan, though this restriction is not required by +the memory manager. + +In a non-virtual-memory machine, some performance benefit can be gained by +making the in-memory buffers for virtual arrays be as large as possible. +(For small images, the buffers might fit entirely in memory, so blind +swapping would be very wasteful.) The memory manager will adjust the height +of the buffers to fit within a prespecified maximum memory usage. In order +to do this in a reasonably optimal fashion, the manager needs to allocate all +of the virtual arrays at once. Therefore, there isn't a one-step allocation +routine for virtual arrays; instead, there is a "request" routine that simply +allocates the control block, and a "realize" routine (called just once) that +determines space allocation and creates all of the actual buffers. The +realize routine must allow for space occupied by non-virtual large objects. +(We don't bother to factor in the space needed for small objects, on the +grounds that it isn't worth the trouble.) + +To support all this, we establish the following protocol for doing business +with the memory manager: + 1. Modules must request virtual arrays (which may have only image lifespan) + during the initial setup phase, i.e., in their jinit_xxx routines. + 2. All "large" objects (including JSAMPARRAYs and JBLOCKARRAYs) must also be + allocated during initial setup. + 3. realize_virt_arrays will be called at the completion of initial setup. + The above conventions ensure that sufficient information is available + for it to choose a good size for virtual array buffers. +Small objects of any lifespan may be allocated at any time. We expect that +the total space used for small objects will be small enough to be negligible +in the realize_virt_arrays computation. + +In a virtual-memory machine, we simply pretend that the available space is +infinite, thus causing realize_virt_arrays to decide that it can allocate all +the virtual arrays as full-size in-memory buffers. The overhead of the +virtual-array access protocol is very small when no swapping occurs. + +A virtual array can be specified to be "pre-zeroed"; when this flag is set, +never-yet-written sections of the array are set to zero before being made +available to the caller. If this flag is not set, never-written sections +of the array contain garbage. (This feature exists primarily because the +equivalent logic would otherwise be needed in jdcoefct.c for progressive +JPEG mode; we may as well make it available for possible other uses.) + +The first write pass on a virtual array is required to occur in top-to-bottom +order; read passes, as well as any write passes after the first one, may +access the array in any order. This restriction exists partly to simplify +the virtual array control logic, and partly because some file systems may not +support seeking beyond the current end-of-file in a temporary file. The main +implication of this restriction is that rearrangement of rows (such as +converting top-to-bottom data order to bottom-to-top) must be handled while +reading data out of the virtual array, not while putting it in. + + +*** Memory manager internal structure *** + +To isolate system dependencies as much as possible, we have broken the +memory manager into two parts. There is a reasonably system-independent +"front end" (jmemmgr.c) and a "back end" that contains only the code +likely to change across systems. All of the memory management methods +outlined above are implemented by the front end. The back end provides +the following routines for use by the front end (none of these routines +are known to the rest of the JPEG code): + +jpeg_mem_init, jpeg_mem_term system-dependent initialization/shutdown + +jpeg_get_small, jpeg_free_small interface to malloc and free library routines + (or their equivalents) + +jpeg_get_large, jpeg_free_large interface to FAR malloc/free in MSDOS machines; + else usually the same as + jpeg_get_small/jpeg_free_small + +jpeg_mem_available estimate available memory + +jpeg_open_backing_store create a backing-store object + +read_backing_store, manipulate a backing-store object +write_backing_store, +close_backing_store + +On some systems there will be more than one type of backing-store object +(specifically, in MS-DOS a backing store file might be an area of extended +memory as well as a disk file). jpeg_open_backing_store is responsible for +choosing how to implement a given object. The read/write/close routines +are method pointers in the structure that describes a given object; this +lets them be different for different object types. + +It may be necessary to ensure that backing store objects are explicitly +released upon abnormal program termination. For example, MS-DOS won't free +extended memory by itself. To support this, we will expect the main program +or surrounding application to arrange to call self_destruct (typically via +jpeg_destroy) upon abnormal termination. This may require a SIGINT signal +handler or equivalent. We don't want to have the back end module install its +own signal handler, because that would pre-empt the surrounding application's +ability to control signal handling. + +The IJG distribution includes several memory manager back end implementations. +Usually the same back end should be suitable for all applications on a given +system, but it is possible for an application to supply its own back end at +need. + + +*** Implications of DNL marker *** + +Some JPEG files may use a DNL marker to postpone definition of the image +height (this would be useful for a fax-like scanner's output, for instance). +In these files the SOF marker claims the image height is 0, and you only +find out the true image height at the end of the first scan. + +We could read these files as follows: +1. Upon seeing zero image height, replace it by 65535 (the maximum allowed). +2. When the DNL is found, update the image height in the global image + descriptor. +This implies that control modules must avoid making copies of the image +height, and must re-test for termination after each MCU row. This would +be easy enough to do. + +In cases where image-size data structures are allocated, this approach will +result in very inefficient use of virtual memory or much-larger-than-necessary +temporary files. This seems acceptable for something that probably won't be a +mainstream usage. People might have to forgo use of memory-hogging options +(such as two-pass color quantization or noninterleaved JPEG files) if they +want efficient conversion of such files. (One could improve efficiency by +demanding a user-supplied upper bound for the height, less than 65536; in most +cases it could be much less.) + +The standard also permits the SOF marker to overestimate the image height, +with a DNL to give the true, smaller height at the end of the first scan. +This would solve the space problems if the overestimate wasn't too great. +However, it implies that you don't even know whether DNL will be used. + +This leads to a couple of very serious objections: +1. Testing for a DNL marker must occur in the inner loop of the decompressor's + Huffman decoder; this implies a speed penalty whether the feature is used + or not. +2. There is no way to hide the last-minute change in image height from an + application using the decoder. Thus *every* application using the IJG + library would suffer a complexity penalty whether it cared about DNL or + not. +We currently do not support DNL because of these problems. + +A different approach is to insist that DNL-using files be preprocessed by a +separate program that reads ahead to the DNL, then goes back and fixes the SOF +marker. This is a much simpler solution and is probably far more efficient. +Even if one wants piped input, buffering the first scan of the JPEG file needs +a lot smaller temp file than is implied by the maximum-height method. For +this approach we'd simply treat DNL as a no-op in the decompressor (at most, +check that it matches the SOF image height). + +We will not worry about making the compressor capable of outputting DNL. +Something similar to the first scheme above could be applied if anyone ever +wants to make that work.