/*========================================================================= * * Copyright NumFOCUS * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0.txt * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *=========================================================================*/ #include "itkMRCHeaderObject.h" #include "itkMRCImageIOPrivate.h" #include "itkByteSwapper.h" namespace itk { void MRCHeaderObject::DeepCopy(ConstPointer h) { memcpy(&this->m_Header, &h->m_Header, sizeof(Header)); this->m_ExtendedHeaderSize = h->m_ExtendedHeaderSize; if (this->m_ExtendedHeaderSize) { delete[] static_cast(this->m_ExtendedHeader); this->m_ExtendedHeader = new char[this->m_ExtendedHeaderSize]; memcpy(this->m_ExtendedHeader, h->m_ExtendedHeader, this->m_ExtendedHeaderSize); } this->m_BigEndianHeader = h->m_BigEndianHeader; if (h->m_ExtendedFeiHeader) { this->m_ExtendedFeiHeader = static_cast(this->m_ExtendedHeader); } else { this->m_ExtendedFeiHeader = nullptr; } } const MRCHeaderObject::Header & MRCHeaderObject::GetHeader() const { return this->m_Header; } bool MRCHeaderObject::SetHeader(const Header * buffer) { if (!buffer) { return false; } const auto * _header = static_cast(buffer); memcpy(&this->m_Header, buffer, sizeof(Header)); // the cmap field must should either be the magic field or 0 if (strncmp(_header->cmap, magicMAP, 4) != 0 && memcmp(_header->cmap, "\0\0\0\0", 4) != 0) { itkWarningMacro("The header's cmap field does not have expected values"); return false; } // the stamp may help up tell the endian of the header // or it's an older header if (_header->stamp[0] == 17) { this->m_BigEndianHeader = true; this->swapHeader(this->m_BigEndianHeader); } else if (_header->stamp[0] == 68) { this->m_BigEndianHeader = false; this->swapHeader(this->m_BigEndianHeader); } else if (_header->stamp[0] == 0 && _header->stamp[1] == 0 && _header->stamp[2] == 0 && _header->stamp[3] == 0) { this->m_BigEndianHeader = ByteSwapper::SystemIsBigEndian(); // do a check to see which byte order make sense if (this->m_Header.mapc < 1 || this->m_Header.mapc > 3 || this->m_Header.mapr < 1 || this->m_Header.mapr > 3 || this->m_Header.maps < 1 || this->m_Header.maps > 3) { this->m_BigEndianHeader = !this->m_BigEndianHeader; this->swapHeader(this->m_BigEndianHeader); } } else { // the stamp is not expected itkWarningMacro("The header's stamp field does not have expected values"); return false; } // clean up delete[] static_cast(this->m_ExtendedHeader); this->m_ExtendedHeader = nullptr; this->m_ExtendedFeiHeader = nullptr; this->m_ExtendedHeaderSize = this->m_Header.next; // check to make sure the data makes sense if (this->m_Header.nx <= 0 || this->m_Header.ny <= 0 || this->m_Header.nz <= 0 || (this->m_Header.nx > 65535 || this->m_Header.ny > 65535 || this->m_Header.nz > 65535) || this->m_Header.mapc < MRCHEADER_MAP_X || this->m_Header.mapc > MRCHEADER_MAP_Z || this->m_Header.mapr < MRCHEADER_MAP_X || this->m_Header.mapr > MRCHEADER_MAP_Z || this->m_Header.maps < MRCHEADER_MAP_X || this->m_Header.maps > MRCHEADER_MAP_Z || this->m_Header.nxstart >= this->m_Header.nx || this->m_Header.nystart >= this->m_Header.ny || this->m_Header.nzstart >= this->m_Header.nz) { itkWarningMacro("Some header data does not have sensable values"); return false; } if (this->m_Header.nxstart != 0 || this->m_Header.nystart != 0 || this->m_Header.nzstart != 0) { itkWarningMacro("The header's nxstart, nystart and nzstart fields are not supported correctly"); } return true; } SizeValueType MRCHeaderObject::GetExtendedHeaderSize() const { return this->m_ExtendedHeaderSize; } bool MRCHeaderObject::SetExtendedHeader(const void * buffer) { if (!this->m_ExtendedHeaderSize) { return false; } delete[] static_cast(this->m_ExtendedHeader); this->m_ExtendedHeader = new char[this->m_ExtendedHeaderSize]; memcpy(this->m_ExtendedHeader, buffer, this->m_ExtendedHeaderSize); this->m_ExtendedFeiHeader = nullptr; if (this->m_ExtendedHeaderSize == 128 * 1024 && this->m_Header.nint == 0 && this->m_Header.nreal == 32) { this->m_ExtendedFeiHeader = static_cast(this->m_ExtendedHeader); if (this->m_BigEndianHeader) { ByteSwapper::SwapRangeFromSystemToBigEndian((float *)this->m_ExtendedHeader, this->m_ExtendedHeaderSize); } else { ByteSwapper::SwapRangeFromSystemToLittleEndian((float *)this->m_ExtendedHeader, this->m_ExtendedHeaderSize); } } return true; } bool MRCHeaderObject::IsOriginalHeaderBigEndian() const { return this->m_BigEndianHeader; } MRCHeaderObject::MRCHeaderObject() { memset(&this->m_Header, 0, sizeof(Header)); this->m_BigEndianHeader = ByteSwapper::SystemIsBE(); } MRCHeaderObject::~MRCHeaderObject() { delete[] static_cast(this->m_ExtendedHeader); } void MRCHeaderObject::swapHeader(bool bigEndian) { using FloatSwapper = itk::ByteSwapper; using Int32Swapper = itk::ByteSwapper; using Int16Swapper = itk::ByteSwapper; if (FloatSwapper::SystemIsBigEndian()) { this->m_Header.stamp[0] = 17; } else { this->m_Header.stamp[0] = 68; } if (bigEndian) { Int32Swapper::SwapFromSystemToBigEndian(&this->m_Header.nx); Int32Swapper::SwapFromSystemToBigEndian(&this->m_Header.ny); Int32Swapper::SwapFromSystemToBigEndian(&this->m_Header.nz); Int32Swapper::SwapFromSystemToBigEndian(&this->m_Header.mode); Int32Swapper::SwapFromSystemToBigEndian(&this->m_Header.nxstart); Int32Swapper::SwapFromSystemToBigEndian(&this->m_Header.nystart); Int32Swapper::SwapFromSystemToBigEndian(&this->m_Header.nzstart); Int32Swapper::SwapFromSystemToBigEndian(&this->m_Header.mx); Int32Swapper::SwapFromSystemToBigEndian(&this->m_Header.my); Int32Swapper::SwapFromSystemToBigEndian(&this->m_Header.mz); FloatSwapper::SwapFromSystemToBigEndian(&this->m_Header.xlen); FloatSwapper::SwapFromSystemToBigEndian(&this->m_Header.ylen); FloatSwapper::SwapFromSystemToBigEndian(&this->m_Header.zlen); FloatSwapper::SwapFromSystemToBigEndian(&this->m_Header.alpha); FloatSwapper::SwapFromSystemToBigEndian(&this->m_Header.beta); FloatSwapper::SwapFromSystemToBigEndian(&this->m_Header.gamma); Int32Swapper::SwapFromSystemToBigEndian(&this->m_Header.mapc); Int32Swapper::SwapFromSystemToBigEndian(&this->m_Header.mapr); Int32Swapper::SwapFromSystemToBigEndian(&this->m_Header.maps); FloatSwapper::SwapFromSystemToBigEndian(&this->m_Header.amin); FloatSwapper::SwapFromSystemToBigEndian(&this->m_Header.amax); FloatSwapper::SwapFromSystemToBigEndian(&this->m_Header.amean); Int16Swapper::SwapFromSystemToBigEndian(&this->m_Header.ispg); Int16Swapper::SwapFromSystemToBigEndian(&this->m_Header.nsymbt); Int32Swapper::SwapFromSystemToBigEndian(&this->m_Header.next); Int16Swapper::SwapFromSystemToBigEndian(&this->m_Header.creatid); Int16Swapper::SwapFromSystemToBigEndian(&this->m_Header.nint); Int16Swapper::SwapFromSystemToBigEndian(&this->m_Header.nreal); Int16Swapper::SwapFromSystemToBigEndian(&this->m_Header.idtype); Int16Swapper::SwapFromSystemToBigEndian(&this->m_Header.lens); Int16Swapper::SwapFromSystemToBigEndian(&this->m_Header.nd1); Int16Swapper::SwapFromSystemToBigEndian(&this->m_Header.nd2); Int16Swapper::SwapFromSystemToBigEndian(&this->m_Header.vd1); Int16Swapper::SwapFromSystemToBigEndian(&this->m_Header.vd2); FloatSwapper::SwapFromSystemToBigEndian(&this->m_Header.tiltangles[0]); FloatSwapper::SwapFromSystemToBigEndian(&this->m_Header.tiltangles[1]); FloatSwapper::SwapFromSystemToBigEndian(&this->m_Header.tiltangles[2]); FloatSwapper::SwapFromSystemToBigEndian(&this->m_Header.tiltangles[3]); FloatSwapper::SwapFromSystemToBigEndian(&this->m_Header.tiltangles[4]); FloatSwapper::SwapFromSystemToBigEndian(&this->m_Header.tiltangles[5]); FloatSwapper::SwapFromSystemToBigEndian(&this->m_Header.xorg); FloatSwapper::SwapFromSystemToBigEndian(&this->m_Header.yorg); FloatSwapper::SwapFromSystemToBigEndian(&this->m_Header.zorg); FloatSwapper::SwapFromSystemToBigEndian(&this->m_Header.rms); Int32Swapper::SwapFromSystemToBigEndian(&this->m_Header.nlabl); } else { Int32Swapper::SwapFromSystemToLittleEndian(&this->m_Header.nx); Int32Swapper::SwapFromSystemToLittleEndian(&this->m_Header.ny); Int32Swapper::SwapFromSystemToLittleEndian(&this->m_Header.nz); Int32Swapper::SwapFromSystemToLittleEndian(&this->m_Header.mode); Int32Swapper::SwapFromSystemToLittleEndian(&this->m_Header.nxstart); Int32Swapper::SwapFromSystemToLittleEndian(&this->m_Header.nystart); Int32Swapper::SwapFromSystemToLittleEndian(&this->m_Header.nzstart); Int32Swapper::SwapFromSystemToLittleEndian(&this->m_Header.mx); Int32Swapper::SwapFromSystemToLittleEndian(&this->m_Header.my); Int32Swapper::SwapFromSystemToLittleEndian(&this->m_Header.mz); FloatSwapper::SwapFromSystemToLittleEndian(&this->m_Header.xlen); FloatSwapper::SwapFromSystemToLittleEndian(&this->m_Header.ylen); FloatSwapper::SwapFromSystemToLittleEndian(&this->m_Header.zlen); FloatSwapper::SwapFromSystemToLittleEndian(&this->m_Header.alpha); FloatSwapper::SwapFromSystemToLittleEndian(&this->m_Header.beta); FloatSwapper::SwapFromSystemToLittleEndian(&this->m_Header.gamma); Int32Swapper::SwapFromSystemToLittleEndian(&this->m_Header.mapc); Int32Swapper::SwapFromSystemToLittleEndian(&this->m_Header.mapr); Int32Swapper::SwapFromSystemToLittleEndian(&this->m_Header.maps); FloatSwapper::SwapFromSystemToLittleEndian(&this->m_Header.amin); FloatSwapper::SwapFromSystemToLittleEndian(&this->m_Header.amax); FloatSwapper::SwapFromSystemToLittleEndian(&this->m_Header.amean); Int16Swapper::SwapFromSystemToLittleEndian(&this->m_Header.ispg); Int16Swapper::SwapFromSystemToLittleEndian(&this->m_Header.nsymbt); Int32Swapper::SwapFromSystemToLittleEndian(&this->m_Header.next); Int16Swapper::SwapFromSystemToLittleEndian(&this->m_Header.creatid); Int16Swapper::SwapFromSystemToLittleEndian(&this->m_Header.nint); Int16Swapper::SwapFromSystemToLittleEndian(&this->m_Header.nreal); Int16Swapper::SwapFromSystemToLittleEndian(&this->m_Header.idtype); Int16Swapper::SwapFromSystemToLittleEndian(&this->m_Header.lens); Int16Swapper::SwapFromSystemToLittleEndian(&this->m_Header.nd1); Int16Swapper::SwapFromSystemToLittleEndian(&this->m_Header.nd2); Int16Swapper::SwapFromSystemToLittleEndian(&this->m_Header.vd1); Int16Swapper::SwapFromSystemToLittleEndian(&this->m_Header.vd2); FloatSwapper::SwapFromSystemToLittleEndian(&this->m_Header.tiltangles[0]); FloatSwapper::SwapFromSystemToLittleEndian(&this->m_Header.tiltangles[1]); FloatSwapper::SwapFromSystemToLittleEndian(&this->m_Header.tiltangles[2]); FloatSwapper::SwapFromSystemToLittleEndian(&this->m_Header.tiltangles[3]); FloatSwapper::SwapFromSystemToLittleEndian(&this->m_Header.tiltangles[4]); FloatSwapper::SwapFromSystemToLittleEndian(&this->m_Header.tiltangles[5]); FloatSwapper::SwapFromSystemToLittleEndian(&this->m_Header.xorg); FloatSwapper::SwapFromSystemToLittleEndian(&this->m_Header.yorg); FloatSwapper::SwapFromSystemToLittleEndian(&this->m_Header.zorg); FloatSwapper::SwapFromSystemToLittleEndian(&this->m_Header.rms); Int32Swapper::SwapFromSystemToLittleEndian(&this->m_Header.nlabl); } } void MRCHeaderObject::PrintSelf(std::ostream & os, Indent indent) const { Superclass::PrintSelf(os, indent); os << indent << "number: " << this->m_Header.nx << ' ' << this->m_Header.ny << ' ' << this->m_Header.nz << std::endl; os << indent << "mode: " << this->m_Header.mode << std::endl; os << indent << "start: " << this->m_Header.nxstart << ' ' << this->m_Header.nystart << ' ' << this->m_Header.nzstart << std::endl; os << indent << "grid: " << this->m_Header.mx << ' ' << this->m_Header.my << ' ' << this->m_Header.mz << std::endl; os << indent << "len: " << this->m_Header.xlen << ' ' << this->m_Header.ylen << ' ' << this->m_Header.zlen << std::endl; os << indent << "abg angles: " << this->m_Header.alpha << ' ' << this->m_Header.beta << ' ' << this->m_Header.gamma << std::endl; os << indent << "map: " << this->m_Header.mapc << ' ' << this->m_Header.mapr << ' ' << this->m_Header.maps << std::endl; os << indent << "mmm: " << this->m_Header.amin << ' ' << this->m_Header.amax << ' ' << this->m_Header.amean << std::endl; os << indent << "ispg: " << this->m_Header.ispg << std::endl; os << indent << "nsymbt: " << this->m_Header.nsymbt << std::endl; os << indent << "next: " << this->m_Header.next << std::endl; os << indent << "creatid: " << this->m_Header.creatid << std::endl; os << indent << "nint: " << this->m_Header.nint << std::endl; os << indent << "nreal: " << this->m_Header.nreal << std::endl; os << indent << "idtype: " << this->m_Header.idtype << std::endl; os << indent << "lens: " << this->m_Header.lens << std::endl; os << indent << "nd: " << this->m_Header.nd1 << ' ' << this->m_Header.nd2 << std::endl; os << indent << "vd: " << this->m_Header.vd1 << ' ' << this->m_Header.vd2 << std::endl; os << indent << "tiltangles: (" << this->m_Header.tiltangles[0] << ", " << this->m_Header.tiltangles[1] << ", " << this->m_Header.tiltangles[2] << ") (" << this->m_Header.tiltangles[3] << ", " << this->m_Header.tiltangles[4] << ", " << this->m_Header.tiltangles[5] << ')' << std::endl; os << indent << "org: " << this->m_Header.xorg << ' ' << this->m_Header.yorg << ' ' << this->m_Header.zorg << std::endl; os << indent << "cmap: \"" << this->m_Header.cmap[0] << this->m_Header.cmap[1] << this->m_Header.cmap[2] << this->m_Header.cmap[3] << '"' << std::endl; os << indent << "stamp: " << static_cast(this->m_Header.stamp[0]) << ' ' << static_cast(this->m_Header.stamp[1]) << ' ' << static_cast(this->m_Header.stamp[2]) << ' ' << static_cast(this->m_Header.stamp[3]) << std::endl; os << indent << "rms: " << this->m_Header.rms << std::endl; os << indent << "nlabl: " << this->m_Header.nlabl << std::endl; for (int32_t i = 0; i < this->m_Header.nlabl && i < 10; ++i) { os.write(this->m_Header.label[i], 80); os << indent << std::endl; } if (this->m_ExtendedFeiHeader) { os << indent << "Extended Header: " << std::endl; os << indent << "( atilt, btilt, xstage, ystage, zstage, xshift, yshift, defocus, exptime, meanint, tiltaxis, pixelsize, " "magnification)" << std::endl; for (int32_t z = 0; z < this->m_Header.nz && z < 1024; ++z) { os << indent << '(' << this->m_ExtendedFeiHeader[z].atilt << ", " << this->m_ExtendedFeiHeader[z].btilt << ", " << this->m_ExtendedFeiHeader[z].xstage << ", " << this->m_ExtendedFeiHeader[z].ystage << ", " << this->m_ExtendedFeiHeader[z].zstage << ", " << this->m_ExtendedFeiHeader[z].xshift << ", " << this->m_ExtendedFeiHeader[z].yshift << ", " << this->m_ExtendedFeiHeader[z].defocus << ", " << this->m_ExtendedFeiHeader[z].exptime << ", " << this->m_ExtendedFeiHeader[z].meanint << ", " << this->m_ExtendedFeiHeader[z].tiltaxis << ", " << this->m_ExtendedFeiHeader[z].pixelsize << ", " << this->m_ExtendedFeiHeader[z].magnification << ')' << std::endl; } } } } // namespace itk