Allow size-specific resizers
[jpcrr.git] / streamtools / resize.cpp
blob09f97d2503be631ca5e5a9f00165b6705fff5a6f
1 #include "resize.hpp"
2 #include <stdexcept>
3 #include <iostream>
4 #include <zlib.h>
5 #include <cstring>
6 #include <map>
7 #include <string>
8 #include <sstream>
9 #include <cmath>
11 namespace
13 uint32_t decode32(const unsigned char* buf)
15 uint32_t v = 0;
16 v |= ((uint32_t)buf[0] << 24);
17 v |= ((uint32_t)buf[1] << 16);
18 v |= ((uint32_t)buf[2] << 8);
19 v |= ((uint32_t)buf[3]);
20 return v;
23 #define INBUF_SIZE 16384
24 #define OUTBUF_SIZE 16384
26 void decode_zlib(unsigned char* target, const unsigned char* src, uint32_t insize, uint32_t pixels)
28 unsigned char out[INBUF_SIZE];
29 unsigned char in[OUTBUF_SIZE];
30 uint32_t dptr = 0;
32 z_stream s;
33 memset(&s, 0, sizeof(s));
34 int r = inflateInit(&s);
35 if(r < 0) {
36 std::stringstream str;
37 str << "inflateInit: zlib error: " << s.msg;
38 throw std::runtime_error(str.str());
41 s.next_in = in;
42 s.avail_in = 0;
43 s.next_out = out;
44 s.avail_out = INBUF_SIZE;
46 while(1) {
47 uint32_t old_avail_out = s.avail_out;
49 if(s.avail_in == 0) {
50 if(insize > OUTBUF_SIZE) {
51 s.next_in = in;
52 s.avail_in = OUTBUF_SIZE;
53 memcpy(s.next_in, src, OUTBUF_SIZE);
54 src += OUTBUF_SIZE;
55 insize -= OUTBUF_SIZE;
56 } else {
57 s.next_in = in;
58 s.avail_in = insize;
59 memcpy(s.next_in, src, insize);
60 src += insize;
61 insize = 0;
65 r = inflate(&s, Z_NO_FLUSH);
66 if(r < 0) {
67 inflateEnd(&s);
68 std::stringstream str;
69 str << "inflate: zlib error: " << s.msg;
70 throw std::runtime_error(str.str());
72 dptr += (old_avail_out - s.avail_out);
73 if(s.avail_out == 0) {
74 memcpy(target, out, INBUF_SIZE);
75 target += INBUF_SIZE;
76 s.avail_out = INBUF_SIZE;
77 s.next_out = out;
79 if(dptr == 4 * pixels) {
80 memcpy(target, out, INBUF_SIZE - s.avail_out);
81 target += (INBUF_SIZE - s.avail_out);
82 s.avail_out = INBUF_SIZE;
83 s.next_out = out;
84 break;
86 if(r == Z_STREAM_END) {
87 inflateEnd(&s);
88 std::stringstream str;
89 str << "Uncompressed stream truncated";
90 throw std::runtime_error(str.str());
93 inflateEnd(&s);
98 const unsigned char* image_frame_rgbx::get_pixels() const
100 return imagedata;
103 unsigned char* image_frame_rgbx::get_pixels()
105 return imagedata;
108 uint32_t image_frame_rgbx::get_height() const
110 return height;
113 uint32_t image_frame_rgbx::get_width() const
115 return width;
118 image_frame_rgbx::~image_frame_rgbx()
120 delete[] imagedata;
123 image_frame_rgbx::image_frame_rgbx(uint32_t width, uint32_t height)
125 this->width = width;
126 this->height = height;
127 if(width && height)
128 this->imagedata = new unsigned char[4 * width * height];
129 else
130 this->imagedata = NULL;
133 image_frame_rgbx::image_frame_rgbx(const image_frame_rgbx& x)
135 this->width = x.width;
136 this->height = x.height;
137 if(width && height) {
138 this->imagedata = new unsigned char[4 * width * height];
139 memcpy(imagedata, x.imagedata, 4 * width * height);
140 } else
141 this->imagedata = NULL;
144 image_frame_rgbx& image_frame_rgbx::operator=(const image_frame_rgbx& x)
146 if(this == &x)
147 return *this;
148 unsigned char* old_imagedata = imagedata;
149 if(x.width && x.height)
150 this->imagedata = new unsigned char[4 * x.width * x.height];
151 else
152 this->imagedata = NULL;
153 this->width = x.width;
154 this->height = x.height;
155 if(x.width && x.height)
156 memcpy(imagedata, x.imagedata, 4 * width * height);
157 delete[] old_imagedata;
158 return *this;
161 image_frame_rgbx::image_frame_rgbx(struct packet& p)
163 if(p.rp_major != 0) {
164 std::stringstream str;
165 str << "frame_from_packet: Incorrect major type (" << p.rp_major << ", should be 0)";
166 throw std::runtime_error(str.str());
168 if(p.rp_minor != 0 && p.rp_minor != 1) {
169 std::stringstream str;
170 str << "frame_from_packet: Unknown minor type (" << p.rp_minor << ", should be 0 or 1)";
171 throw std::runtime_error(str.str());
173 if(p.rp_payload.size() < 4)
174 throw std::runtime_error("frame_from_packet: Malformed payload (image parameters missing)");
176 uint32_t ihdr = decode32(&p.rp_payload[0]);
177 width = ihdr / 65536;
178 height = ihdr % 65536;
179 imagedata = new unsigned char[4 * width * height];
181 if(p.rp_minor == 0)
182 memcpy(imagedata, &p.rp_payload[4], 4 * width * height);
183 else if(p.rp_minor == 1)
184 try {
185 decode_zlib(imagedata, &p.rp_payload[4], p.rp_payload.size() - 4, width * height);
186 } catch(...) {
187 delete[] imagedata;
188 imagedata = NULL;
189 throw;
193 size_t image_frame_rgbx::get_data_size() const
195 return 4 * width * height;
198 image_frame_rgbx& image_frame_rgbx::resize(uint32_t nwidth, uint32_t nheight, resizer& using_resizer)
200 if(width == nwidth && height == nheight)
201 return *this;
202 image_frame_rgbx* newf = new image_frame_rgbx(nwidth, nheight);
203 if(width == 0 && height == 0) {
204 //Fill with black.
205 memset(newf->get_pixels(), 0, newf->get_data_size());
206 return *newf;
208 using_resizer(newf->get_pixels(), nwidth, nheight, get_pixels(), width, height);
209 return *newf;
212 resizer::~resizer()
216 std::map<std::string, resizer_factory*>* resizer_factory::factories;
218 resizer_factory::~resizer_factory()
222 resizer_factory::resizer_factory(const std::string& type)
224 if(!factories)
225 factories = new std::map<std::string, resizer_factory*>();
226 (*factories)[type] = this;
229 resizer& resizer_factory::make_by_type(const std::string& type)
231 if(!factories || !factories->count(type))
232 throw std::runtime_error("Unknown output driver type");
233 return (*factories)[type]->make(type);
236 std::string get_resizer_list()
238 bool first = true;
239 if(!resizer_factory::factories)
240 return "";
241 std::string c;
242 std::map<std::string, resizer_factory*>& f = *resizer_factory::factories;
243 for(std::map<std::string, resizer_factory*>::iterator i = f.begin(); i != f.end(); ++i) {
244 if(first)
245 c = i->first;
246 else
247 c = c + " " + i->first;
248 first = false;
250 return c;
253 namespace
255 class simple_resizer_c : public resizer
257 public:
258 simple_resizer_c(void(*_resize_fn)(uint8_t* target, uint32_t twidth, uint32_t theight,
259 const uint8_t* source, uint32_t swidth, uint32_t sheight))
261 resize_fn = _resize_fn;
264 void operator()(uint8_t* target, uint32_t twidth, uint32_t theight,
265 const uint8_t* source, uint32_t swidth, uint32_t sheight)
267 resize_fn(target, twidth, theight, source, swidth, sheight);
270 private:
271 void(*resize_fn)(uint8_t* target, uint32_t twidth, uint32_t theight,
272 const uint8_t* source, uint32_t swidth, uint32_t sheight);
275 class simple_resizer_c2 : public resizer
277 public:
278 simple_resizer_c2(void(*_resize_fn)(uint8_t* target, uint32_t twidth, uint32_t theight,
279 const uint8_t* source, uint32_t swidth, uint32_t sheight, int algo), int _algo)
281 resize_fn = _resize_fn;
282 algo = _algo;
285 void operator()(uint8_t* target, uint32_t twidth, uint32_t theight,
286 const uint8_t* source, uint32_t swidth, uint32_t sheight)
288 resize_fn(target, twidth, theight, source, swidth, sheight, algo);
291 private:
292 void(*resize_fn)(uint8_t* target, uint32_t twidth, uint32_t theight,
293 const uint8_t* source, uint32_t swidth, uint32_t sheight, int algo);
294 int algo;
298 simple_resizer::simple_resizer(const std::string& type, void(*_resize_fn)(uint8_t* target, uint32_t twidth, uint32_t theight,
299 const uint8_t* source, uint32_t swidth, uint32_t sheight))
300 : resizer_factory(type)
302 resize_fn = _resize_fn;
303 resize_fn2 = NULL;
304 algo = 0;
307 simple_resizer::simple_resizer(const std::string& type, void(*_resize_fn)(uint8_t* target, uint32_t twidth, uint32_t theight,
308 const uint8_t* source, uint32_t swidth, uint32_t sheight, int algo), int _algo)
309 : resizer_factory(type)
311 resize_fn = NULL;
312 resize_fn2 = _resize_fn;
313 algo = _algo;
316 resizer& simple_resizer::make(const std::string& type)
318 if(resize_fn)
319 return *new simple_resizer_c(resize_fn);
320 else
321 return *new simple_resizer_c2(resize_fn2, algo);