Skip to content

Commit

Permalink
Merge pull request #14 from oblivioncth/overhaul_consolidate
Browse files Browse the repository at this point in the history
Consolidate Frame into Canvas
  • Loading branch information
oblivioncth authored Sep 30, 2024
2 parents 3632c64 + aa11b4f commit edee5a9
Show file tree
Hide file tree
Showing 24 changed files with 606 additions and 690 deletions.
10 changes: 4 additions & 6 deletions lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,10 @@ ob_add_standard_library(${LIB_TARGET_NAME}
codec/standard_encoder.cpp
medium_io/canvas.h
medium_io/canvas.cpp
medium_io/frame.h
medium_io/frame.cpp
medium_io/operate/basic_px_access.h
medium_io/operate/basic_px_access.cpp
medium_io/operate/data_translator.h
medium_io/operate/data_translator.cpp
medium_io/operate/meta_access.h
medium_io/operate/meta_access.cpp
medium_io/operate/px_access.h
medium_io/operate/px_access.cpp
medium_io/sequence/ch_sequence_generator.h
Expand All @@ -47,8 +45,8 @@ ob_add_standard_library(${LIB_TARGET_NAME}
medium_io/sequence/px_sequence_generator.cpp
medium_io/traverse/canvas_traverser.h
medium_io/traverse/canvas_traverser.cpp
medium_io/traverse/frame_traverser.h
medium_io/traverse/frame_traverser.cpp
medium_io/traverse/canvas_traverser_prime.h
medium_io/traverse/canvas_traverser_prime.cpp
LINKS
PRIVATE
$<BUILD_INTERFACE:magic_enum::magic_enum>
Expand Down
3 changes: 3 additions & 0 deletions lib/include/pxcrypt/stat.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class PXCRYPT_CODEC_EXPORT Stat
//-Constructor---------------------------------------------------------------------------------------------------------
public:
Stat(const QImage& image);
Stat(const QSize& size);

//-Destructor---------------------------------------------------------------------------------------------------
public:
Expand All @@ -38,6 +39,8 @@ class PXCRYPT_CODEC_EXPORT Stat
//-Instance Functions----------------------------------------------------------------------------------------------
public:
Capacity capacity(quint8 bpc) const;
bool fitsMetadata() const;
quint8 minimumDensity(quint64 bytes) const;
};

}
Expand Down
6 changes: 5 additions & 1 deletion lib/src/art_io/measure.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
// Unit Include
#include "measure.h"

// Project Includes
#include "art_io/artwork.h"
#include "pxcrypt/stat.h"

namespace PxCryptPrivate
{
Expand All @@ -15,6 +19,6 @@ IMeasure::IMeasure() {}
//-Instance Functions----------------------------------------------------------------------------------------------
//Public:
quint64 IMeasure::size() const { return IArtwork::size(renditionSize()); }
Frame::metavalue_t IMeasure::minimumBpc(const QSize& dim) const { return Frame::minimumBpc(dim, size()); }
Canvas::metavalue_t IMeasure::minimumBpc(const QSize& dim) const { return PxCrypt::Stat(dim).minimumDensity(size()); }

}
4 changes: 2 additions & 2 deletions lib/src/art_io/measure.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#include <QtGlobal>

// Project Includes
#include "medium_io/frame.h"
#include "medium_io/canvas.h"

namespace PxCryptPrivate
{
Expand All @@ -22,7 +22,7 @@ class IMeasure

public:
quint64 size() const;
Frame::metavalue_t minimumBpc(const QSize& dim) const;
Canvas::metavalue_t minimumBpc(const QSize& dim) const;
};

template<typename T>
Expand Down
23 changes: 12 additions & 11 deletions lib/src/codec/standard_decoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
#include "pxcrypt/codec/encoder.h"
#include "codec/decoder_p.h"
#include "codec/encdec.h"
#include "medium_io/frame.h"
#include "medium_io/canvas.h"
#include "art_io/works/standard.h"
#include "pxcrypt/stat.h"

