- Added maximization features, with corresponding plugins. Added painting feature...
[mldemos:mldemos.git] / _3rdParty / dlib / image_saver / image_saver.h
1 // Copyright (C) 2006  Davis E. King (davis@dlib.net)\r
2 // License: Boost Software License   See LICENSE.txt for the full license.\r
3 #ifndef DLIB_IMAGE_SAVEr_\r
4 #define DLIB_IMAGE_SAVEr_\r
5 \r
6 #include "image_saver_abstract.h"\r
7 #include <iostream>\r
8 #include <sstream>\r
9 #include "../algs.h"\r
10 #include "../pixel.h"\r
11 #include "../byte_orderer.h"\r
12 #include "../entropy_encoder.h"\r
13 #include "../entropy_encoder_model.h"\r
14 #include "dng_shared.h"\r
15 #include "../uintn.h"\r
16 \r
17 namespace dlib\r
18 {\r
19 \r
20 // ----------------------------------------------------------------------------------------\r
21 \r
22     class image_save_error : public dlib::error { \r
23     public: image_save_error(const std::string& str) : error(EIMAGE_SAVE,str){}\r
24     };\r
25 \r
26 // ----------------------------------------------------------------------------------------\r
27 \r
28     template <\r
29         typename image_type,\r
30         bool grayscale = pixel_traits<typename image_type::type>::grayscale\r
31         >\r
32     struct save_bmp_helper;\r
33 \r
34 \r
35     template <typename image_type>\r
36     struct save_bmp_helper<image_type,false>\r
37     {\r
38         static void save_bmp (\r
39             const image_type& image,\r
40             std::ostream& out \r
41         )\r
42         {\r
43             // we are going to write out a 24bit color image.\r
44             byte_orderer::kernel_1a bo;\r
45 \r
46             out.write("BM",2);\r
47             \r
48             if (!out)\r
49                 throw image_save_error("error writing image to output stream");\r
50 \r
51 \r
52             unsigned long pad = 4 - (image.nc()*3)%4;\r
53             if (pad == 4)\r
54                 pad = 0;\r
55 \r
56             unsigned long bfSize = 14 + 40 + (image.nc()*3 + pad)*image.nr();\r
57             unsigned long bfReserved = 0;\r
58             unsigned long bfOffBits = 14 + 40;\r
59             unsigned long biSize = 40;\r
60             unsigned long biWidth = image.nc();\r
61             unsigned long biHeight = image.nr();\r
62             unsigned short biPlanes = 1;\r
63             unsigned short biBitCount = 24;\r
64             unsigned long biCompression = 0;\r
65             unsigned long biSizeImage = 0;\r
66             unsigned long biXPelsPerMeter = 0;\r
67             unsigned long biYPelsPerMeter = 0;\r
68             unsigned long biClrUsed = 0;\r
69             unsigned long biClrImportant = 0;\r
70 \r
71             bo.host_to_little(bfSize);\r
72             bo.host_to_little(bfOffBits);\r
73             bo.host_to_little(biSize);\r
74             bo.host_to_little(biWidth);\r
75             bo.host_to_little(biHeight);\r
76             bo.host_to_little(biPlanes);\r
77             bo.host_to_little(biBitCount);\r
78 \r
79             out.write((char*)&bfSize,4);\r
80             out.write((char*)&bfReserved,4);\r
81             out.write((char*)&bfOffBits,4);\r
82             out.write((char*)&biSize,4);\r
83             out.write((char*)&biWidth,4);\r
84             out.write((char*)&biHeight,4);\r
85             out.write((char*)&biPlanes,2);\r
86             out.write((char*)&biBitCount,2);\r
87             out.write((char*)&biCompression,4);\r
88             out.write((char*)&biSizeImage,4);\r
89             out.write((char*)&biXPelsPerMeter,4);\r
90             out.write((char*)&biYPelsPerMeter,4);\r
91             out.write((char*)&biClrUsed,4);\r
92             out.write((char*)&biClrImportant,4);\r
93 \r
94 \r
95             if (!out)\r
96                 throw image_save_error("error writing image to output stream");\r
97 \r
98             // now we write out the pixel data\r
99             for (long row = image.nr()-1; row >= 0; --row)\r
100             {\r
101                 for (long col = 0; col < image.nc(); ++col)\r
102                 {\r
103                     rgb_pixel p;\r
104                     p.red = 0;\r
105                     p.green = 0;\r
106                     p.blue = 0;\r
107                     assign_pixel(p,image[row][col]);\r
108                     out.write((char*)&p.blue,1);\r
109                     out.write((char*)&p.green,1);\r
110                     out.write((char*)&p.red,1);\r
111                 }\r
112 \r
113                 // write out some zeros so that this line is a multiple of 4 bytes\r
114                 for (unsigned long i = 0; i < pad; ++i)\r
115                 {\r
116                     unsigned char p = 0;\r
117                     out.write((char*)&p,1);\r
118                 }\r
119             }\r
120 \r
121             if (!out)\r
122                 throw image_save_error("error writing image to output stream");\r
123         }\r
124     };\r
125 \r
126     template <typename image_type>\r
127     struct save_bmp_helper<image_type,true>\r
128     {\r
129         static void save_bmp (\r
130             const image_type& image,\r
131             std::ostream& out\r
132         )\r
133         {\r
134             // we are going to write out an 8bit color image.\r
135             byte_orderer::kernel_1a bo;\r
136 \r
137             out.write("BM",2);\r
138             \r
139             if (!out)\r
140                 throw image_save_error("error writing image to output stream");\r
141 \r
142             unsigned long pad = 4 - image.nc()%4;\r
143             if (pad == 4)\r
144                 pad = 0;\r
145 \r
146             unsigned long bfSize = 14 + 40 + (image.nc() + pad)*image.nr() + 256*4;\r
147             unsigned long bfReserved = 0;\r
148             unsigned long bfOffBits = 14 + 40 + 256*4;\r
149             unsigned long biSize = 40;\r
150             unsigned long biWidth = image.nc();\r
151             unsigned long biHeight = image.nr();\r
152             unsigned short biPlanes = 1;\r
153             unsigned short biBitCount = 8;\r
154             unsigned long biCompression = 0;\r
155             unsigned long biSizeImage = 0;\r
156             unsigned long biXPelsPerMeter = 0;\r
157             unsigned long biYPelsPerMeter = 0;\r
158             unsigned long biClrUsed = 0;\r
159             unsigned long biClrImportant = 0;\r
160 \r
161             bo.host_to_little(bfSize);\r
162             bo.host_to_little(bfOffBits);\r
163             bo.host_to_little(biSize);\r
164             bo.host_to_little(biWidth);\r
165             bo.host_to_little(biHeight);\r
166             bo.host_to_little(biPlanes);\r
167             bo.host_to_little(biBitCount);\r
168 \r
169             out.write((char*)&bfSize,4);\r
170             out.write((char*)&bfReserved,4);\r
171             out.write((char*)&bfOffBits,4);\r
172             out.write((char*)&biSize,4);\r
173             out.write((char*)&biWidth,4);\r
174             out.write((char*)&biHeight,4);\r
175             out.write((char*)&biPlanes,2);\r
176             out.write((char*)&biBitCount,2);\r
177             out.write((char*)&biCompression,4);\r
178             out.write((char*)&biSizeImage,4);\r
179             out.write((char*)&biXPelsPerMeter,4);\r
180             out.write((char*)&biYPelsPerMeter,4);\r
181             out.write((char*)&biClrUsed,4);\r
182             out.write((char*)&biClrImportant,4);\r
183 \r
184 \r
185             // write out the color palette\r
186             for (unsigned int i = 0; i <= 255; ++i)\r
187             {\r
188                 unsigned char ch = static_cast<unsigned char>(i);\r
189                 out.write((char*)&ch,1);\r
190                 out.write((char*)&ch,1);\r
191                 out.write((char*)&ch,1);\r
192                 ch = 0;\r
193                 out.write((char*)&ch,1);\r
194             }\r
195 \r
196             if (!out)\r
197                 throw image_save_error("error writing image to output stream");\r
198 \r
199             // now we write out the pixel data\r
200             for (long row = image.nr()-1; row >= 0; --row)\r
201             {\r
202                 for (long col = 0; col < image.nc(); ++col)\r
203                 {\r
204                     unsigned char p = 0;\r
205                     assign_pixel(p,image[row][col]);\r
206                     out.write((char*)&p,1);\r
207                 }\r
208 \r
209                 // write out some zeros so that this line is a multiple of 4 bytes\r
210                 for (unsigned long i = 0; i < pad; ++i)\r
211                 {\r
212                     unsigned char p = 0;\r
213                     out.write((char*)&p,1);\r
214                 }\r
215             }\r
216 \r
217             if (!out)\r
218                 throw image_save_error("error writing image to output stream");\r
219 \r
220         }\r
221     };\r
222 \r
223 // ----------------------------------------------------------------------------------------\r
224 \r
225     template <\r
226         typename image_type \r
227         >\r
228     inline void save_bmp (\r
229         const image_type& image,\r
230         std::ostream& out\r
231     )\r
232     {\r
233         save_bmp_helper<image_type>::save_bmp(image,out);\r
234     }\r
235 \r
236 // ----------------------------------------------------------------------------------------\r
237 \r
238     namespace dng_helpers_namespace\r
239     {\r
240 \r
241         template <\r
242             typename image_type,\r
243             int pixel_type = static_switch <\r
244                 pixel_traits<typename image_type::type>::grayscale && sizeof(typename image_type::type) == 1,\r
245                 pixel_traits<typename image_type::type>::rgb,\r
246                 pixel_traits<typename image_type::type>::hsi,\r
247                 false,\r
248                 pixel_traits<typename image_type::type>::rgb_alpha,\r
249                 false,\r
250                 pixel_traits<typename image_type::type>::grayscale && sizeof(typename image_type::type) != 1\r
251                 >::value\r
252             >\r
253         struct save_dng_helper;\r
254 \r
255         typedef entropy_encoder::kernel_2a encoder_type;\r
256         typedef entropy_encoder_model<256,encoder_type>::kernel_5a eem_type; \r
257 \r
258         template <typename image_type >\r
259         struct save_dng_helper<image_type, grayscale_16bit>\r
260         {\r
261             static void save_dng (\r
262                 const image_type& image,\r
263                 std::ostream& out \r
264             )\r
265             {\r
266                 out.write("DNG",3);\r
267                 unsigned long version = 1;\r
268                 serialize(version,out);\r
269                 unsigned long type = grayscale_16bit;\r
270                 serialize(type,out);\r
271                 serialize(image.nc(),out);\r
272                 serialize(image.nr(),out);\r
273 \r
274                 encoder_type encoder;\r
275                 encoder.set_stream(out);\r
276 \r
277                 eem_type eem(encoder);\r
278                 for (long r = 0; r < image.nr(); ++r)\r
279                 {\r
280                     for (long c = 0; c < image.nc(); ++c)\r
281                     {\r
282                         uint16 cur;\r
283                         assign_pixel(cur, image[r][c]);\r
284                         cur -= predictor_grayscale_16(image,r,c);\r
285                         unsigned char byte1 = cur&0xFF;\r
286                         unsigned char byte2 = cur>>8;\r
287                         eem.encode(byte2);\r
288                         eem.encode(byte1);\r
289                     }\r
290                 }\r
291                 // write out the magic byte to mark the end of the data\r
292                 eem.encode(dng_magic_byte);\r
293                 eem.encode(dng_magic_byte);\r
294                 eem.encode(dng_magic_byte);\r
295                 eem.encode(dng_magic_byte);\r
296             }\r
297         };\r
298 \r
299 \r
300         template <typename image_type>\r
301         struct save_dng_helper<image_type, grayscale>\r
302         {\r
303             static void save_dng (\r
304                 const image_type& image,\r
305                 std::ostream& out \r
306             )\r
307             {\r
308                 out.write("DNG",3);\r
309                 unsigned long version = 1;\r
310                 serialize(version,out);\r
311                 unsigned long type = grayscale;\r
312                 serialize(type,out);\r
313                 serialize(image.nc(),out);\r
314                 serialize(image.nr(),out);\r
315 \r
316                 encoder_type encoder;\r
317                 encoder.set_stream(out);\r
318 \r
319                 eem_type eem(encoder);\r
320                 for (long r = 0; r < image.nr(); ++r)\r
321                 {\r
322                     for (long c = 0; c < image.nc(); ++c)\r
323                     {\r
324                         unsigned char cur;\r
325                         assign_pixel(cur, image[r][c]);\r
326                         eem.encode(cur - predictor_grayscale(image,r,c));\r
327                     }\r
328                 }\r
329                 // write out the magic byte to mark the end of the data\r
330                 eem.encode(dng_magic_byte);\r
331                 eem.encode(dng_magic_byte);\r
332                 eem.encode(dng_magic_byte);\r
333                 eem.encode(dng_magic_byte);\r
334             }\r
335         };\r
336 \r
337         template <typename image_type>\r
338         struct save_dng_helper<image_type,rgb>\r
339         {\r
340             static void save_dng (\r
341                 const image_type& image,\r
342                 std::ostream& out\r
343             )\r
344             {\r
345                 out.write("DNG",3);\r
346                 unsigned long version = 1;\r
347                 serialize(version,out);\r
348 \r
349                 unsigned long type = rgb;\r
350                 // if this is a small image then we will use a different predictor\r
351                 if (image.size() < 4000)\r
352                     type = rgb_paeth;\r
353 \r
354                 serialize(type,out);\r
355                 serialize(image.nc(),out);\r
356                 serialize(image.nr(),out);\r
357 \r
358                 encoder_type encoder;\r
359                 encoder.set_stream(out);\r
360 \r
361                 rgb_pixel pre, cur;\r
362                 eem_type eem(encoder);\r
363 \r
364                 if (type == rgb)\r
365                 {\r
366                     for (long r = 0; r < image.nr(); ++r)\r
367                     {\r
368                         for (long c = 0; c < image.nc(); ++c)\r
369                         {\r
370                             pre = predictor_rgb(image,r,c);\r
371                             assign_pixel(cur, image[r][c]);\r
372 \r
373                             eem.encode((unsigned char)(cur.red - pre.red));\r
374                             eem.encode((unsigned char)(cur.green - pre.green));\r
375                             eem.encode((unsigned char)(cur.blue - pre.blue));\r
376                         }\r
377                     }\r
378                 }\r
379                 else\r
380                 {\r
381                     for (long r = 0; r < image.nr(); ++r)\r
382                     {\r
383                         for (long c = 0; c < image.nc(); ++c)\r
384                         {\r
385                             pre = predictor_rgb_paeth(image,r,c);\r
386                             assign_pixel(cur, image[r][c]);\r
387 \r
388                             eem.encode((unsigned char)(cur.red - pre.red));\r
389                             eem.encode((unsigned char)(cur.green - pre.green));\r
390                             eem.encode((unsigned char)(cur.blue - pre.blue));\r
391                         }\r
392                     }\r
393                 }\r
394                 // write out the magic byte to mark the end of the data\r
395                 eem.encode(dng_magic_byte);\r
396                 eem.encode(dng_magic_byte);\r
397                 eem.encode(dng_magic_byte);\r
398                 eem.encode(dng_magic_byte);\r
399             }\r
400         };\r
401 \r
402         template <typename image_type>\r
403         struct save_dng_helper<image_type,rgb_alpha>\r
404         {\r
405             static void save_dng (\r
406                 const image_type& image,\r
407                 std::ostream& out\r
408             )\r
409             {\r
410                 out.write("DNG",3);\r
411                 unsigned long version = 1;\r
412                 serialize(version,out);\r
413 \r
414                 unsigned long type = rgb_alpha;\r
415                 // if this is a small image then we will use a different predictor\r
416                 if (image.size() < 4000)\r
417                     type = rgb_alpha_paeth;\r
418 \r
419                 serialize(type,out);\r
420                 serialize(image.nc(),out);\r
421                 serialize(image.nr(),out);\r
422 \r
423                 encoder_type encoder;\r
424                 encoder.set_stream(out);\r
425 \r
426                 rgb_alpha_pixel pre, cur;\r
427                 eem_type eem(encoder);\r
428 \r
429                 if (type == rgb_alpha)\r
430                 {\r
431                     for (long r = 0; r < image.nr(); ++r)\r
432                     {\r
433                         for (long c = 0; c < image.nc(); ++c)\r
434                         {\r
435                             pre = predictor_rgb_alpha(image,r,c);\r
436                             assign_pixel(cur, image[r][c]);\r
437 \r
438                             eem.encode((unsigned char)(cur.red - pre.red));\r
439                             eem.encode((unsigned char)(cur.green - pre.green));\r
440                             eem.encode((unsigned char)(cur.blue - pre.blue));\r
441                             eem.encode((unsigned char)(cur.alpha - pre.alpha));\r
442                         }\r
443                     }\r
444                 }\r
445                 else\r
446                 {\r
447                     for (long r = 0; r < image.nr(); ++r)\r
448                     {\r
449                         for (long c = 0; c < image.nc(); ++c)\r
450                         {\r
451                             pre = predictor_rgb_alpha_paeth(image,r,c);\r
452                             assign_pixel(cur, image[r][c]);\r
453 \r
454                             eem.encode((unsigned char)(cur.red - pre.red));\r
455                             eem.encode((unsigned char)(cur.green - pre.green));\r
456                             eem.encode((unsigned char)(cur.blue - pre.blue));\r
457                             eem.encode((unsigned char)(cur.alpha - pre.alpha));\r
458                         }\r
459                     }\r
460                 }\r
461                 // write out the magic byte to mark the end of the data\r
462                 eem.encode(dng_magic_byte);\r
463                 eem.encode(dng_magic_byte);\r
464                 eem.encode(dng_magic_byte);\r
465                 eem.encode(dng_magic_byte);\r
466             }\r
467         };\r
468 \r
469         template <typename image_type>\r
470         struct save_dng_helper<image_type,hsi>\r
471         {\r
472             static void save_dng (\r
473                 const image_type& image,\r
474                 std::ostream& out\r
475             )\r
476             {\r
477                 out.write("DNG",3);\r
478                 unsigned long version = 1;\r
479                 serialize(version,out);\r
480                 unsigned long type = hsi;\r
481                 serialize(type,out);\r
482                 serialize(image.nc(),out);\r
483                 serialize(image.nr(),out);\r
484 \r
485                 encoder_type encoder;\r
486                 encoder.set_stream(out);\r
487 \r
488                 hsi_pixel pre, cur;\r
489                 eem_type eem(encoder);\r
490                 for (long r = 0; r < image.nr(); ++r)\r
491                 {\r
492                     for (long c = 0; c < image.nc(); ++c)\r
493                     {\r
494                         pre = predictor_hsi(image,r,c);\r
495                         assign_pixel(cur, image[r][c]);\r
496 \r
497                         eem.encode((unsigned char)(cur.h - pre.h));\r
498                         eem.encode((unsigned char)(cur.s - pre.s));\r
499                         eem.encode((unsigned char)(cur.i - pre.i));\r
500                     }\r
501                 }\r
502                 // write out the magic byte to mark the end of the data\r
503                 eem.encode(dng_magic_byte);\r
504                 eem.encode(dng_magic_byte);\r
505                 eem.encode(dng_magic_byte);\r
506                 eem.encode(dng_magic_byte);\r
507             }\r
508         };\r
509     }\r
510 \r
511 // ----------------------------------------------------------------------------------------\r
512 \r
513     template <\r
514         typename image_type \r
515         >\r
516     inline void save_dng (\r
517         const image_type& image,\r
518         std::ostream& out\r
519     )\r
520     {\r
521         using namespace dng_helpers_namespace;\r
522         save_dng_helper<image_type>::save_dng(image,out);\r
523     }\r
524 \r
525 // ----------------------------------------------------------------------------------------\r
526 \r
527 \r
528 }\r
529 \r
530 #endif // DLIB_IMAGE_SAVEr_\r
531 \r
532 \r
533 \r
534 \r