aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libqpdf/Pl_TIFFPredictor.cc123
-rw-r--r--libqpdf/build.mk1
-rw-r--r--libqpdf/qpdf/Pl_TIFFPredictor.hh39
-rw-r--r--libtests/libtests.testcov1
-rw-r--r--libtests/predictors.cc8
-rw-r--r--libtests/qtest/predictors.test38
-rw-r--r--libtests/qtest/predictors/tiff-01--16-1-8.databin0 -> 48 bytes
-rw-r--r--libtests/qtest/predictors/tiff-01--16-1-8.decoded3
-rw-r--r--libtests/qtest/predictors/tiff-02--8-2-4.databin0 -> 16 bytes
-rw-r--r--libtests/qtest/predictors/tiff-02--8-2-4.decoded1
-rw-r--r--libtests/qtest/predictors/tiff-03--4-1-16.data1
-rw-r--r--libtests/qtest/predictors/tiff-03--4-1-16.decoded1
12 files changed, 213 insertions, 3 deletions
diff --git a/libqpdf/Pl_TIFFPredictor.cc b/libqpdf/Pl_TIFFPredictor.cc
new file mode 100644
index 00000000..42cfbb1a
--- /dev/null
+++ b/libqpdf/Pl_TIFFPredictor.cc
@@ -0,0 +1,123 @@
+#include <qpdf/Pl_TIFFPredictor.hh>
+#include <qpdf/QTC.hh>
+#include <qpdf/BitStream.hh>
+#include <qpdf/BitWriter.hh>
+#include <stdexcept>
+#include <vector>
+#include <string.h>
+#include <limits.h>
+
+Pl_TIFFPredictor::Pl_TIFFPredictor(char const* identifier, Pipeline* next,
+ action_e action, unsigned int columns,
+ unsigned int samples_per_pixel,
+ unsigned int bits_per_sample) :
+ Pipeline(identifier, next),
+ action(action),
+ columns(columns),
+ samples_per_pixel(samples_per_pixel),
+ bits_per_sample(bits_per_sample),
+ cur_row(0),
+ pos(0)
+{
+ if (samples_per_pixel < 1)
+ {
+ throw std::runtime_error(
+ "TIFFPredictor created with invalid samples_per_pixel");
+ }
+ if ((bits_per_sample < 1) ||
+ (bits_per_sample > (8 * (sizeof(unsigned long long)))))
+ {
+ throw std::runtime_error(
+ "TIFFPredictor created with invalid bits_per_sample");
+ }
+ unsigned long long bpr =
+ ((columns * bits_per_sample * samples_per_pixel) + 7) / 8;
+ if ((bpr == 0) || (bpr > (UINT_MAX - 1)))
+ {
+ throw std::runtime_error(
+ "TIFFPredictor created with invalid columns value");
+ }
+ this->bytes_per_row = bpr & UINT_MAX;
+ this->cur_row = new unsigned char[this->bytes_per_row];
+ memset(this->cur_row, 0, this->bytes_per_row);
+}
+
+Pl_TIFFPredictor::~Pl_TIFFPredictor()
+{
+ delete [] cur_row;
+}
+
+void
+Pl_TIFFPredictor::write(unsigned char* data, size_t len)
+{
+ size_t left = this->bytes_per_row - this->pos;
+ size_t offset = 0;
+ while (len >= left)
+ {
+ // finish off current row
+ memcpy(this->cur_row + this->pos, data + offset, left);
+ offset += left;
+ len -= left;
+
+ processRow();
+
+ // Prepare for next row
+ memset(this->cur_row, 0, this->bytes_per_row);
+ left = this->bytes_per_row;
+ this->pos = 0;
+ }
+ if (len)
+ {
+ memcpy(this->cur_row + this->pos, data + offset, len);
+ }
+ this->pos += len;
+}
+
+void
+Pl_TIFFPredictor::processRow()
+{
+ QTC::TC("libtests", "Pl_TIFFPredictor processRow",
+ (action == a_decode ? 0 : 1));
+ BitWriter bw(this->getNext());
+ BitStream in(this->cur_row, this->bytes_per_row);
+ std::vector<long long> prev;
+ for (unsigned int i = 0; i < this->samples_per_pixel; ++i)
+ {
+ long long sample = in.getBitsSigned(this->bits_per_sample);
+ bw.writeBitsSigned(sample, this->bits_per_sample);
+ prev.push_back(sample);
+ }
+ for (unsigned int col = 1; col < this->columns; ++col)
+ {
+ for (unsigned int i = 0; i < this->samples_per_pixel; ++i)
+ {
+ long long sample = in.getBitsSigned(this->bits_per_sample);
+ long long new_sample = sample;
+ if (action == a_encode)
+ {
+ new_sample -= prev[i];
+ prev[i] = sample;
+ }
+ else
+ {
+ new_sample += prev[i];
+ prev[i] = new_sample;
+ }
+ bw.writeBitsSigned(new_sample, this->bits_per_sample);
+ }
+ }
+ bw.flush();
+}
+
+void
+Pl_TIFFPredictor::finish()
+{
+ if (this->pos)
+ {
+ // write partial row
+ processRow();
+ }
+ this->pos = 0;
+ memset(this->cur_row, 0, this->bytes_per_row);
+ getNext()->finish();
+}
diff --git a/libqpdf/build.mk b/libqpdf/build.mk
index 75d0054e..c75c3dd9 100644
--- a/libqpdf/build.mk
+++ b/libqpdf/build.mk
@@ -32,6 +32,7 @@ SRCS_libqpdf = \
libqpdf/Pl_RunLength.cc \
libqpdf/Pl_SHA2.cc \
libqpdf/Pl_StdioFile.cc \
+ libqpdf/Pl_TIFFPredictor.cc \
libqpdf/QPDF.cc \
libqpdf/QPDFExc.cc \
libqpdf/QPDFObjGen.cc \
diff --git a/libqpdf/qpdf/Pl_TIFFPredictor.hh b/libqpdf/qpdf/Pl_TIFFPredictor.hh
new file mode 100644
index 00000000..235068ee
--- /dev/null
+++ b/libqpdf/qpdf/Pl_TIFFPredictor.hh
@@ -0,0 +1,39 @@
+#ifndef __PL_TIFFPREDICTOR_HH__
+#define __PL_TIFFPREDICTOR_HH__
+
+// This pipeline reverses the application of a TIFF predictor as
+// described in the TIFF specification.
+
+#include <qpdf/Pipeline.hh>
+
+class Pl_TIFFPredictor: public Pipeline
+{
+ public:
+ enum action_e { a_encode, a_decode };
+
+ QPDF_DLL
+ Pl_TIFFPredictor(char const* identifier, Pipeline* next,
+ action_e action, unsigned int columns,
+ unsigned int samples_per_pixel = 1,
+ unsigned int bits_per_sample = 8);
+ QPDF_DLL
+ virtual ~Pl_TIFFPredictor();
+
+ QPDF_DLL
+ virtual void write(unsigned char* data, size_t len);
+ QPDF_DLL
+ virtual void finish();
+
+ private:
+ void processRow();
+
+ action_e action;
+ unsigned int columns;
+ unsigned int bytes_per_row;
+ unsigned int samples_per_pixel;
+ unsigned int bits_per_sample;
+ unsigned char* cur_row;
+ size_t pos;
+};
+
+#endif // __PL_TIFFPREDICTOR_HH__
diff --git a/libtests/libtests.testcov b/libtests/libtests.testcov
index 03ca98a6..8b209281 100644
--- a/libtests/libtests.testcov
+++ b/libtests/libtests.testcov
@@ -33,3 +33,4 @@ Pl_PNGFilter decodeSub 0
Pl_PNGFilter decodeUp 0
Pl_PNGFilter decodeAverage 0
Pl_PNGFilter decodePaeth 0
+Pl_TIFFPredictor processRow 1
diff --git a/libtests/predictors.cc b/libtests/predictors.cc
index fe2b90f4..47efa287 100644
--- a/libtests/predictors.cc
+++ b/libtests/predictors.cc
@@ -1,4 +1,5 @@
#include <qpdf/Pl_PNGFilter.hh>
+#include <qpdf/Pl_TIFFPredictor.hh>
#include <qpdf/Pl_StdioFile.hh>
#include <qpdf/QUtil.hh>
@@ -23,6 +24,13 @@ void run(char const* filename, char const* filter,
encode ? Pl_PNGFilter::a_encode : Pl_PNGFilter::a_decode,
columns, samples_per_pixel, bits_per_sample);
}
+ else if (strcmp(filter, "tiff") == 0)
+ {
+ pl = new Pl_TIFFPredictor(
+ "png", out,
+ encode ? Pl_TIFFPredictor::a_encode : Pl_TIFFPredictor::a_decode,
+ columns, samples_per_pixel, bits_per_sample);
+ }
else
{
std::cerr << "unknown filter " << filter << std::endl;
diff --git a/libtests/qtest/predictors.test b/libtests/qtest/predictors.test
index f0553472..98961d1a 100644
--- a/libtests/qtest/predictors.test
+++ b/libtests/qtest/predictors.test
@@ -53,7 +53,7 @@ $td->runtest("check output",
{$td->FILE => "out"},
{$td->FILE => "in2"});
-my @other = (
+my @other_png = (
'01--32-3-16',
'02--32-1-8',
'03--32-3-8',
@@ -68,7 +68,7 @@ my @other = (
'12--32-1-4',
);
-foreach my $i (@other)
+foreach my $i (@other_png)
{
$i =~ m/^.*?--(\d+)-(\d+)-(\d+)$/ or die;
my $columns = $1;
@@ -85,9 +85,41 @@ foreach my $i (@other)
{$td->FILE => "$i.decoded"});
}
+my @tiff = (
+ '01--16-1-8',
+ '02--8-2-4',
+ '03--4-1-16',
+ );
+
+foreach my $i (@tiff)
+{
+ $i =~ m/^.*?--(\d+)-(\d+)-(\d+)$/ or die;
+ my $columns = $1;
+ my $samples_per_pixel = $2;
+ my $bits_per_sample = $3;
+ $td->runtest("decode tiff $i",
+ {$td->COMMAND => "predictors tiff decode tiff-$i.data" .
+ " $columns $samples_per_pixel $bits_per_sample"},
+ {$td->STRING => "done\n",
+ $td->EXIT_STATUS => 0},
+ $td->NORMALIZE_NEWLINES);
+ $td->runtest("check output for tiff-$i",
+ {$td->FILE => "out"},
+ {$td->FILE => "tiff-$i.decoded"});
+ $td->runtest("encode tiff $i",
+ {$td->COMMAND => "predictors tiff encode tiff-$i.decoded" .
+ " $columns $samples_per_pixel $bits_per_sample"},
+ {$td->STRING => "done\n",
+ $td->EXIT_STATUS => 0},
+ $td->NORMALIZE_NEWLINES);
+ $td->runtest("check output for tiff-$i",
+ {$td->FILE => "out"},
+ {$td->FILE => "tiff-$i.data"});
+}
+
cleanup();
-$td->report(8 + (2 * scalar(@other)));
+$td->report(8 + (2 * scalar(@other_png)) + (4 * scalar(@tiff)));
sub cleanup
{
diff --git a/libtests/qtest/predictors/tiff-01--16-1-8.data b/libtests/qtest/predictors/tiff-01--16-1-8.data
new file mode 100644
index 00000000..30ba8de7
--- /dev/null
+++ b/libtests/qtest/predictors/tiff-01--16-1-8.data
Binary files differ
diff --git a/libtests/qtest/predictors/tiff-01--16-1-8.decoded b/libtests/qtest/predictors/tiff-01--16-1-8.decoded
new file mode 100644
index 00000000..a47c5d62
--- /dev/null
+++ b/libtests/qtest/predictors/tiff-01--16-1-8.decoded
@@ -0,0 +1,3 @@
+
+ 
+ WXWVUTSRQG=33467 \ No newline at end of file
diff --git a/libtests/qtest/predictors/tiff-02--8-2-4.data b/libtests/qtest/predictors/tiff-02--8-2-4.data
new file mode 100644
index 00000000..0861af5a
--- /dev/null
+++ b/libtests/qtest/predictors/tiff-02--8-2-4.data
Binary files differ
diff --git a/libtests/qtest/predictors/tiff-02--8-2-4.decoded b/libtests/qtest/predictors/tiff-02--8-2-4.decoded
new file mode 100644
index 00000000..7386e3ec
--- /dev/null
+++ b/libtests/qtest/predictors/tiff-02--8-2-4.decoded
@@ -0,0 +1 @@
+ª›Œ}__wª›Œ}__w \ No newline at end of file
diff --git a/libtests/qtest/predictors/tiff-03--4-1-16.data b/libtests/qtest/predictors/tiff-03--4-1-16.data
new file mode 100644
index 00000000..e03d809d
--- /dev/null
+++ b/libtests/qtest/predictors/tiff-03--4-1-16.data
@@ -0,0 +1 @@
+UUÍðd 9[ \ No newline at end of file
diff --git a/libtests/qtest/predictors/tiff-03--4-1-16.decoded b/libtests/qtest/predictors/tiff-03--4-1-16.decoded
new file mode 100644
index 00000000..7d3c2dd9
--- /dev/null
+++ b/libtests/qtest/predictors/tiff-03--4-1-16.decoded
@@ -0,0 +1 @@
+UU#E‡eÀÀ \ No newline at end of file