namespace PxCrypt
{
Expand Down Expand Up @@ -109,35 +109,37 @@ StandardDecoder::Error StandardDecoder::decode(QByteArray& decoded, const QImage
if(encoded.isNull())
return Error(Error::InvalidSource);

// Get image stats
Stat encStat(encoded);

// Ensure image meets bare minimum space for meta pixels
if(!Frame::meetsSizeMinimum(encoded))
if(!encStat.fitsMetadata())
return Error(Error::NotLargeEnough);

// Ensure standard pixel format
QImage encStd = standardizeImage(encoded);

// Setup frame
Frame frame(&encStd, d->mPsk);
// Setup canvas
Canvas canvas(encStd, d->mPsk);

// Ensure BPC is valid
quint8 bpc = frame.bpc();
quint8 bpc = canvas.bpc();
if(bpc < BPC_MIN || bpc > BPC_MAX)
return Error(Error::InvalidMeta);

// Ensure encoding is valid
Encoder::Encoding encoding = frame.encoding();
Encoder::Encoding encoding = canvas.encoding();
if(!magic_enum::enum_contains(encoding))
return Error(Error::InvalidMeta);

// Bare minimum size check
Frame::Capacity capacity = frame.capacity();
Stat::Capacity capacity = encStat.capacity(bpc);
quint64 minSize = StandardWork::Measure().size();
if(capacity.bytes < minSize)
return Error(Error::NotLargeEnough);

// Ensure medium image is valid if applicable
QImage mediumStd;
const QImage* mediumStdPtr = nullptr;
if(encoding == Encoder::Relative)
{
if(medium.isNull())
Expand All @@ -147,11 +149,10 @@ StandardDecoder::Error StandardDecoder::decode(QByteArray& decoded, const QImage
return Error(Error::DimensionMismatch);

mediumStd = standardizeImage(medium);
mediumStdPtr = &mediumStd;
canvas.setReference(&mediumStd);
}

// Setup IO
Canvas canvas(&encStd, frame, mediumStdPtr);
// Prepare for IO
canvas.open(QIODevice::ReadOnly); // Closes upon destruction

// Read
Expand Down
23 changes: 12 additions & 11 deletions lib/src/codec/standard_encoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
#include "codec/encdec.h"
#include "codec/encoder_p.h"
#include "codec/encdec.h"
#include "medium_io/frame.h"
#include "medium_io/canvas.h"
#include "art_io/works/standard.h"
#include "pxcrypt/stat.h"

namespace PxCrypt
{
Expand Down Expand Up @@ -87,8 +87,8 @@ StandardEncoder::StandardEncoder() : Encoder(std::make_unique<StandardEncoderPri
*/
quint64 StandardEncoder::calculateMaximumPayload(const QSize& dim, quint16 tagSize, quint8 bpc)
{
PxCryptPrivate::StandardWork::Measure m(tagSize, 0); // 0 size payload to check for leftover
PxCryptPrivate::Frame::Capacity c = PxCryptPrivate::Frame::capacity(dim, bpc);
PxCryptPrivate::StandardWork::Measure m(tagSize, 0); // 0 size payload to check for leftover
Stat::Capacity c = Stat(dim).capacity(bpc);
return c.bytes - m.size();
}

Expand Down Expand Up @@ -179,6 +179,7 @@ StandardEncoder::Error StandardEncoder::encode(QImage& encoded, QByteArrayView p
return Error(Error::InvalidImage);

// Measurements
Stat mediumStat(medium);
StandardWork::Measure measurement(d->mTag.size(), payload.size());

if(d->mBpc == 0)// Determine BPC if auto
Expand All @@ -187,27 +188,27 @@ StandardEncoder::Error StandardEncoder::encode(QImage& encoded, QByteArrayView p
if(d->mBpc == 0)
{
// Check how short at max density
quint64 max = Frame::capacity(medium.size(), BPC_MAX).bytes;
quint64 max = mediumStat.capacity(BPC_MAX).bytes;
return Error(Error::WontFit, u"(%1 KiB short)."_s.arg((measurement.size() - max)/1024.0, 0, 'f', 3));
}
}
else // Ensure data will fit with fixed BPC
{
quint64 max = Frame::capacity(medium.size(), d->mBpc).bytes;
quint64 max = mediumStat.capacity(d->mBpc).bytes;
if(static_cast<quint64>(measurement.size()) > max)
return Error(Error::WontFit, u"(%1 KiB short)."_s.arg((measurement.size() - max)/1024.0, 0, 'f', 3));
}

// Copy base image, normalize to standard format
QImage workspace = standardizeImage(medium);

// Setup frame, mark meta pixels
Frame frame(&workspace, d->mPsk);
frame.setBpc(d->mBpc);
frame.setEncoding(d->mEncoding);
// Setup canvas, mark meta pixels, use self as reference if using relative encoding
Canvas canvas(workspace, d->mPsk);
canvas.setBpc(d->mBpc);
canvas.setEncoding(d->mEncoding);
canvas.setReference( d->mEncoding == Relative ? &workspace : nullptr);

// Setup IO, use self to denote relative encoding if applicable
Canvas canvas(&workspace, frame, d->mEncoding == Relative ? &workspace : nullptr);
// Prepare for IO
canvas.open(QIODevice::WriteOnly); // Closes upon destruction

// Write
Expand Down
46 changes: 29 additions & 17 deletions lib/src/medium_io/canvas.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,35 +10,35 @@ namespace PxCryptPrivate

//-Constructor---------------------------------------------------------------------------------------------------------
//Public:
Canvas::Canvas(QImage* image, const Frame& frame, const QImage* refImage) :
mAccess(image, frame.traverser(), frame.bpc(), refImage),
mTranslator(mAccess)
{
Q_ASSERT(image && !image->isNull());
}
Canvas::Canvas(QImage& image, const QByteArray& psk) :
mSize(image.size()),
mMetaAccess(image, !psk.isEmpty() ? psk : DEFAULT_SEED),
mPxAccess(image, mMetaAccess),
mTranslator(mPxAccess)
{}

//-Destructor---------------------------------------------------------------------------------------------------
//Public:
Canvas::~Canvas() { close(); }

//-Instance Functions--------------------------------------------------------------------------------------------
//Private:
void Canvas::_reset() { mAccess.reset(); }
void Canvas::_reset() { mPxAccess.reset(); }

//Protected:
qint64 Canvas::readData(char* data, qint64 maxlen)
{
if(maxlen == 0) // QIODevice doc's say this input can be used to perform "post-reading operations"
return mAccess.atEnd() ? -1 : 0;
if(maxlen == 0) // QIODevice doc's say this input (0) can be used to perform "post-reading operations"
return mPxAccess.atEnd() ? -1 : 0;

if(mAccess.atEnd())
if(mPxAccess.atEnd())
{
qWarning("Attempt to read at end of canvas!");
return -1;
}

qint64 i;
for(i = 0; i < maxlen && !mAccess.atEnd(); i++)
for(i = 0; i < maxlen && !mPxAccess.atEnd(); i++)
{
char& byte = data[i];
if(!mTranslator.skimByte(reinterpret_cast<quint8&>(byte)))
Expand All @@ -51,19 +51,19 @@ qint64 Canvas::readData(char* data, qint64 maxlen)
qint64 Canvas::skipData(qint64 maxSize)
{
Q_ASSERT(maxSize >= 0);
return mAccess.skip(maxSize);
return mPxAccess.skip(maxSize);
}

qint64 Canvas::writeData(const char* data, qint64 len)
{
if(mAccess.atEnd())
if(mPxAccess.atEnd())
{
qWarning("Attempt to write at end of canvas!");
return -1;
}

qint64 i;
for(i = 0; i < len && !mAccess.atEnd(); i++)
for(i = 0; i < len && !mPxAccess.atEnd(); i++)
{
quint8 byte = data[i];
if(!mTranslator.weaveByte(byte))
Expand All @@ -72,7 +72,7 @@ qint64 Canvas::writeData(const char* data, qint64 len)

// Always ensure data is current if Unbuffered is used
if(openMode().testFlag(QIODevice::Unbuffered))
mAccess.flush();
mPxAccess.flush();

return i;
}
Expand All @@ -87,6 +87,11 @@ bool Canvas::open(OpenMode mode)
qCritical("Unsupported open mode!");

// Prepare for access
Encoding e = static_cast<Encoding>(mMetaAccess.enc());
if(e == Encoding::Relative)
Q_ASSERT(mPxAccess.hasReferenceImage());
else
mPxAccess.setReferenceImage(nullptr); // Force-clear reference when it's not needed
_reset();

// Base implementation
Expand All @@ -95,10 +100,17 @@ bool Canvas::open(OpenMode mode)

void Canvas::close()
{
mAccess.flush();
mPxAccess.flush();
return QIODevice::close();
}

bool Canvas::atEnd() const { return mAccess.atEnd(); }
bool Canvas::atEnd() const { return mPxAccess.atEnd(); }

Canvas::metavalue_t Canvas::bpc() const { return mMetaAccess.bpc(); }
Canvas::Encoding Canvas::encoding() const { return static_cast<Encoding>(mMetaAccess.enc()); }

void Canvas::setBpc(metavalue_t bpc) { mMetaAccess.setBpc(bpc); }
void Canvas::setEncoding(Encoding enc) { mMetaAccess.setEnc(enc); }
void Canvas::setReference(const QImage* ref) { mPxAccess.setReferenceImage(ref); }

}
31 changes: 28 additions & 3 deletions lib/src/medium_io/canvas.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,39 @@
#include <QIODevice>

// Project Includes
#include "medium_io/frame.h"
#include "pxcrypt/codec/encoder.h"
#include "medium_io/operate/meta_access.h"
#include "medium_io/operate/px_access.h"
#include "medium_io/operate/data_translator.h"

using namespace Qt::StringLiterals;

namespace PxCryptPrivate
{

class Canvas final : public QIODevice
{
//-Aliases----------------------------------------------------------------------------------------------------------
private:
using Encoding = PxCrypt::Encoder::Encoding;

public:
using metavalue_t = quint8;

//-Class Variables----------------------------------------------------------------------------------------------
private:
static inline const QByteArray DEFAULT_SEED = "The best and most secure seed that is possible to exist!"_ba;

//-Instance Variables----------------------------------------------------------------------------------------------
private:
PxAccess mAccess;
QSize mSize;
MetaAccess mMetaAccess;
PxAccess mPxAccess;
DataTranslator mTranslator;

//-Constructor---------------------------------------------------------------------------------------------------
public:
Canvas(QImage* image, const Frame& frame, const QImage* refImage = nullptr);
Canvas(QImage& image, const QByteArray& psk = {});

//-Destructor---------------------------------------------------------------------------------------------------
public:
Expand All @@ -38,10 +54,19 @@ class Canvas final : public QIODevice
qint64 writeData(const char* data, qint64 len) override;

public:
// IO
bool isSequential() const override;
bool open(OpenMode mode) override;
void close() override;
bool atEnd() const override;

// Other
metavalue_t bpc() const;
Encoding encoding() const;

void setBpc(metavalue_t bpc);
void setEncoding(Encoding enc);
void setReference(const QImage* ref = nullptr);
};

}
Expand Down
Loading

0 comments on commit edee5a9

Please sign in to comment.