diff --git a/libxisf.cpp b/libxisf.cpp index ae333b9..64cf60d 100644 --- a/libxisf.cpp +++ b/libxisf.cpp @@ -35,8 +35,6 @@ namespace LibXISF void deserializeVariant(const pugi::xml_node &node, Variant &variant, const ByteArray &data); void serializeVariant(pugi::xml_node &node, const Variant &variant); -static std::unordered_map typeToId; -static std::unordered_map idToType; static std::unordered_map imageTypeToEnum; static std::unordered_map imageTypeToString; static std::unordered_map sampleFormatToEnum; @@ -506,7 +504,38 @@ size_t Image::sampleFormatSize(SampleFormat sampleFormat) return sizeof(UInt16); } -void XISFReader::open(const String &name) +class XISFReaderPrivate +{ +public: + void open(const String &name); + void open(const ByteArray &data); + /** Open image from istream. This method takes ownership of *io pointer */ + void open(std::istream *io); + /** Close opended file release all data. */ + void close(); + /** Return number of images inside file */ + int imagesCount() const; + /** Return reference to Image + * @param n index of image + * @param readPixel when false it will read pixel data from file and imageData() + * will return nullptr */ + const Image& getImage(uint32_t n, bool readPixels = true); +private: + void readXISFHeader(); + void readSignature(); + void parseCompression(const pugi::xml_node &node, DataBlock &dataBlock); + DataBlock parseDataBlock(const pugi::xml_node &node); + Property parseProperty(const pugi::xml_node &node); + FITSKeyword parseFITSKeyword(const pugi::xml_node &node); + ColorFilterArray parseCFA(const pugi::xml_node &node); + Image parseImage(const pugi::xml_node &node); + + std::unique_ptr _io; + std::vector _images; + std::vector _properties; +}; + +void XISFReaderPrivate::open(const String &name) { close(); _io = std::make_unique(name.c_str(), std::ios_base::in | std::ios_base::binary); @@ -514,7 +543,7 @@ void XISFReader::open(const String &name) readXISFHeader(); } -void XISFReader::open(const ByteArray &data) +void XISFReaderPrivate::open(const ByteArray &data) { close(); std::string str((char*)data.data(), data.size()); @@ -523,7 +552,7 @@ void XISFReader::open(const ByteArray &data) readXISFHeader(); } -void XISFReader::open(std::istream *io) +void XISFReaderPrivate::open(std::istream *io) { close(); _io.reset(io); @@ -531,19 +560,19 @@ void XISFReader::open(std::istream *io) readXISFHeader(); } -void XISFReader::close() +void XISFReaderPrivate::close() { _io.reset(); _images.clear(); _properties.clear(); } -int XISFReader::imagesCount() const +int XISFReaderPrivate::imagesCount() const { return _images.size(); } -const Image& XISFReader::getImage(uint32_t n, bool readPixels) +const Image& XISFReaderPrivate::getImage(uint32_t n, bool readPixels) { if(n >= _images.size()) throw Error("Out of bounds"); @@ -559,7 +588,7 @@ const Image& XISFReader::getImage(uint32_t n, bool readPixels) return img; } -void XISFReader::readXISFHeader() +void XISFReaderPrivate::readXISFHeader() { uint32_t headerLen[2] = {0}; _io->read((char*)&headerLen, sizeof(headerLen)); @@ -583,7 +612,7 @@ void XISFReader::readXISFHeader() else throw Error("Unknown root XML element"); } -void XISFReader::readSignature() +void XISFReaderPrivate::readSignature() { char signature[8]; _io->read(signature, sizeof(signature)); @@ -594,7 +623,7 @@ void XISFReader::readSignature() throw Error("Not valid XISF 1.0 file"); } -void XISFReader::parseCompression(const pugi::xml_node &node, DataBlock &dataBlock) +void XISFReaderPrivate::parseCompression(const pugi::xml_node &node, DataBlock &dataBlock) { std::vector compression = split_string(node.attribute("compression").as_string(), ':'); if(compression.size() >= 2) @@ -620,7 +649,7 @@ void XISFReader::parseCompression(const pugi::xml_node &node, DataBlock &dataBlo } } -DataBlock XISFReader::parseDataBlock(const pugi::xml_node &node) +DataBlock XISFReaderPrivate::parseDataBlock(const pugi::xml_node &node) { DataBlock dataBlock; std::vector location = split_string(node.attribute("location").as_string(), ':'); @@ -663,7 +692,7 @@ DataBlock XISFReader::parseDataBlock(const pugi::xml_node &node) return dataBlock; } -Property XISFReader::parseProperty(const pugi::xml_node &node) +Property XISFReaderPrivate::parseProperty(const pugi::xml_node &node) { Property property; @@ -691,7 +720,7 @@ Property XISFReader::parseProperty(const pugi::xml_node &node) return property; } -FITSKeyword XISFReader::parseFITSKeyword(const pugi::xml_node &node) +FITSKeyword XISFReaderPrivate::parseFITSKeyword(const pugi::xml_node &node) { FITSKeyword fitsKeyword; fitsKeyword.name = node.attribute("name").as_string(); @@ -700,7 +729,7 @@ FITSKeyword XISFReader::parseFITSKeyword(const pugi::xml_node &node) return fitsKeyword; } -ColorFilterArray XISFReader::parseCFA(const pugi::xml_node &node) +ColorFilterArray XISFReaderPrivate::parseCFA(const pugi::xml_node &node) { ColorFilterArray cfa; if(node.attribute("pattern") && node.attribute("width") && node.attribute("height")) @@ -716,7 +745,7 @@ ColorFilterArray XISFReader::parseCFA(const pugi::xml_node &node) return cfa; } -Image XISFReader::parseImage(const pugi::xml_node &node) +Image XISFReaderPrivate::parseImage(const pugi::xml_node &node) { Image image; @@ -758,8 +787,26 @@ Image XISFReader::parseImage(const pugi::xml_node &node) return image; } +class XISFWriterPrivate +{ +public: + void save(const String &name); + void save(ByteArray &data); + void save(std::ostream &io); + void writeImage(const Image &image); +private: + void writeHeader(); + void writeImageElement(pugi::xml_node &node, const Image &image); + void writeDataBlockAttributes(pugi::xml_node &image_node, const DataBlock &dataBlock); + void writePropertyElement(pugi::xml_node &node, const Property &property); + void writeFITSKeyword(pugi::xml_node &node, const FITSKeyword &keyword); + void writeMetadata(pugi::xml_node &node); + ByteArray _xisfHeader; + ByteArray _attachmentsData; + std::vector _images; +}; -void XISFWriter::save(const String &name) +void XISFWriterPrivate::save(const String &name) { std::ofstream fw(name.c_str(), std::ios_base::out | std::ios_base::binary); @@ -769,7 +816,7 @@ void XISFWriter::save(const String &name) save(fw); } -void XISFWriter::save(ByteArray &data) +void XISFWriterPrivate::save(ByteArray &data) { std::ostringstream oss; save(oss); @@ -777,7 +824,7 @@ void XISFWriter::save(ByteArray &data) data = ByteArray(str.data(), str.size()); } -void XISFWriter::save(std::ostream &io) +void XISFWriterPrivate::save(std::ostream &io) { writeHeader(); @@ -789,14 +836,14 @@ void XISFWriter::save(std::ostream &io) } } -void XISFWriter::writeImage(const Image &image) +void XISFWriterPrivate::writeImage(const Image &image) { _images.push_back(image); _images.back()._dataBlock.attachmentPos = 1; _images.back()._dataBlock.compress(image.sampleFormatSize(image.sampleFormat())); } -void XISFWriter::writeHeader() +void XISFWriterPrivate::writeHeader() { const char signature[16] = {'X', 'I', 'S', 'F', '0', '1', '0', '0', 0, 0, 0, 0, 0, 0, 0, 0}; @@ -840,7 +887,7 @@ void XISFWriter::writeHeader() _xisfHeader = ByteArray(header.c_str(), header.size()); } -void XISFWriter::writeImageElement(pugi::xml_node &node, const Image &image) +void XISFWriterPrivate::writeImageElement(pugi::xml_node &node, const Image &image) { pugi::xml_node image_node = node.append_child("Image"); std::string geometry = std::to_string(image._width) + ":" + std::to_string(image._height) + ":" + std::to_string(image._channelCount); @@ -881,7 +928,7 @@ void XISFWriter::writeImageElement(pugi::xml_node &node, const Image &image) } } -void XISFWriter::writeDataBlockAttributes(pugi::xml_node &image_node, const DataBlock &dataBlock) +void XISFWriterPrivate::writeDataBlockAttributes(pugi::xml_node &image_node, const DataBlock &dataBlock) { if(dataBlock.embedded) { @@ -919,7 +966,7 @@ void XISFWriter::writeDataBlockAttributes(pugi::xml_node &image_node, const Data } } -void XISFWriter::writePropertyElement(pugi::xml_node &node, const Property &property) +void XISFWriterPrivate::writePropertyElement(pugi::xml_node &node, const Property &property) { pugi::xml_node property_node = node.append_child("Property"); property_node.append_attribute("id").set_value(property.id.c_str()); @@ -930,7 +977,7 @@ void XISFWriter::writePropertyElement(pugi::xml_node &node, const Property &prop property_node.append_attribute("comment").set_value(property.comment.c_str()); } -void XISFWriter::writeFITSKeyword(pugi::xml_node &node, const FITSKeyword &keyword) +void XISFWriterPrivate::writeFITSKeyword(pugi::xml_node &node, const FITSKeyword &keyword) { pugi::xml_node fits_node = node.append_child("FITSKeyword"); fits_node.append_attribute("name").set_value(keyword.name.c_str()); @@ -938,7 +985,7 @@ void XISFWriter::writeFITSKeyword(pugi::xml_node &node, const FITSKeyword &keywo fits_node.append_attribute("comment").set_value(keyword.comment.c_str()); } -void XISFWriter::writeMetadata(pugi::xml_node &node) +void XISFWriterPrivate::writeMetadata(pugi::xml_node &node) { pugi::xml_node metadata = node.append_child("Metadata"); std::time_t t = std::time(nullptr); @@ -947,6 +994,76 @@ void XISFWriter::writeMetadata(pugi::xml_node &node) writePropertyElement(metadata, Property("XISF:CreatorApplication", "LibXISF")); } +XISFReader::XISFReader() +{ + p = new XISFReaderPrivate; +} + +XISFReader::~XISFReader() +{ + delete p; +} + +void XISFReader::open(const String &name) +{ + p->open(name); +} + +void XISFReader::open(const ByteArray &data) +{ + p->open(data); +} + +void XISFReader::open(std::istream *io) +{ + p->open(io); +} + +void XISFReader::close() +{ + p->close(); +} + +int XISFReader::imagesCount() const +{ + return p->imagesCount(); +} + +const Image &XISFReader::getImage(uint32_t n, bool readPixels) +{ + return p->getImage(n, readPixels); +} + +XISFWriter::XISFWriter() +{ + p = new XISFWriterPrivate; +} + +XISFWriter::~XISFWriter() +{ + delete p; +} + +void XISFWriter::save(const String &name) +{ + p->save(name); +} + +void XISFWriter::save(ByteArray &data) +{ + p->save(data); +} + +void XISFWriter::save(std::ostream &io) +{ + p->save(io); +} + +void XISFWriter::writeImage(const Image &image) +{ + p->writeImage(image); +} + #define STRING_ENUM(map, map2, c, e) { map.insert({#e, c::e}); map2.insert({c::e, #e}); } struct Init diff --git a/libxisf.h b/libxisf.h index f8815e1..e5713a7 100644 --- a/libxisf.h +++ b/libxisf.h @@ -27,12 +27,13 @@ #include #include "propertyvariant.h" -namespace pugi { class xml_node; } - namespace LibXISF { -struct DataBlock +class XISFReaderPrivate; +class XISFWriterPrivate; + +struct LIBXISF_EXPORT DataBlock { enum CompressionCodec { @@ -190,7 +191,7 @@ public: static String pixelStorageString(PixelStorage storage); static SampleFormat sampleFormatEnum(const String &format); template - static SampleFormat sampleFormatEnum(); + constexpr static SampleFormat sampleFormatEnum(); static String sampleFormatString(SampleFormat format); static ColorSpace colorSpaceEnum(const String &colorSpace); static String colorSpaceString(ColorSpace colorSpace); @@ -212,14 +213,15 @@ private: std::map _propertiesId; std::vector _fitsKeywords; - friend class XISFReader; - friend class XISFWriter; - friend class XISFReaderNoQt; + friend class XISFReaderPrivate; + friend class XISFWriterPrivate; }; class LIBXISF_EXPORT XISFReader { public: + XISFReader(); + virtual ~XISFReader(); void open(const String &name); void open(const ByteArray &data); /** Open image from istream. This method takes ownership of *io pointer */ @@ -234,37 +236,20 @@ public: * will return nullptr */ const Image& getImage(uint32_t n, bool readPixels = true); private: - void readXISFHeader(); - void readSignature(); - void parseCompression(const pugi::xml_node &node, DataBlock &dataBlock); - DataBlock parseDataBlock(const pugi::xml_node &node); - Property parseProperty(const pugi::xml_node &node); - FITSKeyword parseFITSKeyword(const pugi::xml_node &node); - ColorFilterArray parseCFA(const pugi::xml_node &node); - Image parseImage(const pugi::xml_node &node); - - std::unique_ptr _io; - std::vector _images; - std::vector _properties; + XISFReaderPrivate *p; }; class LIBXISF_EXPORT XISFWriter { public: + XISFWriter(); + virtual ~XISFWriter(); void save(const String &name); void save(ByteArray &data); void save(std::ostream &io); void writeImage(const Image &image); private: - void writeHeader(); - void writeImageElement(pugi::xml_node &node, const Image &image); - void writeDataBlockAttributes(pugi::xml_node &image_node, const DataBlock &dataBlock); - void writePropertyElement(pugi::xml_node &node, const Property &property); - void writeFITSKeyword(pugi::xml_node &node, const FITSKeyword &keyword); - void writeMetadata(pugi::xml_node &node); - ByteArray _xisfHeader; - ByteArray _attachmentsData; - std::vector _images; + XISFWriterPrivate *p; }; class LIBXISF_EXPORT Error : public std::exception @@ -278,7 +263,7 @@ public: }; template -Image::SampleFormat Image::sampleFormatEnum() +constexpr Image::SampleFormat Image::sampleFormatEnum() { if(std::is_same::value)return Image::UInt8; if(std::is_same::value)return Image::UInt16; diff --git a/propertyvariant.h b/propertyvariant.h index 0a5501c..d909bc3 100644 --- a/propertyvariant.h +++ b/propertyvariant.h @@ -27,11 +27,12 @@ #include #include #include +#include "libXISF_global.h" namespace LibXISF { -class ByteArray +class LIBXISF_EXPORT ByteArray { using PtrType = std::vector; using Ptr = std::shared_ptr;