mirror of
https://github.com/JakubMelka/PDF4QT.git
synced 2025-04-26 16:08:45 +02:00
TIFF predictor
This commit is contained in:
parent
f8d72d1960
commit
f443aec09c
@ -77,12 +77,12 @@ PDFImage PDFImage::createImage(const PDFDocument* document, const PDFStream* str
|
|||||||
|
|
||||||
if (isSoftMask && (imageMask || dictionary->hasKey("Mask") || dictionary->hasKey("SMask")))
|
if (isSoftMask && (imageMask || dictionary->hasKey("Mask") || dictionary->hasKey("SMask")))
|
||||||
{
|
{
|
||||||
throw PDFRendererException(RenderErrorType::NotImplemented, PDFTranslationContext::tr("Soft mask image can't have mask / soft mask itself."));
|
throw PDFRendererException(RenderErrorType::Error, PDFTranslationContext::tr("Soft mask image can't have mask / soft mask itself."));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isSoftMask && !matte.empty())
|
if (!isSoftMask && !matte.empty())
|
||||||
{
|
{
|
||||||
throw PDFRendererException(RenderErrorType::NotImplemented, PDFTranslationContext::tr("Regular image can't have Matte entry (used for soft masks)."));
|
throw PDFRendererException(RenderErrorType::Error, PDFTranslationContext::tr("Regular image can't have Matte entry (used for soft masks)."));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fill Mask
|
// Fill Mask
|
||||||
|
@ -800,9 +800,29 @@ QByteArray PDFStreamPredictor::applyTIFFPredictor(const QByteArray& data) const
|
|||||||
{
|
{
|
||||||
Q_UNUSED(data);
|
Q_UNUSED(data);
|
||||||
|
|
||||||
// TODO: Implement TIFF algorithm filter
|
PDFBitWriter writer(m_bitsPerComponent);
|
||||||
throw PDFException(PDFTranslationContext::tr("Invalid predictor algorithm."));
|
PDFBitReader reader(&data, m_bitsPerComponent);
|
||||||
return QByteArray();
|
|
||||||
|
writer.reserve(data.size());
|
||||||
|
std::vector<uint32_t> leftValues(m_components, 0);
|
||||||
|
|
||||||
|
while (!reader.isAtEnd())
|
||||||
|
{
|
||||||
|
for (int i = 0; i < m_columns; ++i)
|
||||||
|
{
|
||||||
|
for (int componentIndex = 0; componentIndex < m_components; ++componentIndex)
|
||||||
|
{
|
||||||
|
leftValues[componentIndex] = (leftValues[componentIndex] + reader.read()) & reader.max();
|
||||||
|
writer.write(leftValues[componentIndex]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::fill(leftValues.begin(), leftValues.end(), 0);
|
||||||
|
reader.alignToBytes();
|
||||||
|
writer.finishLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
return writer.takeByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray PDFCryptFilter::apply(const QByteArray& data,
|
QByteArray PDFCryptFilter::apply(const QByteArray& data,
|
||||||
|
@ -84,4 +84,48 @@ bool PDFBitReader::isAtEnd() const
|
|||||||
return (m_position >= m_stream->size());
|
return (m_position >= m_stream->size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PDFBitWriter::PDFBitWriter(Value bitsPerComponent) :
|
||||||
|
m_bitsPerComponent(bitsPerComponent),
|
||||||
|
m_mask((static_cast<Value>(1) << m_bitsPerComponent) - static_cast<Value>(1)),
|
||||||
|
m_buffer(0),
|
||||||
|
m_bitsInBuffer(0)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFBitWriter::write(Value value)
|
||||||
|
{
|
||||||
|
m_buffer = (m_buffer << m_bitsPerComponent) | (value & m_mask);
|
||||||
|
m_bitsInBuffer += m_bitsPerComponent;
|
||||||
|
|
||||||
|
flush(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFBitWriter::flush(bool alignToByteBoundary)
|
||||||
|
{
|
||||||
|
if (m_bitsInBuffer >= 8)
|
||||||
|
{
|
||||||
|
Value remainder = m_bitsInBuffer % 8;
|
||||||
|
Value alignedBuffer = m_buffer >> remainder;
|
||||||
|
Value bitsToWrite = m_bitsInBuffer - remainder;
|
||||||
|
Value bytesToWrite = bitsToWrite / 8;
|
||||||
|
|
||||||
|
for (Value byteIndex = 0; byteIndex < bytesToWrite; ++byteIndex)
|
||||||
|
{
|
||||||
|
const Value shift = (bytesToWrite - 1 - byteIndex) * 8;
|
||||||
|
m_outputByteArray.push_back(static_cast<const char>(static_cast<uint8_t>((alignedBuffer >> shift) & 0xFF)));
|
||||||
|
}
|
||||||
|
|
||||||
|
m_bitsInBuffer = remainder;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (alignToByteBoundary && m_bitsInBuffer > 0)
|
||||||
|
{
|
||||||
|
Value missingBits = 8 - m_bitsInBuffer % 8;
|
||||||
|
m_buffer = m_buffer << missingBits;
|
||||||
|
m_bitsInBuffer += missingBits;
|
||||||
|
flush(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace pdf
|
} // namespace pdf
|
||||||
|
@ -128,6 +128,37 @@ private:
|
|||||||
Value m_bitsInBuffer;
|
Value m_bitsInBuffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Bit writer
|
||||||
|
class PDFBitWriter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using Value = uint64_t;
|
||||||
|
|
||||||
|
explicit PDFBitWriter(Value bitsPerComponent);
|
||||||
|
|
||||||
|
/// Writes value to the output stream
|
||||||
|
void write(Value value);
|
||||||
|
|
||||||
|
/// Finish line - align to byte boundary
|
||||||
|
void finishLine() { flush(true); }
|
||||||
|
|
||||||
|
/// Returns the result byte array
|
||||||
|
QByteArray takeByteArray() { return qMove(m_outputByteArray); }
|
||||||
|
|
||||||
|
/// Reserve memory in buffer
|
||||||
|
void reserve(int size) { m_outputByteArray.reserve(size); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void flush(bool alignToByteBoundary);
|
||||||
|
|
||||||
|
QByteArray m_outputByteArray;
|
||||||
|
|
||||||
|
Value m_bitsPerComponent;
|
||||||
|
Value m_mask;
|
||||||
|
Value m_buffer;
|
||||||
|
Value m_bitsInBuffer;
|
||||||
|
};
|
||||||
|
|
||||||
/// Simple class guard, for properly saving/restoring new/old value. In the constructor,
|
/// Simple class guard, for properly saving/restoring new/old value. In the constructor,
|
||||||
/// new value is stored in the pointer (old one is being saved), and in the destructor,
|
/// new value is stored in the pointer (old one is being saved), and in the destructor,
|
||||||
/// old value is restored. This object assumes, that value is not a null pointer.
|
/// old value is restored. This object assumes, that value is not a null pointer.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user