9#include "scanlineconverter_p.h"
18#include <QLoggingCategory>
20Q_DECLARE_LOGGING_CATEGORY(LOG_IFFPLUGIN)
21Q_LOGGING_CATEGORY(LOG_IFFPLUGIN,
"kf.imageformats.plugins.scitex", QtWarningMsg)
23#define CTRLBLOCK_SIZE 256
24#define PRMSBLOCK_SIZE_CT 256
27#define HEADER_SIZE_CT (CTRLBLOCK_SIZE + PRMSBLOCK_SIZE_CT + 768 + 768)
29#define FILETYPE_CT "CT"
30#define FILETYPE_LW "LW"
31#define FILETYPE_BM "BM"
32#define FILETYPE_PG "PG"
33#define FILETYPE_TX "TX"
37 using pchar_t =
char *;
40 ScitexCtrlBlock(
const ScitexCtrlBlock& other) =
default;
41 ScitexCtrlBlock& operator =(
const ScitexCtrlBlock& other) =
default;
45 auto ok = (device && device->
isOpen());
46 ok =
ok && device->
read(pchar_t(_name.data()), _name.size()) == qint64(_name.size());
47 ok =
ok && device->
read(pchar_t(_fileType.data()), _fileType.size()) == qint64(_fileType.size());
48 ok =
ok && device->
read(pchar_t(_blockSize.data()), _blockSize.size()) == qint64(_blockSize.size());
49 ok =
ok && device->
read(pchar_t(_reserved.data()), _reserved.size()) == qint64(_reserved.size());
50 ok =
ok && device->
read(pchar_t(&_count),
sizeof(_count)) == qint64(
sizeof(_count));
51 ok =
ok && device->
read(pchar_t(_padding.data()), _padding.size()) == qint64(_padding.size());
65 quint8 sequenceCount()
const
70 std::array<quint8, 80> _name = {};
71 std::array<quint8, 2> _fileType = {};
72 std::array<quint8, 12> _blockSize = {};
73 std::array<quint8, 12> _reserved = {};
75 std::array<quint8, 149> _padding = {};
78class ScitexParamsBlock
80 using pchar_t =
char *;
82 ScitexParamsBlock() {}
83 ScitexParamsBlock(
const ScitexParamsBlock& other) =
default;
84 ScitexParamsBlock& operator =(
const ScitexParamsBlock& other) =
default;
88 auto ok = (device && device->
isOpen());
89 ok =
ok && device->
read(pchar_t(&_unitsOfMeasurement),
sizeof(_unitsOfMeasurement)) == qint64(
sizeof(_unitsOfMeasurement));
90 ok =
ok && device->
read(pchar_t(&_numOfColorSeparations),
sizeof(_numOfColorSeparations)) == qint64(
sizeof(_numOfColorSeparations));
91 ok =
ok && device->
read(pchar_t(_separationBitMask.data()), _separationBitMask.size()) == qint64(_separationBitMask.size());
92 ok =
ok && device->
read(pchar_t(_heightInUnits.data()), _heightInUnits.size()) == qint64(_heightInUnits.size());
93 ok =
ok && device->
read(pchar_t(_widthInUnits.data()), _widthInUnits.size()) == qint64(_widthInUnits.size());
94 ok =
ok && device->
read(pchar_t(_heightInPixels.data()), _heightInPixels.size()) == qint64(_heightInPixels.size());
95 ok =
ok && device->
read(pchar_t(_widthInPixels.data()), _widthInPixels.size()) == qint64(_widthInPixels.size());
96 ok =
ok && device->
read(pchar_t(&_scanDirection),
sizeof(_scanDirection)) == qint64(
sizeof(_scanDirection));
97 ok =
ok && device->
read(pchar_t(_reserved.data()), _reserved.size()) == qint64(_reserved.size());
101 quint8 colorCount()
const
103 return _numOfColorSeparations;
106 quint16 bitMask()
const
108 return ((_separationBitMask.at(0) << 8) | _separationBitMask.at(1));
111 quint8 _unitsOfMeasurement = 0;
112 quint8 _numOfColorSeparations = 0;
113 std::array<quint8, 2> _separationBitMask = {};
114 std::array<quint8, 14> _heightInUnits = {};
115 std::array<quint8, 14> _widthInUnits = {};
116 std::array<quint8, 12> _heightInPixels = {};
117 std::array<quint8, 12> _widthInPixels = {};
118 quint8 _scanDirection = 0;
119 std::array<quint8, 199> _reserved = {};
122class ScitexHandlerPrivate
124 using pchar_t =
char *;
126 ScitexHandlerPrivate()
129 ~ScitexHandlerPrivate()
137 bool isSupported()
const
143 if (width() > 300000 || height() > 300000) {
155 if (width() == 0 || height() == 0) {
159 QStringLiteral(FILETYPE_CT),
160 QStringLiteral(FILETYPE_LW),
161 QStringLiteral(FILETYPE_BM),
162 QStringLiteral(FILETYPE_PG),
163 QStringLiteral(FILETYPE_TX)
165 return ft.
contains(m_cb.fileType());
171#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
172 if (m_pb.colorCount() == 4) {
173 if (m_pb.bitMask() == 15)
174 format = QImage::Format_CMYK8888;
177 if (m_pb.colorCount() == 3) {
178 if (m_pb.bitMask() == 7)
181 if (m_pb.colorCount() == 1) {
182 if (m_pb.bitMask() == 8)
188 quint32 width()
const
191 auto&& px = m_pb._widthInPixels;
196 quint32 height()
const
199 auto&& px = m_pb._heightInPixels;
204 qint32 dotsPerMeterX()
const {
206 auto&& res = m_pb._widthInUnits;
209 if (m_pb._unitsOfMeasurement) {
210 return qRound(width() / v / 25.4 * 1000);
213 return qRound(width() / v * 1000);
218 qint32 dotsPerMeterY()
const {
220 auto&& res = m_pb._heightInUnits;
223 if (m_pb._unitsOfMeasurement) {
224 return qRound(width() / v / 25.4 * 1000);
227 return qRound(width() / v * 1000);
235 switch (m_pb._scanDirection) {
266 if (device ==
nullptr) {
269 auto ba = device->
peek(HEADER_SIZE_CT);
270 if (ba.size() != HEADER_SIZE_CT) {
278 return loadHeader(&b);
282 if (device ==
nullptr) {
285 if (!m_cb.load(device)) {
288 auto pad1 = device->
read(768);
289 if (pad1.size() != 768) {
292 if (!m_pb.load(device)) {
295 auto pad2 = device->
read(768);
296 if (pad2.size() != 768) {
302 ScitexCtrlBlock m_cb;
303 ScitexParamsBlock m_pb;
306ScitexHandler::ScitexHandler()
308 , d(new ScitexHandlerPrivate)
312bool ScitexHandler::canRead()
const
314 if (canRead(device())) {
321bool ScitexHandler::canRead(
QIODevice *device)
324 qWarning(
"ScitexHandler::canRead() called with no device");
327 ScitexHandlerPrivate hp;
328 if (hp.peekHeader(device)) {
329 return hp.isSupported();
334bool ScitexHandler::read(
QImage *image)
337 if (dev ==
nullptr) {
338 qWarning(
"ScitexHandler::read() called with no device");
341 if (!d->loadHeader(dev)) {
344 if (!d->isSupported()) {
348 auto img = imageAlloc(d->width(), d->height(), d->format());
353 auto hres = d->dotsPerMeterX();
355 img.setDotsPerMeterX(hres);
357 auto vres = d->dotsPerMeterY();
359 img.setDotsPerMeterY(vres);
362 QByteArray line(img.width() * d->m_pb.colorCount(),
char());
363 if (img.bytesPerLine() < line.size()) {
366 for (qint32 y = 0, h = img.height(); y < h; ++y) {
367 if (dev->read(line.data(), line.size()) != line.size()) {
370 auto scanLine = img.scanLine(y);
371 for (qint32 c = 0, cc = d->m_pb.colorCount(); c < cc; ++c) {
372 for (qint32 x = 0, w = img.width(); x < w; ++x) {
373 scanLine[x * cc + c] = cc == 4 ? uchar(255) - uchar(line.at(c * w + x)) : uchar(line.at(c * w + x));
382bool ScitexHandler::supportsOption(ImageOption option)
const
399QVariant ScitexHandler::option(ImageOption option)
const
405 d->peekHeader(device());
407 if (d->isSupported()) {
408 v =
QSize(d->width(), d->height());
414 d->peekHeader(device());
416 if (d->isSupported()) {
423 d->peekHeader(device());
425 if (d->isSupported()) {
426 v = int(d->transformation());
435 if (format ==
"sct") {
446 if (device->
isReadable() && ScitexHandler::canRead(device)) {
QFlags< Capability > Capabilities
virtual bool open(OpenMode flags) override
void setData(const QByteArray &data)
bool isEmpty() const const
void setDevice(QIODevice *device)
bool isOpen() const const
bool isReadable() const const
QByteArray peek(qint64 maxSize)
QByteArray read(qint64 maxSize)
QString fromLatin1(QByteArrayView str)
double toDouble(bool *ok) const const
uint toUInt(bool *ok, int base) const const
bool contains(QLatin1StringView str, Qt::CaseSensitivity cs) const const