424 lines
13 KiB
C++
424 lines
13 KiB
C++
/************************************************************************
|
|
* LibXISF - library to load and save XISF files *
|
|
* Copyright (C) 2023 Dušan Poizl *
|
|
* *
|
|
* This program is free software: you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation, either version 3 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
* This program is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
* GNU General Public License for more details. *
|
|
* *
|
|
* You should have received a copy of the GNU General Public License *
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.*
|
|
************************************************************************/
|
|
|
|
#ifndef LIBXISF_H
|
|
#define LIBXISF_H
|
|
|
|
#include "libXISF_global.h"
|
|
#include <memory>
|
|
#include <map>
|
|
#include <variant>
|
|
#include <fstream>
|
|
#include <cstring>
|
|
#include <vector>
|
|
#include <cstdint>
|
|
#include <memory>
|
|
#include <ctime>
|
|
|
|
namespace LibXISF
|
|
{
|
|
|
|
class XISFReaderPrivate;
|
|
class XISFWriterPrivate;
|
|
|
|
class LIBXISF_EXPORT ByteArray
|
|
{
|
|
using PtrType = std::vector<char>;
|
|
using Ptr = std::shared_ptr<PtrType>;
|
|
Ptr _data;
|
|
void makeUnique();
|
|
public:
|
|
ByteArray() : ByteArray((size_t)0) {}
|
|
explicit ByteArray(size_t size);
|
|
explicit ByteArray(const char *ptr);
|
|
ByteArray(const char *ptr, size_t size)
|
|
{
|
|
_data = std::make_shared<std::vector<char>>();
|
|
_data->resize(size);
|
|
std::memcpy(data(), ptr, size);
|
|
}
|
|
ByteArray(const ByteArray &d);
|
|
char& operator[](size_t i);
|
|
const char& operator[](size_t i) const;
|
|
char* data() { return &_data->at(0); }
|
|
const char* data() const { return &_data->at(0); }
|
|
const char* constData() const { return &_data->at(0); }
|
|
size_t size() const;
|
|
void resize(size_t newsize);
|
|
void append(char c);
|
|
void decodeBase64();
|
|
void encodeBase64();
|
|
void encodeHex();
|
|
void decodeHex();
|
|
};
|
|
|
|
struct Complex32
|
|
{
|
|
float real;
|
|
float imag;
|
|
};
|
|
|
|
struct Complex64
|
|
{
|
|
double real;
|
|
double imag;
|
|
};
|
|
|
|
template<typename T>
|
|
class Matrix
|
|
{
|
|
int _rows = 0;
|
|
int _cols = 0;
|
|
std::vector<T> _elem;
|
|
public:
|
|
using value_type = T;
|
|
|
|
Matrix() = default;
|
|
Matrix(int rows, int cols) : _rows(rows), _cols(cols), _elem(rows * cols) {}
|
|
void resize(int rows, int cols) { _rows = rows; _cols = cols; _elem.resize(rows * cols); }
|
|
T& operator()(int row, int col) { return _elem[row * _cols + col]; }
|
|
const T& operator()(int row, int col) const { return _elem[row * _cols + col]; }
|
|
int rows() const { return _rows; }
|
|
int cols() const { return _cols; }
|
|
};
|
|
|
|
typedef bool Boolean;
|
|
typedef int8_t Int8;
|
|
typedef uint8_t UInt8;
|
|
typedef int16_t Int16;
|
|
typedef uint16_t UInt16;
|
|
typedef int32_t Int32;
|
|
typedef uint32_t UInt32;
|
|
typedef int64_t Int64;
|
|
typedef uint64_t UInt64;
|
|
typedef float Float32;
|
|
typedef double Float64;
|
|
typedef std::string String;
|
|
typedef std::tm TimePoint;
|
|
typedef std::vector<int8_t> I8Vector;
|
|
typedef std::vector<uint8_t> UI8Vector;
|
|
typedef std::vector<int16_t> I16Vector;
|
|
typedef std::vector<uint16_t> UI16Vector;
|
|
typedef std::vector<int32_t> I32Vector;
|
|
typedef std::vector<uint32_t> UI32Vector;
|
|
typedef std::vector<int64_t> I64Vector;
|
|
typedef std::vector<uint64_t> UI64Vector;
|
|
typedef std::vector<float> F32Vector;
|
|
typedef std::vector<double> F64Vector;
|
|
typedef std::vector<Complex32> C32Vector;
|
|
typedef std::vector<Complex64> C64Vector;
|
|
typedef Matrix<Int8> I8Matrix;
|
|
typedef Matrix<UInt8> UI8Matrix;
|
|
typedef Matrix<Int16> I16Matrix;
|
|
typedef Matrix<UInt16> UI16Matrix;
|
|
typedef Matrix<Int32> I32Matrix;
|
|
typedef Matrix<UInt32> UI32Matrix;
|
|
typedef Matrix<Int64> I64Matrix;
|
|
typedef Matrix<UInt64> UI64Matrix;
|
|
typedef Matrix<float> F32Matrix;
|
|
typedef Matrix<double> F64Matrix;
|
|
typedef Matrix<Complex32> C32Matrix;
|
|
typedef Matrix<Complex64> C64Matrix;
|
|
|
|
class LIBXISF_EXPORT Variant
|
|
{
|
|
using StdVariant = std::variant<std::monostate, Boolean, Int8, UInt8, Int16, UInt16, Int32, UInt32, Int64, UInt64, Float32, Float64,
|
|
Complex32, Complex64, String, TimePoint,
|
|
I8Vector, UI8Vector, I16Vector, UI16Vector, I32Vector, UI32Vector, I64Vector, UI64Vector, F32Vector, F64Vector, C32Vector, C64Vector,
|
|
I8Matrix, UI8Matrix, I16Matrix, UI16Matrix, I32Matrix, UI32Matrix, I64Matrix, UI64Matrix, F32Matrix, F64Matrix, C32Matrix, C64Matrix>;
|
|
StdVariant _value;
|
|
public:
|
|
enum class Type
|
|
{
|
|
Monostate, Boolean, Int8, UInt8, Int16, UInt16, Int32, UInt32, Int64, UInt64, Float32, Float64,
|
|
Complex32, Complex64, String, TimePoint,
|
|
I8Vector, UI8Vector, I16Vector, UI16Vector, I32Vector, UI32Vector, I64Vector, UI64Vector, F32Vector, F64Vector, C32Vector, C64Vector,
|
|
I8Matrix, UI8Matrix, I16Matrix, UI16Matrix, I32Matrix, UI32Matrix, I64Matrix, UI64Matrix, F32Matrix, F64Matrix, C32Matrix, C64Matrix
|
|
};
|
|
|
|
Variant() = default;
|
|
template<typename T>
|
|
Variant(const T &t) : _value(t) {}
|
|
Type type() const;
|
|
const char *typeName() const;
|
|
template<typename T>
|
|
T& value() { return std::get<T>(_value); }
|
|
template<typename T>
|
|
const T& value() const { return std::get<T>(_value); }
|
|
template<typename T>
|
|
void setValue(const T& val) { _value = val; }
|
|
String toString() const;
|
|
};
|
|
|
|
struct LIBXISF_EXPORT DataBlock
|
|
{
|
|
enum CompressionCodec
|
|
{
|
|
None,
|
|
Zlib,
|
|
LZ4,
|
|
LZ4HC,
|
|
ZSTD
|
|
};
|
|
bool embedded = false;
|
|
uint32_t byteShuffling = 0;
|
|
uint64_t attachmentPos = 0;
|
|
uint64_t attachmentSize = 0;
|
|
uint64_t uncompressedSize = 0;
|
|
std::vector<std::pair<uint64_t, uint64_t>> subblocks;
|
|
CompressionCodec codec = None;
|
|
int compressLevel = -1;
|
|
ByteArray data;
|
|
void decompress(const ByteArray &input, const std::string &encoding = "");
|
|
void compress(int sampleFormatSize);
|
|
/// ZSTD compression can be disabled at compile time
|
|
static bool CompressionCodecSupported(CompressionCodec codec);
|
|
};
|
|
|
|
struct LIBXISF_EXPORT Property
|
|
{
|
|
String id;
|
|
Variant value;
|
|
String comment;
|
|
|
|
Property() = default;
|
|
Property(const Property &) = default;
|
|
Property(const String &_id, const char *_value);
|
|
template<typename T>
|
|
Property(const String &_id, const T& _value) :
|
|
id(_id),
|
|
value(_value){}
|
|
};
|
|
|
|
struct LIBXISF_EXPORT FITSKeyword
|
|
{
|
|
String name;
|
|
String value;
|
|
String comment;
|
|
};
|
|
|
|
/**
|
|
Describe color filter array. Each letter in pattern describe color of element.
|
|
0 - A nonexistent or undefined CFA element
|
|
R - Red
|
|
G - Green
|
|
B - Blue
|
|
W - White or panchromatic
|
|
C - Cyan
|
|
M - Magenta
|
|
Y - Yellow
|
|
*/
|
|
struct LIBXISF_EXPORT ColorFilterArray
|
|
{
|
|
int width = 0;
|
|
int height = 0;
|
|
String pattern;
|
|
};
|
|
|
|
typedef std::pair<double, double> Bounds;
|
|
|
|
class LIBXISF_EXPORT Image
|
|
{
|
|
public:
|
|
enum Type
|
|
{
|
|
Bias,
|
|
Dark,
|
|
Flat,
|
|
Light,
|
|
MasterBias,
|
|
MasterDark,
|
|
MasterFlat,
|
|
DefectMap,
|
|
RejectionMapHigh,
|
|
RejectionMapLow,
|
|
BinaryRejectionMapHigh,
|
|
BinaryRejectionMapLow,
|
|
SlopeMap,
|
|
WeightMap
|
|
};
|
|
/**
|
|
Planar - each channel samples are stored separately for example RGB image will be stored RRRRGGGGBBBB
|
|
Normal - channel values for each pixel are stored inteleaved RGBRGBRGBRGB */
|
|
enum PixelStorage
|
|
{
|
|
Planar,
|
|
Normal
|
|
};
|
|
enum SampleFormat
|
|
{
|
|
UInt8,
|
|
UInt16,
|
|
UInt32,
|
|
UInt64,
|
|
Float32,
|
|
Float64,
|
|
Complex32,
|
|
Complex64
|
|
};
|
|
enum ColorSpace
|
|
{
|
|
Gray,
|
|
RGB,
|
|
CIELab
|
|
};
|
|
Image() = default;
|
|
Image(uint64_t width, uint64_t height, uint64_t channelCount = 1, SampleFormat sampleFormat = UInt16, ColorSpace colorSpace = Gray, PixelStorage pixelStorate = Planar);
|
|
|
|
uint64_t width() const;
|
|
uint64_t height() const;
|
|
uint64_t channelCount() const;
|
|
void setGeometry(uint64_t width, uint64_t height, uint64_t channelCount);
|
|
const Bounds &bounds() const;
|
|
void setBounds(const Bounds &newBounds);
|
|
Type imageType() const;
|
|
void setImageType(Type newImageType);
|
|
PixelStorage pixelStorage() const;
|
|
void setPixelStorage(PixelStorage newPixelStorage);
|
|
SampleFormat sampleFormat() const;
|
|
void setSampleFormat(SampleFormat newSampleFormat);
|
|
ColorSpace colorSpace() const;
|
|
void setColorSpace(ColorSpace newColorSpace);
|
|
const ColorFilterArray colorFilterArray() const;
|
|
void setColorFilterArray(const ColorFilterArray cfa);
|
|
const std::vector<Property> &imageProperties() const;
|
|
void addProperty(const Property &property);
|
|
void updateProperty(const Property &property);
|
|
const std::vector<FITSKeyword> fitsKeywords() const;
|
|
void addFITSKeyword(const FITSKeyword &keyword);
|
|
/** Add image property while doing automatic conversion of FITS name to XISF property
|
|
* For example OBSERVER => Observer:Name, SITELAT => Observation:Location:Latitude
|
|
*/
|
|
bool addFITSKeywordAsProperty(const String &name, const String &value);
|
|
const ByteArray& iccProfile() const;
|
|
void setIccProfile(const ByteArray &iccProfile);
|
|
|
|
void* imageData();
|
|
const void* imageData() const;
|
|
template<typename T>
|
|
T* imageData(){ return static_cast<T*>(imageData()); }
|
|
template<typename T>
|
|
const T* imageData() const { return static_cast<T*>(imageData()); }
|
|
size_t imageDataSize() const;
|
|
DataBlock::CompressionCodec compression() const;
|
|
void setCompression(DataBlock::CompressionCodec compression, int level = -1);
|
|
bool byteShuffling() const;
|
|
void setByteshuffling(bool enable);
|
|
|
|
/** Convert between Planar and Normal storage format s*/
|
|
void convertPixelStorageTo(PixelStorage storage);
|
|
|
|
static Type imageTypeEnum(const String &type);
|
|
static String imageTypeString(Type type);
|
|
static PixelStorage pixelStorageEnum(const String &storage);
|
|
static String pixelStorageString(PixelStorage storage);
|
|
static SampleFormat sampleFormatEnum(const String &format);
|
|
template<typename T>
|
|
constexpr static SampleFormat sampleFormatEnum();
|
|
static String sampleFormatString(SampleFormat format);
|
|
static ColorSpace colorSpaceEnum(const String &colorSpace);
|
|
static String colorSpaceString(ColorSpace colorSpace);
|
|
static size_t sampleFormatSize(SampleFormat sampleFormat);
|
|
|
|
private:
|
|
uint64_t _width = 0;
|
|
uint64_t _height = 0;
|
|
uint64_t _channelCount = 1;
|
|
Bounds _bounds = {0.0, 1.0};
|
|
Type _imageType = Light;
|
|
PixelStorage _pixelStorage = Planar;
|
|
SampleFormat _sampleFormat = UInt16;
|
|
ColorSpace _colorSpace = Gray;
|
|
DataBlock _dataBlock;
|
|
ByteArray _iccProfile;
|
|
ColorFilterArray _cfa;
|
|
std::vector<Property> _properties;
|
|
std::map<String, uint32_t> _propertiesId;
|
|
std::vector<FITSKeyword> _fitsKeywords;
|
|
|
|
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 */
|
|
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 not read pixel data from file and imageData()
|
|
* will return nullptr. Other properties like width, height, format etc will be returned correctly */
|
|
const Image& getImage(uint32_t n, bool readPixels = true);
|
|
/**
|
|
* @brief getThumbnail
|
|
* @return image thumbnail
|
|
*/
|
|
const Image& getThumbnail();
|
|
private:
|
|
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:
|
|
XISFWriterPrivate *p;
|
|
};
|
|
|
|
class LIBXISF_EXPORT Error : public std::exception
|
|
{
|
|
std::string _msg;
|
|
public:
|
|
Error() = default;
|
|
explicit Error(const char *msg) : Error(std::string(msg)) {}
|
|
explicit Error(const std::string &msg) : std::exception(), _msg(msg) {}
|
|
const char* what() const noexcept { return _msg.c_str(); }
|
|
};
|
|
|
|
template<typename T>
|
|
constexpr Image::SampleFormat Image::sampleFormatEnum()
|
|
{
|
|
if(std::is_same<T, LibXISF::UInt8>::value)return Image::UInt8;
|
|
if(std::is_same<T, LibXISF::UInt16>::value)return Image::UInt16;
|
|
if(std::is_same<T, LibXISF::UInt32>::value)return Image::UInt32;
|
|
if(std::is_same<T, LibXISF::UInt64>::value)return Image::UInt64;
|
|
if(std::is_same<T, LibXISF::Float32>::value)return Image::Float32;
|
|
if(std::is_same<T, LibXISF::Float64>::value)return Image::Float64;
|
|
if(std::is_same<T, LibXISF::Complex32>::value)return Image::Complex32;
|
|
if(std::is_same<T, LibXISF::Complex64>::value)return Image::Complex64;
|
|
}
|
|
|
|
}
|
|
|
|
#endif // LIBXISF_H
|