From e293c3168d846cf6755087311597674228d46e59 Mon Sep 17 00:00:00 2001 From: mattmcw Date: Wed, 6 Nov 2024 22:37:15 -0500 Subject: [PATCH] This adds the first draft of DXF functionality to the filmout_display application --- include/dxf.hpp | 80 ++++++++++++++++++++ include/image.hpp | 4 + src/dxf.cpp | 186 ++++++++++++++++++++++++++++++++++++++++++++++ src/image.cpp | 17 ++++- src/main.cpp | 2 +- 5 files changed, 287 insertions(+), 2 deletions(-) create mode 100644 include/dxf.hpp create mode 100644 src/dxf.cpp diff --git a/include/dxf.hpp b/include/dxf.hpp new file mode 100644 index 0000000..c2a54ba --- /dev/null +++ b/include/dxf.hpp @@ -0,0 +1,80 @@ +#include +#include +#include +#include +#include +#include + +using namespace cv; +using namespace std; + +struct DXFHeader { + int32_t width; + int32_t height; + uint8_t bitDepth; + uint8_t version; + uint8_t flags; + uint8_t reserved; +}; + +class DXF { + public: + explicit DXF(const string& filepath) : + _filepath(filepath), + _width(0), + _height(0), + _bitDepth(0) { + analyzeFile(); + loadImageData(); + } + + int getWidth() const { return _width; } + int getHeight() const { return _height; } + int getBitDepth() const { return _bitDepth; } + bool hasDXFHeader() const { return true; } + + Mat to8bitBGR() const; + Mat to10bitBGR() const; + + private: + string _filepath; + int _width; + int _height; + int _bitDepth; + Mat _imageData; + + void analyzeFile(); + bool readDXFHeader(ifstream& file); + void analyzeDXFContent(ifstream& file); + int detectBitDepth(const vector& sample); + void loadImageData(); + void unpackBits(const std::vector& rawData); + void calculateDimensions(streamsize fileSize); + void validateImageProperties(); + + static uint16_t extractBits(const std::vector& buffer, size_t bitPos, int bitDepth, uint16_t maxValue); +}; + +/* Example usage +int main() { + try { + DXF dxf("sample.dxf"); + + cout << "Image dimensions: " << dxf.getWidth() << "x" << + dxf.getHeight() << endl; + cout << "Original bit depth: " << dxf.getBitDepth() << endl; + + Mat bgr8bit = dxf.to8BitBGR(); + Mat bgr10bit = dxf.to10BitBGR(); + + + imwrite("output_8bit_bgr.png", bgr8bit); + imwrite("output_10bit_bgr.png", bgr10bit); + + return 0; + } + catch (const exception& e) { + cerr << "Error: " << e.what() << endl; + return 1; + } +}*/ \ No newline at end of file diff --git a/include/image.hpp b/include/image.hpp index 41224c6..793f857 100644 --- a/include/image.hpp +++ b/include/image.hpp @@ -17,6 +17,8 @@ #include #include +#include "dxf.hpp" + using namespace std; using namespace cv; @@ -28,6 +30,8 @@ class Image { Mat loaded; Mat resized; Mat image; + string getExtLower(const string& path); + public: Image(); void setDimensions(uint16_t w, uint16_t h) { width = w; height = h; }; diff --git a/src/dxf.cpp b/src/dxf.cpp new file mode 100644 index 0000000..109feb8 --- /dev/null +++ b/src/dxf.cpp @@ -0,0 +1,186 @@ +#include "dxf.hpp" + + +Mat DXF::to8bitBGR() const { + if (_imageData.empty()) { + throw runtime_error("No image data loaded"); + } + + Mat output(_height, _width, CV_8UC3); + + double scale = 255.0 / ((1 << _bitDepth) - 1); + + for (int y = 0; y < _height; ++y) { + const uint16_t* srcRow = _imageData.ptr(y); + uint8_t* dstRow = output.ptr(y); + + for (int x = 0; x < _width; ++x) { + uint8_t value = static_cast(srcRow[x] * scale + 0.5); + dstRow[x * 3] = value; // B + dstRow[x * 3 + 1] = value; // G + dstRow[x * 3 + 2] = value; // R + } + } + + return output; +} + +Mat DXF::to10bitBGR() const { + if (_imageData.empty()) { + throw runtime_error("No image data loaded"); + } + + Mat output(_height, _width, CV_16UC3); + + double scale = 1023.0 / ((1 << _bitDepth) - 1); + + for (int y = 0; y < _height; ++y) { + const uint16_t* srcRow = _imageData.ptr(y); + uint16_t* dstRow = output.ptr(y); + + for (int x = 0; x < _width; ++x) { + uint16_t value = static_cast(srcRow[x] * scale + 0.5); + value = min(value, static_cast(1023)); + + uint16_t shiftedValue = value << 6; + + dstRow[x * 3] = shiftedValue; // B + dstRow[x * 3 + 1] = shiftedValue; // G + dstRow[x * 3 + 2] = shiftedValue; // R + } + } + + return output; +} + +void DXF::analyzeFile() { + ifstream file(_filepath, ios::binary); + if (!file.is_open()) { + throw runtime_error("Could not open file: " + _filepath); + } + + if (!readDXFHeader(file)) { + analyzeDXFContent(file); + } + + validateImageProperties(); +} + +bool DXF::readDXFHeader(ifstream& file) { + struct DXFHeader { + uint32_t magic; + uint32_t width; + uint32_t height; + uint8_t bitDepth; + uint8_t version; + uint16_t flags; + }; + + DXFHeader header; + file.read(reinterpret_cast(&header), sizeof(header)); + + if (file.gcount() != sizeof(header)) { + return false; + } + + if (header.magic != 0x44584631) { + return false; + } + + _width = header.width; + _height = header.height; + _bitDepth = header.bitDepth; + + return true; +} + +void DXF::analyzeDXFContent(ifstream& file) { + file.seekg(0, ios::end); + streamsize fileSize = file.tellg(); + file.seekg(0, ios::beg); + + vector sample(min(static_cast(1024), fileSize)); + file.read(reinterpret_cast(sample.data()), sample.size()); + + _bitDepth = detectBitDepth(sample); + + calculateDimensions(fileSize); +} + +int DXF::detectBitDepth(const vector& sample) { + uint16_t maxValue = 0; + + for (size_t i = 0; i < sample.size() - 1; i += 2) { + uint16_t value = (static_cast(sample[i + 1]) << 8) | sample[i]; + maxValue = max(maxValue, value); + } + + int bitDepth = 16; + while (bitDepth > 8 && maxValue < (1 << (bitDepth - 1))) { + bitDepth--; + } + + return bitDepth; +} + +void DXF::loadImageData() { + ifstream file(_filepath, ios::binary); + if (!file.is_open()) { + throw runtime_error("Could not open file: " + _filepath); + } + if (hasDXFHeader()) { + file.seekg(sizeof(struct DXFHeader)); + } + + size_t dataSize = static_cast(ceil(_width * _height * _bitDepth / 8.0)); + vector rawData(dataSize); + + file.read(reinterpret_cast(rawData.data()), dataSize); + + _imageData = Mat(_height, _width, CV_16UC1); + + unpackBits(rawData); +} + +void DXF::unpackBits(const vector& rawData) { + size_t bitPos = 0; + const uint16_t maxValue = (1 << _bitDepth) - 1; + + for (int y = 0; y < _height; ++y) { + uint16_t* row = _imageData.ptr(y); + for (int x = 0; x < _width; ++x) { + row[x] = extractBits(rawData, bitPos, _bitDepth, maxValue); + bitPos += _bitDepth; + } + } +} + +uint16_t DXF::extractBits(const vector& buffer, size_t bitPos, int bitDepth, uint16_t maxValue) { + size_t bytePos = bitPos / 8; + size_t bitOffset = bitPos % 8; + + uint32_t temp = 0; + for (int i = 0; i < 3 && bytePos + i < buffer.size(); ++i) { + temp |= static_cast(buffer[bytePos + i]) << (16 - (i * 8)); + } + + temp >>= (24 - (bitOffset + bitDepth)); + return static_cast(temp & maxValue); +} + +void DXF::calculateDimensions(streamsize fileSize) { + int pixelCount = (fileSize * 8) / _bitDepth; + _width = static_cast(sqrt(pixelCount)); + _height = _width; +} + +void DXF::validateImageProperties() { + if (_width <= 0 || _height <= 0 || + _width > 65536 || _height > 65536) { + throw runtime_error("Invalid image dimensions"); + } + + if (_bitDepth < 8 || _bitDepth > 16) { + throw runtime_error("Unsupported bit depth: " + to_string(_bitDepth)); + } +} \ No newline at end of file diff --git a/src/image.cpp b/src/image.cpp index 6e1cd5d..2d17725 100644 --- a/src/image.cpp +++ b/src/image.cpp @@ -13,7 +13,12 @@ Mat Image::getBlank () { Mat Image::loadImage (string& image_path, uint64_t& x, uint64_t& y, uint64_t& w, uint64_t& h) { string located_path = samples::findFile(image_path); - loaded = imread(located_path, IMREAD_COLOR); + if (getExtLower(located_path) == ".dxf") { + DXF dxf(located_path); + loaded = dxf.to8bitBGR(); + } else { + loaded = imread(located_path, IMREAD_COLOR); + } image = getBlank(); if (loaded.empty()) { @@ -37,4 +42,14 @@ Mat Image::loadImage (string& image_path, uint64_t& x, uint64_t& y, uint64_t& w, resized.release(); } return image; +} + +string Image::getExtLower (const string& path) { + size_t pos = path.find_last_of('.'); + if (pos != string::npos) { + string ext = path.substr(pos + 1); + transform(ext.begin(), ext.end(), ext.begin(), ::tolower); + return ext; + } + return ""; } \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 7cc8c62..51eade6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -214,7 +214,7 @@ void display () { glBindTexture(GL_TEXTURE_2D, 0); glutSwapBuffers(); - //glFlush(); + //glFlush(); } void timer(int value) {