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