mirror of https://github.com/JakubMelka/PDF4QT.git
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")))
|
||||
{
|
||||
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())
|
||||
{
|
||||
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
|
||||
|
|
|
@ -800,9 +800,29 @@ QByteArray PDFStreamPredictor::applyTIFFPredictor(const QByteArray& data) const
|
|||
{
|
||||
Q_UNUSED(data);
|
||||
|
||||
// TODO: Implement TIFF algorithm filter
|
||||
throw PDFException(PDFTranslationContext::tr("Invalid predictor algorithm."));
|
||||
return QByteArray();
|
||||
PDFBitWriter writer(m_bitsPerComponent);
|
||||
PDFBitReader reader(&data, m_bitsPerComponent);
|
||||
|
||||
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,
|
||||
|
|
|
@ -84,4 +84,48 @@ bool PDFBitReader::isAtEnd() const
|
|||
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
|
||||
|
|
|
@ -128,6 +128,37 @@ private:
|
|||
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,
|
||||
/// 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.
|
||||
|
|
Loading…
Reference in New Issue