Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| de757840b3 | |||
| 7b70b6a081 | |||
| 2e74d94641 | |||
| 556bb22d26 | |||
| c6581e1122 | |||
| fa39440b9e |
+1
-1
@@ -16,7 +16,7 @@ option(BUILD_SHARED_LIBS "Build using shared libraries" ON)
|
||||
option(USE_BUNDLED_LIBS "Use bundled LZ4 PugiXML and Zlib. You can still exclude some" ON)
|
||||
cmake_dependent_option(USE_BUNDLED_LZ4 "Use bundled LZ4" ON "USE_BUNDLED_LIBS" OFF)
|
||||
cmake_dependent_option(USE_BUNDLED_PUGIXML "Use bundled PugiXML" ON "USE_BUNDLED_LIBS" OFF)
|
||||
cmake_dependent_option(USE_BUNDLED_ZLIB "Use bundled Zlib" ON "USE_BUNDLED_LIBS" OFF)
|
||||
cmake_dependent_option(USE_BUNDLED_ZLIB "Use bundled Zlib" OFF "USE_BUNDLED_LIBS" OFF)
|
||||
|
||||
find_package(PkgConfig)
|
||||
|
||||
|
||||
+153
-13
@@ -17,21 +17,21 @@
|
||||
************************************************************************/
|
||||
|
||||
#include "libxisf.h"
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <cstdlib>
|
||||
#include "streambuffer.h"
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <lz4.h>
|
||||
#include <lz4hc.h>
|
||||
#include <pugixml.hpp>
|
||||
#include <sstream>
|
||||
#include <unordered_map>
|
||||
#include <zlib.h>
|
||||
#ifdef HAVE_ZSTD
|
||||
#include <zstd.h>
|
||||
#endif
|
||||
#include "streambuffer.h"
|
||||
|
||||
namespace LibXISF
|
||||
{
|
||||
@@ -101,6 +101,51 @@ static void byteShuffle(ByteArray &data, int itemSize)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __SSE2__
|
||||
#include <x86intrin.h>
|
||||
|
||||
template<int itemSize>
|
||||
size_t byteUnshuffleSSE(const char *in, char *out, size_t num)
|
||||
{
|
||||
//size_t size = num;
|
||||
const __m128i *_in[4] = {(const __m128i*)in,
|
||||
(const __m128i*)(in + num),
|
||||
(const __m128i*)(in + num * 2),
|
||||
(const __m128i*)(in + num * 3)};
|
||||
__m128i *_out = (__m128i*)out;
|
||||
num /= 16;
|
||||
|
||||
for(size_t i = 0; i < num; i++)
|
||||
{
|
||||
if constexpr(itemSize == 4)
|
||||
{
|
||||
__m128i a = _mm_loadu_si128(_in[0] + i);
|
||||
__m128i b = _mm_loadu_si128(_in[1] + i);
|
||||
__m128i c = _mm_loadu_si128(_in[2] + i);
|
||||
__m128i d = _mm_loadu_si128(_in[3] + i);
|
||||
__m128i x = _mm_unpacklo_epi8(a, b);
|
||||
__m128i y = _mm_unpackhi_epi8(a, b);
|
||||
__m128i z = _mm_unpacklo_epi8(c, d);
|
||||
__m128i w = _mm_unpackhi_epi8(c, d);
|
||||
_mm_storeu_si128(_out + i * 4, _mm_unpacklo_epi16(x, z));
|
||||
_mm_storeu_si128(_out + i * 4 + 1, _mm_unpackhi_epi16(x, z));
|
||||
_mm_storeu_si128(_out + i * 4 + 2, _mm_unpacklo_epi16(y, w));
|
||||
_mm_storeu_si128(_out + i * 4 + 3, _mm_unpackhi_epi16(y, w));
|
||||
}
|
||||
if constexpr(itemSize == 2)
|
||||
{
|
||||
__m128i a = _mm_loadu_si128(_in[0] + i);
|
||||
__m128i b = _mm_loadu_si128(_in[1] + i);
|
||||
__m128i x = _mm_unpacklo_epi8(a, b);
|
||||
__m128i y = _mm_unpackhi_epi8(a, b);
|
||||
_mm_storeu_si128(_out + i * 2, x);
|
||||
_mm_storeu_si128(_out + i * 2 + 1, y);
|
||||
}
|
||||
}
|
||||
return num * 16 * itemSize;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void byteUnshuffle(ByteArray &data, int itemSize)
|
||||
{
|
||||
if(itemSize > 1)
|
||||
@@ -108,11 +153,19 @@ static void byteUnshuffle(ByteArray &data, int itemSize)
|
||||
ByteArray &input = data;
|
||||
ByteArray output(input.size());
|
||||
size_t num = input.size() / itemSize;
|
||||
const char *s = input.constData();
|
||||
size_t off = 0;
|
||||
#ifdef __SSE2__
|
||||
if(itemSize == 4)
|
||||
off = byteUnshuffleSSE<4>(input.data(), output.data(), num);
|
||||
if(itemSize == 2)
|
||||
off = byteUnshuffleSSE<2>(input.data(), output.data(), num);
|
||||
#endif
|
||||
|
||||
const char *s = input.constData() + off;
|
||||
for(int i=0; i<itemSize; i++)
|
||||
{
|
||||
char *u = output.data() + i;
|
||||
for(size_t o=0; o<num; o++, s++, u += itemSize)
|
||||
char *u = output.data() + i + off;
|
||||
for(size_t o = off / itemSize; o < num; o++, s++, u += itemSize)
|
||||
*u = *s;
|
||||
}
|
||||
memcpy(output.data() + num * itemSize, s, input.size() % itemSize);
|
||||
@@ -648,6 +701,7 @@ public:
|
||||
void open(const ByteArray &data);
|
||||
/** Open image from istream. This method takes ownership of *io pointer */
|
||||
void open(std::istream *io);
|
||||
void open(const std::filesystem::path &path);
|
||||
/** Close opended file release all data. */
|
||||
void close();
|
||||
/** Return number of images inside file */
|
||||
@@ -701,6 +755,14 @@ void XISFReaderPrivate::open(std::istream *io)
|
||||
readXISFHeader();
|
||||
}
|
||||
|
||||
void XISFReaderPrivate::open(const std::filesystem::path &path)
|
||||
{
|
||||
close();
|
||||
_io = std::make_unique<std::ifstream>(path, std::ios_base::in | std::ios_base::binary);
|
||||
readSignature();
|
||||
readXISFHeader();
|
||||
}
|
||||
|
||||
void XISFReaderPrivate::close()
|
||||
{
|
||||
_io.reset();
|
||||
@@ -979,13 +1041,14 @@ public:
|
||||
void save(const String &name);
|
||||
void save(ByteArray &data);
|
||||
void save(std::ostream &io);
|
||||
void save(const std::filesystem::path &path);
|
||||
void writeImage(const Image &image);
|
||||
static void writeFITSKeyword(pugi::xml_node &node, const FITSKeyword &keyword);
|
||||
static void writePropertyElement(pugi::xml_node &node, const Property &property);
|
||||
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 writeMetadata(pugi::xml_node &node);
|
||||
void updateImageAttachmentPos(pugi::xml_node &root, size_t offset);
|
||||
ByteArray _xisfHeader;
|
||||
@@ -1031,6 +1094,16 @@ void XISFWriterPrivate::save(std::ostream &io)
|
||||
}
|
||||
}
|
||||
|
||||
void XISFWriterPrivate::save(const std::filesystem::path &path)
|
||||
{
|
||||
std::ofstream fw(path, std::ios_base::out | std::ios_base::binary);
|
||||
|
||||
if(fw.fail())
|
||||
throw Error("Failed to open file");
|
||||
|
||||
save(fw);
|
||||
}
|
||||
|
||||
void XISFWriterPrivate::writeImage(const Image &image)
|
||||
{
|
||||
_images.push_back(image);
|
||||
@@ -1251,6 +1324,11 @@ void XISFReader::open(std::istream *io)
|
||||
p->open(io);
|
||||
}
|
||||
|
||||
void XISFReader::open(const std::filesystem::path &path)
|
||||
{
|
||||
p->open(path);
|
||||
}
|
||||
|
||||
void XISFReader::close()
|
||||
{
|
||||
p->close();
|
||||
@@ -1296,6 +1374,11 @@ void XISFWriter::save(std::ostream &io)
|
||||
p->save(io);
|
||||
}
|
||||
|
||||
void XISFWriter::save(const std::filesystem::path &path)
|
||||
{
|
||||
p->save(path);
|
||||
}
|
||||
|
||||
void XISFWriter::writeImage(const Image &image)
|
||||
{
|
||||
p->writeImage(image);
|
||||
@@ -1308,16 +1391,19 @@ public:
|
||||
void open(const ByteArray &data);
|
||||
/** Open image from istream. This method takes ownership of *io pointer */
|
||||
void open(std::istream *io);
|
||||
void open(const std::filesystem::path &path);
|
||||
/** Close opended file release all data. */
|
||||
void close();
|
||||
|
||||
void save(const String &name);
|
||||
void save(ByteArray &data);
|
||||
void save(std::ostream &io);
|
||||
void save(const std::filesystem::path &path);
|
||||
|
||||
void addFITSKeyword(uint32_t image, const FITSKeyword &keyword);
|
||||
void updateFITSKeyword(uint32_t image, const FITSKeyword &keyword, bool add);
|
||||
void removeFITSKeyword(uint32_t image, const String &name);
|
||||
void updateProperty(uint32_t image, const Property &property);
|
||||
private:
|
||||
void readXISFHeader();
|
||||
void parseAttachmentPos(pugi::xml_node &root);
|
||||
@@ -1329,7 +1415,6 @@ private:
|
||||
pugi::xml_document _doc;
|
||||
pugi::xml_node _root;
|
||||
std::map<int, std::pair<uint64_t, uint64_t>> _attachmentPos;// pair contain position and size
|
||||
std::map<int, std::pair<uint64_t, uint64_t>> _attachmentPosNew;
|
||||
};
|
||||
|
||||
|
||||
@@ -1355,6 +1440,13 @@ void XISFModifyPrivate::open(std::istream *io)
|
||||
readXISFHeader();
|
||||
}
|
||||
|
||||
void XISFModifyPrivate::open(const std::filesystem::path &path)
|
||||
{
|
||||
close();
|
||||
_io = std::make_unique<std::ifstream>(path, std::ios_base::in | std::ios_base::binary);
|
||||
readXISFHeader();
|
||||
}
|
||||
|
||||
void XISFModifyPrivate::close()
|
||||
{
|
||||
_io.reset();
|
||||
@@ -1392,6 +1484,8 @@ void XISFModifyPrivate::save(std::ostream &io)
|
||||
doc.append_child(pugi::node_comment).set_value("\nExtensible Image Serialization Format - XISF version 1.0\nCreated with libXISF - https://nouspiro.space\n");
|
||||
pugi::xml_node root_copy = doc.append_copy(_root);
|
||||
|
||||
parseAttachmentPos(_root);
|
||||
|
||||
uint32_t size = 0;
|
||||
std::string header;
|
||||
while(true)
|
||||
@@ -1432,6 +1526,16 @@ void XISFModifyPrivate::save(std::ostream &io)
|
||||
}
|
||||
}
|
||||
|
||||
void XISFModifyPrivate::save(const std::filesystem::path &path)
|
||||
{
|
||||
std::ofstream fw(path, std::ios_base::out | std::ios_base::binary);
|
||||
|
||||
if(fw.fail())
|
||||
throw Error("Failed to open file");
|
||||
|
||||
save(fw);
|
||||
}
|
||||
|
||||
void XISFModifyPrivate::addFITSKeyword(uint32_t image, const FITSKeyword &keyword)
|
||||
{
|
||||
if(!_root)
|
||||
@@ -1498,6 +1602,27 @@ void XISFModifyPrivate::removeFITSKeyword(uint32_t image, const String &name)
|
||||
imageNode.remove_child(keywordNode);
|
||||
}
|
||||
|
||||
void XISFModifyPrivate::updateProperty(uint32_t image, const Property &property)
|
||||
{
|
||||
if(!_root)
|
||||
throw Error("No input file opened");
|
||||
|
||||
pugi::xpath_node_set images = _root.select_nodes("//Image");
|
||||
|
||||
if(image >= images.size())
|
||||
throw Error("Out of bounds");
|
||||
|
||||
pugi::xpath_variable_set variables;
|
||||
variables.set("id", property.id.c_str());
|
||||
pugi::xml_node imageNode = images[image].node();
|
||||
pugi::xml_node propertyNode = imageNode.select_node("Property[@id=string($id)]", &variables).node();
|
||||
|
||||
if(propertyNode)
|
||||
imageNode.remove_child(propertyNode);
|
||||
|
||||
XISFWriterPrivate::writePropertyElement(imageNode, property);
|
||||
}
|
||||
|
||||
void XISFModifyPrivate::readXISFHeader()
|
||||
{
|
||||
char signature[8];
|
||||
@@ -1526,6 +1651,7 @@ void XISFModifyPrivate::readXISFHeader()
|
||||
|
||||
void XISFModifyPrivate::parseAttachmentPos(pugi::xml_node &root)
|
||||
{
|
||||
_attachmentPos.clear();
|
||||
pugi::xpath_node_set locationAttributes = root.select_nodes("//@location");
|
||||
int i = 0;
|
||||
for(auto &attr : locationAttributes)
|
||||
@@ -1550,7 +1676,6 @@ void XISFModifyPrivate::updateAttachmentPos(pugi::xml_node &root, size_t offset)
|
||||
pugi::xml_attribute attr = locationAttributes[pos.first].attribute();
|
||||
uint64_t attachmentSize = pos.second.second;
|
||||
std::string locationStr = "attachment:" + std::to_string(offset) + ":" + std::to_string(attachmentSize);
|
||||
_attachmentPosNew[pos.first] = pos.second;
|
||||
offset += attachmentSize;
|
||||
attr.set_value(locationStr.c_str());
|
||||
}
|
||||
@@ -1581,6 +1706,11 @@ void XISFModify::open(std::istream *io)
|
||||
p->open(io);
|
||||
}
|
||||
|
||||
void XISFModify::open(const std::filesystem::path &path)
|
||||
{
|
||||
p->open(path);
|
||||
}
|
||||
|
||||
void XISFModify::close()
|
||||
{
|
||||
p->close();
|
||||
@@ -1601,6 +1731,11 @@ void XISFModify::save(std::ostream &io)
|
||||
p->save(io);
|
||||
}
|
||||
|
||||
void XISFModify::save(const std::filesystem::path &path)
|
||||
{
|
||||
p->save(path);
|
||||
}
|
||||
|
||||
void XISFModify::addFITSKeyword(uint32_t image, const FITSKeyword &keyword)
|
||||
{
|
||||
p->addFITSKeyword(image, keyword);
|
||||
@@ -1616,6 +1751,11 @@ void XISFModify::removeFITSKeyword(uint32_t image, const String &name)
|
||||
p->removeFITSKeyword(image, name);
|
||||
}
|
||||
|
||||
void XISFModify::updateProperty(uint32_t image, const Property &property)
|
||||
{
|
||||
p->updateProperty(image, property);
|
||||
}
|
||||
|
||||
#define STRING_ENUM(map, map2, c, e) { map.insert({#e, c::e}); map2.insert({c::e, #e}); }
|
||||
|
||||
struct Init
|
||||
|
||||
@@ -20,15 +20,15 @@
|
||||
#define LIBXISF_H
|
||||
|
||||
#include "libXISF_global.h"
|
||||
#include <memory>
|
||||
#include <map>
|
||||
#include <variant>
|
||||
#include <fstream>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
#include <filesystem>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <memory>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
namespace LibXISF
|
||||
{
|
||||
@@ -370,6 +370,7 @@ public:
|
||||
void open(const ByteArray &data);
|
||||
/** Open image from istream. This method takes ownership of *io pointer */
|
||||
void open(std::istream *io);
|
||||
void open(const std::filesystem::path &path);
|
||||
/** Close opended file release all data. */
|
||||
void close();
|
||||
/** Return number of images inside file */
|
||||
@@ -396,6 +397,7 @@ public:
|
||||
void save(const String &name);
|
||||
void save(ByteArray &data);
|
||||
void save(std::ostream &io);
|
||||
void save(const std::filesystem::path &path);
|
||||
void writeImage(const Image &image);
|
||||
private:
|
||||
XISFWriterPrivate *p;
|
||||
@@ -419,10 +421,12 @@ public:
|
||||
void open(const String &name);
|
||||
void open(const ByteArray &data);
|
||||
void open(std::istream *io);
|
||||
void open(const std::filesystem::path &path);
|
||||
void close();
|
||||
void save(const String &name);
|
||||
void save(ByteArray &data);
|
||||
void save(std::ostream &io);
|
||||
void save(const std::filesystem::path &path);
|
||||
|
||||
/**
|
||||
* @brief addFITSKeyword append new keyword to image
|
||||
@@ -443,6 +447,12 @@ public:
|
||||
* @param name of keyword that will be removed
|
||||
*/
|
||||
void removeFITSKeyword(uint32_t image, const String &name);
|
||||
/**
|
||||
* @brief updateProperty add new or update existing XISF Property
|
||||
* @param image index of image to update
|
||||
* @param property new value of property
|
||||
*/
|
||||
void updateProperty(uint32_t image, const Property &property);
|
||||
private:
|
||||
XISFModifyPrivate *p;
|
||||
};
|
||||
|
||||
+1
-1
@@ -102,7 +102,7 @@ int main(int argc, char **argv)
|
||||
else
|
||||
{
|
||||
LibXISF::XISFReader reader;
|
||||
reader.open(argv[1]);
|
||||
reader.open(LibXISF::String(argv[1]));
|
||||
TEST(reader.imagesCount() != 1, "No image");
|
||||
|
||||
const LibXISF::Image &image = reader.getImage(0);
|
||||
|
||||
+1
-3
@@ -17,7 +17,6 @@
|
||||
************************************************************************/
|
||||
|
||||
#include <charconv>
|
||||
#include <type_traits>
|
||||
#include <map>
|
||||
#include <regex>
|
||||
#include <iomanip>
|
||||
@@ -403,7 +402,6 @@ Variant variantFromString(Variant::Type type, const String &str)
|
||||
|
||||
Variant::Type Variant::type() const
|
||||
{
|
||||
int idx = _value.index();
|
||||
return (Variant::Type)_value.index();
|
||||
}
|
||||
|
||||
@@ -442,7 +440,7 @@ String Variant::toString() const
|
||||
ss << "{";
|
||||
for(int o=0; o<matrix.cols(); o++)
|
||||
{
|
||||
#if __GNUC__ >= 11 || __clang__
|
||||
#if __GNUC__ >= 11 || __clang_major__ >= 15
|
||||
char str[128] = {0};
|
||||
char *end = str + sizeof(str);
|
||||
std::to_chars(str, end, matrix(i, o));
|
||||
|
||||
Reference in New Issue
Block a user