1 /* Copyright © 2010 Jakub Wilk <jwilk@jwilk.net>
2 *
3 * This file is part of pdf2djvu.
4 *
5 * pdf2djvu is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * pdf2djvu is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 */
14
15 #ifndef PDF2DJVU_RLE_H
16 #define PDF2DJVU_RLE_H
17
18 #include <cassert>
19 #include <ostream>
20
21 /* Support for RLE formats.
22 * Please refer to csepdjvu(1) for the format specification.
23 */
24
25 namespace rle
26 {
27 class R4
28 {
29 protected:
30 std::ostream &stream;
31 unsigned int x, width, height;
32 unsigned int run_length;
33 int last_pixel;
34 public:
35 template <typename T> R4(std::ostream &, T width, T height);
36 void operator <<(int pixel);
37 template <typename T> void output_run(T);
38 };
39 }
40
41 template <typename T>
R4(std::ostream & stream,T width_,T height_)42 rle::R4::R4(std::ostream &stream, T width_, T height_)
43 : stream(stream),
44 x(0), width(width_), height(height_),
45 run_length(0),
46 last_pixel(0)
47 {
48 assert(width_ > 0);
49 assert(height_ > 0);
50 assert(static_cast<T>(this->width) == width_);
51 assert(static_cast<T>(this->height) == height_);
52 this->stream << "R4 " << this->width << " " << this->height << " ";
53 }
54
operator <<(int pixel)55 void rle::R4::operator <<(int pixel)
56 {
57 pixel = !!pixel;
58 this->x++;
59 assert(this->x > 0);
60 if (this->last_pixel != pixel)
61 {
62 this->output_run(this->run_length);
63 this->run_length = 1;
64 this->last_pixel = pixel;
65 }
66 else
67 this->run_length++;
68 if (this->x == this->width)
69 {
70 this->output_run(this->run_length);
71 this->last_pixel = 0;
72 this->x = 0;
73 this->run_length = 0;
74 }
75 }
76
77 template <typename T>
output_run(T length_)78 void rle::R4::output_run(T length_)
79 {
80 unsigned int length = length_;
81 static const unsigned int max_length = 0x3FFF;
82 assert(length_ >= 0);
83 assert(static_cast<T>(length) == length_);
84 assert(length <= this->width);
85 while (length > max_length)
86 {
87 this->stream.write("\xFF\xFF", 3);
88 length -= max_length;
89 }
90 if (length >= 192)
91 {
92 this->stream
93 << static_cast<char>(0xC0 + (length >> 8))
94 << static_cast<char>(length & 0xFF);
95 }
96 else
97 this->stream << static_cast<char>(length);
98 }
99
100 #endif
101
102 // vim:ts=2 sts=2 sw=2 et
103