summaryrefslogtreecommitdiffstats
path: root/ml/dlib/dlib/image_saver
diff options
context:
space:
mode:
Diffstat (limited to 'ml/dlib/dlib/image_saver')
-rw-r--r--ml/dlib/dlib/image_saver/dng_shared.h288
-rw-r--r--ml/dlib/dlib/image_saver/image_saver.h688
-rw-r--r--ml/dlib/dlib/image_saver/image_saver_abstract.h129
-rw-r--r--ml/dlib/dlib/image_saver/save_jpeg.cpp175
-rw-r--r--ml/dlib/dlib/image_saver/save_jpeg.h82
-rw-r--r--ml/dlib/dlib/image_saver/save_jpeg_abstract.h52
-rw-r--r--ml/dlib/dlib/image_saver/save_png.cpp124
-rw-r--r--ml/dlib/dlib/image_saver/save_png.h162
-rw-r--r--ml/dlib/dlib/image_saver/save_png_abstract.h50
9 files changed, 1750 insertions, 0 deletions
diff --git a/ml/dlib/dlib/image_saver/dng_shared.h b/ml/dlib/dlib/image_saver/dng_shared.h
new file mode 100644
index 000000000..d098851b3
--- /dev/null
+++ b/ml/dlib/dlib/image_saver/dng_shared.h
@@ -0,0 +1,288 @@
+// Copyright (C) 2007 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#ifndef DLIB_DNG_SHAREd_
+#define DLIB_DNG_SHAREd_
+
+#include "../pixel.h"
+#include <cmath>
+#include "../uintn.h"
+
+namespace dlib
+{
+
+ namespace dng_helpers_namespace
+ {
+ enum
+ {
+ grayscale = 1,
+ rgb,
+ hsi,
+ rgb_paeth,
+ rgb_alpha,
+ rgb_alpha_paeth,
+ grayscale_16bit,
+ grayscale_float
+ };
+
+ const unsigned long dng_magic_byte = 100;
+
+ template <typename T>
+ rgb_pixel predictor_rgb_paeth (const T& img, long row, long col)
+ /*
+ This is similar to the Paeth filter from the PNG image format.
+ */
+ {
+ // a = left, b = above, c = upper left
+ rgb_pixel a(0,0,0), b(0,0,0), c(0,0,0);
+
+
+ const long c1 = col-1;
+ const long r1 = row-1;
+
+ if (c1 >= 0)
+ assign_pixel(a, img[row][c1]);
+ else
+ assign_pixel(a,(unsigned char)0);
+
+ if (c1 >= 0 && r1 >= 0)
+ assign_pixel(c, img[r1][c1]);
+ else
+ assign_pixel(c,(unsigned char)0);
+
+ if (r1 >= 0)
+ assign_pixel(b, img[r1][col]);
+ else
+ assign_pixel(b,(unsigned char)0);
+
+
+ rgb_pixel p;
+ p.red = a.red + b.red - c.red;
+ p.green = a.green + b.green - c.green;
+ p.blue = a.blue + b.blue - c.blue;
+
+ short pa = std::abs((short)p.red - (short)a.red) +
+ std::abs((short)p.green - (short)a.green) +
+ std::abs((short)p.blue - (short)a.blue);
+ short pb = std::abs((short)p.red - (short)b.red) +
+ std::abs((short)p.green - (short)b.green) +
+ std::abs((short)p.blue - (short)b.blue);
+ short pc = std::abs((short)p.red - (short)c.red) +
+ std::abs((short)p.green - (short)c.green) +
+ std::abs((short)p.blue - (short)c.blue);
+
+ if (pa <= pb && pa <= pc)
+ return a;
+ else if (pb <= pc)
+ return b;
+ else
+ return c;
+ }
+
+
+ template <typename T>
+ rgb_pixel predictor_rgb (const T& img, long row, long col)
+ {
+ // a = left, b = above, c = upper left
+ rgb_pixel a(0,0,0), b(0,0,0), c(0,0,0);
+
+
+ const long c1 = col-1;
+ const long r1 = row-1;
+
+ if (c1 >= 0)
+ assign_pixel(a, img[row][c1]);
+ else
+ assign_pixel(a,(unsigned char)0);
+
+ if (c1 >= 0 && r1 >= 0)
+ assign_pixel(c, img[r1][c1]);
+ else
+ assign_pixel(c,(unsigned char)0);
+
+ if (r1 >= 0)
+ assign_pixel(b, img[r1][col]);
+ else
+ assign_pixel(b,(unsigned char)0);
+
+
+ rgb_pixel p;
+ p.red = a.red + b.red - c.red;
+ p.green = a.green + b.green - c.green;
+ p.blue = a.blue + b.blue - c.blue;
+ return p;
+ }
+
+ template <typename T>
+ rgb_alpha_pixel predictor_rgb_alpha_paeth (const T& img, long row, long col)
+ /*
+ This is similar to the Paeth filter from the PNG image format.
+ */
+ {
+ // a = left, b = above, c = upper left
+ rgb_alpha_pixel a, b, c;
+
+
+ const long c1 = col-1;
+ const long r1 = row-1;
+
+ if (c1 >= 0)
+ assign_pixel(a, img[row][c1]);
+ else
+ assign_pixel(a,(unsigned char)0);
+
+ if (c1 >= 0 && r1 >= 0)
+ assign_pixel(c, img[r1][c1]);
+ else
+ assign_pixel(c,(unsigned char)0);
+
+ if (r1 >= 0)
+ assign_pixel(b, img[r1][col]);
+ else
+ assign_pixel(b,(unsigned char)0);
+
+
+ rgb_alpha_pixel p;
+ p.red = a.red + b.red - c.red;
+ p.green = a.green + b.green - c.green;
+ p.blue = a.blue + b.blue - c.blue;
+
+ short pa = std::abs((short)p.red - (short)a.red) +
+ std::abs((short)p.green - (short)a.green) +
+ std::abs((short)p.blue - (short)a.blue);
+ short pb = std::abs((short)p.red - (short)b.red) +
+ std::abs((short)p.green - (short)b.green) +
+ std::abs((short)p.blue - (short)b.blue);
+ short pc = std::abs((short)p.red - (short)c.red) +
+ std::abs((short)p.green - (short)c.green) +
+ std::abs((short)p.blue - (short)c.blue);
+
+ if (pa <= pb && pa <= pc)
+ return a;
+ else if (pb <= pc)
+ return b;
+ else
+ return c;
+ }
+
+
+ template <typename T>
+ rgb_alpha_pixel predictor_rgb_alpha (const T& img, long row, long col)
+ {
+ // a = left, b = above, c = upper left
+ rgb_alpha_pixel a, b, c;
+
+
+ const long c1 = col-1;
+ const long r1 = row-1;
+
+ if (c1 >= 0)
+ assign_pixel(a, img[row][c1]);
+ else
+ assign_pixel(a,(unsigned char)0);
+
+ if (c1 >= 0 && r1 >= 0)
+ assign_pixel(c, img[r1][c1]);
+ else
+ assign_pixel(c,(unsigned char)0);
+
+ if (r1 >= 0)
+ assign_pixel(b, img[r1][col]);
+ else
+ assign_pixel(b,(unsigned char)0);
+
+
+ rgb_alpha_pixel p;
+ p.red = a.red + b.red - c.red;
+ p.green = a.green + b.green - c.green;
+ p.blue = a.blue + b.blue - c.blue;
+ p.alpha = a.alpha + b.alpha - c.alpha;
+ return p;
+ }
+
+
+ template <typename T>
+ hsi_pixel predictor_hsi (const T& img, long row, long col)
+ {
+ // a = left, b = above, c = upper left
+ hsi_pixel a(0,0,0), b(0,0,0), c(0,0,0);
+
+
+ const long c1 = col-1;
+ const long r1 = row-1;
+
+ if (c1 >= 0)
+ assign_pixel(a, img[row][c1]);
+ else
+ assign_pixel(a,(unsigned char)0);
+
+ if (c1 >= 0 && r1 >= 0)
+ assign_pixel(c, img[r1][c1]);
+ else
+ assign_pixel(c,(unsigned char)0);
+
+ if (r1 >= 0)
+ assign_pixel(b, img[r1][col]);
+ else
+ assign_pixel(b,(unsigned char)0);
+
+
+ hsi_pixel p;
+ p.h = a.h + b.h - c.h;
+ p.s = a.s + b.s - c.s;
+ p.i = a.i + b.i - c.i;
+ return p;
+ }
+
+ template <typename T>
+ unsigned char predictor_grayscale (const T& img, long row, long col)
+ {
+ // a = left, b = above, c = upper left
+ unsigned char a = 0, b = 0, c = 0;
+
+
+ const long c1 = col-1;
+ const long r1 = row-1;
+
+ if (c1 >= 0)
+ assign_pixel(a, img[row][c1]);
+
+ if (c1 >= 0 && r1 >= 0)
+ assign_pixel(c, img[r1][c1]);
+
+ if (r1 >= 0)
+ assign_pixel(b, img[r1][col]);
+
+
+ unsigned char p = a + b - c;
+ return p;
+ }
+
+ template <typename T>
+ uint16 predictor_grayscale_16 (const T& img, long row, long col)
+ {
+ // a = left, b = above, c = upper left
+ uint16 a = 0, b = 0, c = 0;
+
+
+ const long c1 = col-1;
+ const long r1 = row-1;
+
+ if (c1 >= 0)
+ assign_pixel(a, img[row][c1]);
+
+ if (c1 >= 0 && r1 >= 0)
+ assign_pixel(c, img[r1][c1]);
+
+ if (r1 >= 0)
+ assign_pixel(b, img[r1][col]);
+
+
+ uint16 p = a + b - c;
+ return p;
+ }
+
+ }
+}
+
+#endif // DLIB_DNG_SHAREd_
+
diff --git a/ml/dlib/dlib/image_saver/image_saver.h b/ml/dlib/dlib/image_saver/image_saver.h
new file mode 100644
index 000000000..43a2717af
--- /dev/null
+++ b/ml/dlib/dlib/image_saver/image_saver.h
@@ -0,0 +1,688 @@
+// Copyright (C) 2006 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#ifndef DLIB_IMAGE_SAVEr_
+#define DLIB_IMAGE_SAVEr_
+
+#include "image_saver_abstract.h"
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include "../algs.h"
+#include "../pixel.h"
+#include "../byte_orderer.h"
+#include "../entropy_encoder.h"
+#include "../entropy_encoder_model.h"
+#include "dng_shared.h"
+#include "../uintn.h"
+#include "../dir_nav.h"
+#include "../float_details.h"
+#include "../vectorstream.h"
+#include "../matrix/matrix_exp.h"
+#include "../image_transforms/assign_image.h"
+
+namespace dlib
+{
+
+// ----------------------------------------------------------------------------------------
+
+ class image_save_error : public dlib::error {
+ public: image_save_error(const std::string& str) : error(EIMAGE_SAVE,str){}
+ };
+
+// ----------------------------------------------------------------------------------------
+
+ template <
+ typename image_type,
+ bool grayscale = pixel_traits<typename image_traits<image_type>::pixel_type>::grayscale
+ >
+ struct save_bmp_helper;
+
+
+ template <typename image_type>
+ struct save_bmp_helper<image_type,false>
+ {
+ static void save_bmp (
+ const image_type& image_,
+ std::ostream& out
+ )
+ {
+ const_image_view<image_type> image(image_);
+ // we are going to write out a 24bit color image.
+ byte_orderer::kernel_1a bo;
+
+ out.write("BM",2);
+
+ if (!out)
+ throw image_save_error("error writing image to output stream");
+
+
+ unsigned long pad = 4 - (image.nc()*3)%4;
+ if (pad == 4)
+ pad = 0;
+
+ unsigned long bfSize = 14 + 40 + (image.nc()*3 + pad)*image.nr();
+ unsigned long bfReserved = 0;
+ unsigned long bfOffBits = 14 + 40;
+ unsigned long biSize = 40;
+ unsigned long biWidth = image.nc();
+ unsigned long biHeight = image.nr();
+ unsigned short biPlanes = 1;
+ unsigned short biBitCount = 24;
+ unsigned long biCompression = 0;
+ unsigned long biSizeImage = 0;
+ unsigned long biXPelsPerMeter = 0;
+ unsigned long biYPelsPerMeter = 0;
+ unsigned long biClrUsed = 0;
+ unsigned long biClrImportant = 0;
+
+ bo.host_to_little(bfSize);
+ bo.host_to_little(bfOffBits);
+ bo.host_to_little(biSize);
+ bo.host_to_little(biWidth);
+ bo.host_to_little(biHeight);
+ bo.host_to_little(biPlanes);
+ bo.host_to_little(biBitCount);
+
+ out.write((char*)&bfSize,4);
+ out.write((char*)&bfReserved,4);
+ out.write((char*)&bfOffBits,4);
+ out.write((char*)&biSize,4);
+ out.write((char*)&biWidth,4);
+ out.write((char*)&biHeight,4);
+ out.write((char*)&biPlanes,2);
+ out.write((char*)&biBitCount,2);
+ out.write((char*)&biCompression,4);
+ out.write((char*)&biSizeImage,4);
+ out.write((char*)&biXPelsPerMeter,4);
+ out.write((char*)&biYPelsPerMeter,4);
+ out.write((char*)&biClrUsed,4);
+ out.write((char*)&biClrImportant,4);
+
+
+ if (!out)
+ throw image_save_error("error writing image to output stream");
+
+ // now we write out the pixel data
+ for (long row = image.nr()-1; row >= 0; --row)
+ {
+ for (long col = 0; col < image.nc(); ++col)
+ {
+ rgb_pixel p;
+ p.red = 0;
+ p.green = 0;
+ p.blue = 0;
+ assign_pixel(p,image[row][col]);
+ out.write((char*)&p.blue,1);
+ out.write((char*)&p.green,1);
+ out.write((char*)&p.red,1);
+ }
+
+ // write out some zeros so that this line is a multiple of 4 bytes
+ for (unsigned long i = 0; i < pad; ++i)
+ {
+ unsigned char p = 0;
+ out.write((char*)&p,1);
+ }
+ }
+
+ if (!out)
+ throw image_save_error("error writing image to output stream");
+ }
+ };
+
+ template <typename image_type>
+ struct save_bmp_helper<image_type,true>
+ {
+ static void save_bmp (
+ const image_type& image_,
+ std::ostream& out
+ )
+ {
+ const_image_view<image_type> image(image_);
+ // we are going to write out an 8bit color image.
+ byte_orderer::kernel_1a bo;
+
+ out.write("BM",2);
+
+ if (!out)
+ throw image_save_error("error writing image to output stream");
+
+ unsigned long pad = 4 - image.nc()%4;
+ if (pad == 4)
+ pad = 0;
+
+ unsigned long bfSize = 14 + 40 + (image.nc() + pad)*image.nr() + 256*4;
+ unsigned long bfReserved = 0;
+ unsigned long bfOffBits = 14 + 40 + 256*4;
+ unsigned long biSize = 40;
+ unsigned long biWidth = image.nc();
+ unsigned long biHeight = image.nr();
+ unsigned short biPlanes = 1;
+ unsigned short biBitCount = 8;
+ unsigned long biCompression = 0;
+ unsigned long biSizeImage = 0;
+ unsigned long biXPelsPerMeter = 0;
+ unsigned long biYPelsPerMeter = 0;
+ unsigned long biClrUsed = 0;
+ unsigned long biClrImportant = 0;
+
+ bo.host_to_little(bfSize);
+ bo.host_to_little(bfOffBits);
+ bo.host_to_little(biSize);
+ bo.host_to_little(biWidth);
+ bo.host_to_little(biHeight);
+ bo.host_to_little(biPlanes);
+ bo.host_to_little(biBitCount);
+
+ out.write((char*)&bfSize,4);
+ out.write((char*)&bfReserved,4);
+ out.write((char*)&bfOffBits,4);
+ out.write((char*)&biSize,4);
+ out.write((char*)&biWidth,4);
+ out.write((char*)&biHeight,4);
+ out.write((char*)&biPlanes,2);
+ out.write((char*)&biBitCount,2);
+ out.write((char*)&biCompression,4);
+ out.write((char*)&biSizeImage,4);
+ out.write((char*)&biXPelsPerMeter,4);
+ out.write((char*)&biYPelsPerMeter,4);
+ out.write((char*)&biClrUsed,4);
+ out.write((char*)&biClrImportant,4);
+
+
+ // write out the color palette
+ for (unsigned int i = 0; i <= 255; ++i)
+ {
+ unsigned char ch = static_cast<unsigned char>(i);
+ out.write((char*)&ch,1);
+ out.write((char*)&ch,1);
+ out.write((char*)&ch,1);
+ ch = 0;
+ out.write((char*)&ch,1);
+ }
+
+ if (!out)
+ throw image_save_error("error writing image to output stream");
+
+ // now we write out the pixel data
+ for (long row = image.nr()-1; row >= 0; --row)
+ {
+ for (long col = 0; col < image.nc(); ++col)
+ {
+ unsigned char p = 0;
+ assign_pixel(p,image[row][col]);
+ out.write((char*)&p,1);
+ }
+
+ // write out some zeros so that this line is a multiple of 4 bytes
+ for (unsigned long i = 0; i < pad; ++i)
+ {
+ unsigned char p = 0;
+ out.write((char*)&p,1);
+ }
+ }
+
+ if (!out)
+ throw image_save_error("error writing image to output stream");
+
+ }
+ };
+
+// ----------------------------------------------------------------------------------------
+
+ template <
+ typename image_type
+ >
+ inline typename disable_if<is_matrix<image_type> >::type save_bmp (
+ const image_type& image,
+ std::ostream& out
+ )
+ {
+ save_bmp_helper<image_type>::save_bmp(image,out);
+ }
+
+ template <
+ typename EXP
+ >
+ inline void save_bmp (
+ const matrix_exp<EXP>& image,
+ std::ostream& out
+ )
+ {
+ array2d<typename EXP::type> temp;
+ assign_image(temp, image);
+ save_bmp_helper<array2d<typename EXP::type> >::save_bmp(temp,out);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ namespace dng_helpers_namespace
+ {
+ template <
+ typename image_type,
+ typename enabled = void
+ >
+ struct save_dng_helper;
+
+ typedef entropy_encoder::kernel_2a encoder_type;
+ typedef entropy_encoder_model<256,encoder_type>::kernel_5a eem_type;
+
+ typedef entropy_encoder_model<256,encoder_type>::kernel_4a eem_exp_type;
+
+ template <typename image_type >
+ struct save_dng_helper<image_type, typename enable_if<is_float_type<typename image_traits<image_type>::pixel_type> >::type >
+ {
+ static void save_dng (
+ const image_type& image_,
+ std::ostream& out
+ )
+ {
+ const_image_view<image_type> image(image_);
+ out.write("DNG",3);
+ unsigned long version = 1;
+ serialize(version,out);
+ unsigned long type = grayscale_float;
+ serialize(type,out);
+ serialize(image.nc(),out);
+ serialize(image.nr(),out);
+
+
+ // Write the compressed exponent data into expbuf. We will append it
+ // to the stream at the end of the loops.
+ std::vector<char> expbuf;
+ expbuf.reserve(image.size()*2);
+ vectorstream outexp(expbuf);
+ encoder_type encoder;
+ encoder.set_stream(outexp);
+
+ eem_exp_type eem_exp(encoder);
+ float_details prev;
+ for (long r = 0; r < image.nr(); ++r)
+ {
+ for (long c = 0; c < image.nc(); ++c)
+ {
+ float_details cur = image[r][c];
+ int16 exp = cur.exponent-prev.exponent;
+ int64 man = cur.mantissa-prev.mantissa;
+ prev = cur;
+
+ unsigned char ebyte1 = exp&0xFF;
+ unsigned char ebyte2 = exp>>8;
+ eem_exp.encode(ebyte1);
+ eem_exp.encode(ebyte2);
+
+ serialize(man, out);
+ }
+ }
+ // write out the magic byte to mark the end of the compressed data.
+ eem_exp.encode(dng_magic_byte);
+ eem_exp.encode(dng_magic_byte);
+ eem_exp.encode(dng_magic_byte);
+ eem_exp.encode(dng_magic_byte);
+
+ encoder.clear();
+ serialize(expbuf, out);
+ }
+ };
+
+
+ template <typename image_type>
+ struct is_non_float_non8bit_grayscale
+ {
+ typedef typename image_traits<image_type>::pixel_type pixel_type;
+ const static bool value = pixel_traits<pixel_type>::grayscale &&
+ sizeof(pixel_type) != 1 &&
+ !is_float_type<pixel_type>::value;
+ };
+
+ template <typename image_type >
+ struct save_dng_helper<image_type, typename enable_if<is_non_float_non8bit_grayscale<image_type> >::type>
+ {
+ static void save_dng (
+ const image_type& image_,
+ std::ostream& out
+ )
+ {
+ const_image_view<image_type> image(image_);
+ out.write("DNG",3);
+ unsigned long version = 1;
+ serialize(version,out);
+ unsigned long type = grayscale_16bit;
+ serialize(type,out);
+ serialize(image.nc(),out);
+ serialize(image.nr(),out);
+
+ encoder_type encoder;
+ encoder.set_stream(out);
+
+ eem_type eem(encoder);
+ for (long r = 0; r < image.nr(); ++r)
+ {
+ for (long c = 0; c < image.nc(); ++c)
+ {
+ uint16 cur;
+ assign_pixel(cur, image[r][c]);
+ cur -= predictor_grayscale_16(image,r,c);
+ unsigned char byte1 = cur&0xFF;
+ unsigned char byte2 = cur>>8;
+ eem.encode(byte2);
+ eem.encode(byte1);
+ }
+ }
+ // write out the magic byte to mark the end of the data
+ eem.encode(dng_magic_byte);
+ eem.encode(dng_magic_byte);
+ eem.encode(dng_magic_byte);
+ eem.encode(dng_magic_byte);
+ }
+ };
+
+ template <typename image_type>
+ struct is_8bit_grayscale
+ {
+ typedef typename image_traits<image_type>::pixel_type pixel_type;
+ const static bool value = pixel_traits<pixel_type>::grayscale && sizeof(pixel_type) == 1;
+ };
+
+ template <typename image_type>
+ struct save_dng_helper<image_type, typename enable_if<is_8bit_grayscale<image_type> >::type>
+ {
+ static void save_dng (
+ const image_type& image_,
+ std::ostream& out
+ )
+ {
+ const_image_view<image_type> image(image_);
+ out.write("DNG",3);
+ unsigned long version = 1;
+ serialize(version,out);
+ unsigned long type = grayscale;
+ serialize(type,out);
+ serialize(image.nc(),out);
+ serialize(image.nr(),out);
+
+ encoder_type encoder;
+ encoder.set_stream(out);
+
+ eem_type eem(encoder);
+ for (long r = 0; r < image.nr(); ++r)
+ {
+ for (long c = 0; c < image.nc(); ++c)
+ {
+ unsigned char cur;
+ assign_pixel(cur, image[r][c]);
+ cur -= predictor_grayscale(image,r,c);
+ eem.encode(cur);
+ }
+ }
+ // write out the magic byte to mark the end of the data
+ eem.encode(dng_magic_byte);
+ eem.encode(dng_magic_byte);
+ eem.encode(dng_magic_byte);
+ eem.encode(dng_magic_byte);
+ }
+ };
+
+ template <typename image_type>
+ struct is_rgb_image
+ {
+ typedef typename image_traits<image_type>::pixel_type pixel_type;
+ const static bool value = pixel_traits<pixel_type>::rgb;
+ };
+
+ template <typename image_type>
+ struct save_dng_helper<image_type,typename enable_if<is_rgb_image<image_type> >::type>
+ {
+ static void save_dng (
+ const image_type& image_,
+ std::ostream& out
+ )
+ {
+ const_image_view<image_type> image(image_);
+ out.write("DNG",3);
+ unsigned long version = 1;
+ serialize(version,out);
+
+ unsigned long type = rgb;
+ // if this is a small image then we will use a different predictor
+ if (image.size() < 4000)
+ type = rgb_paeth;
+
+ serialize(type,out);
+ serialize(image.nc(),out);
+ serialize(image.nr(),out);
+
+ encoder_type encoder;
+ encoder.set_stream(out);
+
+ rgb_pixel pre, cur;
+ eem_type eem(encoder);
+
+ if (type == rgb)
+ {
+ for (long r = 0; r < image.nr(); ++r)
+ {
+ for (long c = 0; c < image.nc(); ++c)
+ {
+ pre = predictor_rgb(image,r,c);
+ assign_pixel(cur, image[r][c]);
+
+ eem.encode((unsigned char)(cur.red - pre.red));
+ eem.encode((unsigned char)(cur.green - pre.green));
+ eem.encode((unsigned char)(cur.blue - pre.blue));
+ }
+ }
+ }
+ else
+ {
+ for (long r = 0; r < image.nr(); ++r)
+ {
+ for (long c = 0; c < image.nc(); ++c)
+ {
+ pre = predictor_rgb_paeth(image,r,c);
+ assign_pixel(cur, image[r][c]);
+
+ eem.encode((unsigned char)(cur.red - pre.red));
+ eem.encode((unsigned char)(cur.green - pre.green));
+ eem.encode((unsigned char)(cur.blue - pre.blue));
+ }
+ }
+ }
+ // write out the magic byte to mark the end of the data
+ eem.encode(dng_magic_byte);
+ eem.encode(dng_magic_byte);
+ eem.encode(dng_magic_byte);
+ eem.encode(dng_magic_byte);
+ }
+ };
+
+ template <typename image_type>
+ struct is_rgb_alpha_image
+ {
+ typedef typename image_traits<image_type>::pixel_type pixel_type;
+ const static bool value = pixel_traits<pixel_type>::rgb_alpha;
+ };
+
+ template <typename image_type>
+ struct save_dng_helper<image_type,typename enable_if<is_rgb_alpha_image<image_type> >::type>
+ {
+ static void save_dng (
+ const image_type& image_,
+ std::ostream& out
+ )
+ {
+ const_image_view<image_type> image(image_);
+ out.write("DNG",3);
+ unsigned long version = 1;
+ serialize(version,out);
+
+ unsigned long type = rgb_alpha;
+ // if this is a small image then we will use a different predictor
+ if (image.size() < 4000)
+ type = rgb_alpha_paeth;
+
+ serialize(type,out);
+ serialize(image.nc(),out);
+ serialize(image.nr(),out);
+
+ encoder_type encoder;
+ encoder.set_stream(out);
+
+ rgb_alpha_pixel pre, cur;
+ eem_type eem(encoder);
+
+ if (type == rgb_alpha)
+ {
+ for (long r = 0; r < image.nr(); ++r)
+ {
+ for (long c = 0; c < image.nc(); ++c)
+ {
+ pre = predictor_rgb_alpha(image,r,c);
+ assign_pixel(cur, image[r][c]);
+
+ eem.encode((unsigned char)(cur.red - pre.red));
+ eem.encode((unsigned char)(cur.green - pre.green));
+ eem.encode((unsigned char)(cur.blue - pre.blue));
+ eem.encode((unsigned char)(cur.alpha - pre.alpha));
+ }
+ }
+ }
+ else
+ {
+ for (long r = 0; r < image.nr(); ++r)
+ {
+ for (long c = 0; c < image.nc(); ++c)
+ {
+ pre = predictor_rgb_alpha_paeth(image,r,c);
+ assign_pixel(cur, image[r][c]);
+
+ eem.encode((unsigned char)(cur.red - pre.red));
+ eem.encode((unsigned char)(cur.green - pre.green));
+ eem.encode((unsigned char)(cur.blue - pre.blue));
+ eem.encode((unsigned char)(cur.alpha - pre.alpha));
+ }
+ }
+ }
+ // write out the magic byte to mark the end of the data
+ eem.encode(dng_magic_byte);
+ eem.encode(dng_magic_byte);
+ eem.encode(dng_magic_byte);
+ eem.encode(dng_magic_byte);
+ }
+ };
+
+ template <typename image_type>
+ struct is_hsi_image
+ {
+ typedef typename image_traits<image_type>::pixel_type pixel_type;
+ const static bool value = pixel_traits<pixel_type>::hsi;
+ };
+
+ template <typename image_type>
+ struct save_dng_helper<image_type,typename enable_if<is_hsi_image<image_type> >::type>
+ {
+ static void save_dng (
+ const image_type& image_,
+ std::ostream& out
+ )
+ {
+ const_image_view<image_type> image(image_);
+ out.write("DNG",3);
+ unsigned long version = 1;
+ serialize(version,out);
+ unsigned long type = hsi;
+ serialize(type,out);
+ serialize(image.nc(),out);
+ serialize(image.nr(),out);
+
+ encoder_type encoder;
+ encoder.set_stream(out);
+
+ hsi_pixel pre, cur;
+ eem_type eem(encoder);
+ for (long r = 0; r < image.nr(); ++r)
+ {
+ for (long c = 0; c < image.nc(); ++c)
+ {
+ pre = predictor_hsi(image,r,c);
+ assign_pixel(cur, image[r][c]);
+
+ eem.encode((unsigned char)(cur.h - pre.h));
+ eem.encode((unsigned char)(cur.s - pre.s));
+ eem.encode((unsigned char)(cur.i - pre.i));
+ }
+ }
+ // write out the magic byte to mark the end of the data
+ eem.encode(dng_magic_byte);
+ eem.encode(dng_magic_byte);
+ eem.encode(dng_magic_byte);
+ eem.encode(dng_magic_byte);
+ }
+ };
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ template <
+ typename image_type
+ >
+ inline typename disable_if<is_matrix<image_type> >::type save_dng (
+ const image_type& image,
+ std::ostream& out
+ )
+ {
+ using namespace dng_helpers_namespace;
+ save_dng_helper<image_type>::save_dng(image,out);
+ }
+
+ template <
+ typename EXP
+ >
+ inline void save_dng (
+ const matrix_exp<EXP>& image,
+ std::ostream& out
+ )
+ {
+ array2d<typename EXP::type> temp;
+ assign_image(temp, image);
+ using namespace dng_helpers_namespace;
+ save_dng_helper<array2d<typename EXP::type> >::save_dng(temp,out);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ template <typename image_type>
+ void save_dng (
+ const image_type& image,
+ const std::string& file_name
+ )
+ {
+ std::ofstream fout(file_name.c_str(), std::ios::binary);
+ if (!fout)
+ throw image_save_error("Unable to open " + file_name + " for writing.");
+ save_dng(image, fout);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ template <typename image_type>
+ void save_bmp (
+ const image_type& image,
+ const std::string& file_name
+ )
+ {
+ std::ofstream fout(file_name.c_str(), std::ios::binary);
+ if (!fout)
+ throw image_save_error("Unable to open " + file_name + " for writing.");
+ save_bmp(image, fout);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+}
+
+#endif // DLIB_IMAGE_SAVEr_
+
+
+
+
diff --git a/ml/dlib/dlib/image_saver/image_saver_abstract.h b/ml/dlib/dlib/image_saver/image_saver_abstract.h
new file mode 100644
index 000000000..82f91ed45
--- /dev/null
+++ b/ml/dlib/dlib/image_saver/image_saver_abstract.h
@@ -0,0 +1,129 @@
+// Copyright (C) 2006 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#undef DLIB_IMAGE_SAVEr_ABSTRACT_
+#ifdef DLIB_IMAGE_SAVEr_ABSTRACT_
+
+#include <iosfwd>
+#include "../algs.h"
+#include "../pixel.h"
+#include "../image_processing/generic_image.h"
+
+namespace dlib
+{
+ class image_save_error : public dlib::error
+ {
+ /*!
+ WHAT THIS OBJECT REPRESENTS
+ This is an exception used to indicate a failure to save an image.
+ Its type member variable will be set to EIMAGE_SAVE.
+ !*/
+ };
+
+// ----------------------------------------------------------------------------------------
+
+ template <
+ typename image_type
+ >
+ void save_bmp (
+ const image_type& image,
+ std::ostream& out
+ );
+ /*!
+ requires
+ - image_type == an image object that implements the interface defined in
+ dlib/image_processing/generic_image.h or any kind of matrix expression.
+ ensures
+ - writes the image to the out stream in the Microsoft Windows BMP format.
+ - image[0][0] will be in the upper left corner of the image.
+ - image[image.nr()-1][image.nc()-1] will be in the lower right
+ corner of the image.
+ - This routine can save images containing any type of pixel. However, it
+ will convert all color pixels into rgb_pixel and grayscale pixels into
+ uint8 type before saving to disk.
+ throws
+ - image_save_error
+ This exception is thrown if there is an error that prevents us
+ from saving the image.
+ - std::bad_alloc
+ !*/
+
+// ----------------------------------------------------------------------------------------
+
+ template <
+ typename image_type
+ >
+ void save_bmp (
+ const image_type& image,
+ const std::string& file_name
+ );
+ /*!
+ requires
+ - image_type == an image object that implements the interface defined in
+ dlib/image_processing/generic_image.h or any kind of matrix expression.
+ ensures
+ - opens the file indicated by file_name with an output file stream named fout
+ and performs:
+ save_bmp(image,fout);
+ !*/
+
+// ----------------------------------------------------------------------------------------
+
+ /*!
+ dlib dng file format:
+ This is a file format I created for this library. It is a lossless
+ compressed image format that is similar to the PNG format but uses
+ the dlib PPM compression algorithms instead of the DEFLATE algorithm.
+ !*/
+
+ template <
+ typename image_type
+ >
+ void save_dng (
+ const image_type& image,
+ std::ostream& out
+ );
+ /*!
+ requires
+ - image_type == an image object that implements the interface defined in
+ dlib/image_processing/generic_image.h or any kind of matrix expression.
+ ensures
+ - writes the image to the out stream in the dlib dng format.
+ - image[0][0] will be in the upper left corner of the image.
+ - image[image.nr()-1][image.nc()-1] will be in the lower right
+ corner of the image.
+ - This routine can save images containing any type of pixel. However, the DNG
+ format can natively store only the following pixel types: rgb_pixel,
+ hsi_pixel, rgb_alpha_pixel, uint8, uint16, float, and double.
+ All other pixel types will be converted into one of these types as
+ appropriate before being saved to disk.
+ throws
+ - image_save_error
+ This exception is thrown if there is an error that prevents us
+ from saving the image.
+ - std::bad_alloc
+ !*/
+
+// ----------------------------------------------------------------------------------------
+
+ template <typename image_type>
+ void save_dng (
+ const image_type& image,
+ const std::string& file_name
+ );
+ /*!
+ requires
+ - image_type == an image object that implements the interface defined in
+ dlib/image_processing/generic_image.h or any kind of matrix expression.
+ ensures
+ - opens the file indicated by file_name with an output file stream named fout
+ and performs:
+ save_dng(image,fout);
+ !*/
+
+// ----------------------------------------------------------------------------------------
+
+}
+
+#endif // DLIB_IMAGE_SAVEr_ABSTRACT_
+
+
diff --git a/ml/dlib/dlib/image_saver/save_jpeg.cpp b/ml/dlib/dlib/image_saver/save_jpeg.cpp
new file mode 100644
index 000000000..ef637fa7a
--- /dev/null
+++ b/ml/dlib/dlib/image_saver/save_jpeg.cpp
@@ -0,0 +1,175 @@
+// Copyright (C) 2014 Davis E. King (davis@dlib.net), Nils Labugt
+// License: Boost Software License See LICENSE.txt for the full license.
+#ifndef DLIB_JPEG_SAVER_CPp_
+#define DLIB_JPEG_SAVER_CPp_
+
+// only do anything with this file if DLIB_JPEG_SUPPORT is defined
+#ifdef DLIB_JPEG_SUPPORT
+
+#include "../array2d.h"
+#include "../pixel.h"
+#include "save_jpeg.h"
+#include <stdio.h>
+#include <sstream>
+#include <setjmp.h>
+#include "image_saver.h"
+
+#ifdef DLIB_JPEG_STATIC
+# include "../external/libjpeg/jpeglib.h"
+#else
+# include <jpeglib.h>
+#endif
+
+namespace dlib
+{
+
+// ----------------------------------------------------------------------------------------
+
+ struct jpeg_saver_error_mgr
+ {
+ jpeg_error_mgr pub; /* "public" fields */
+ jmp_buf setjmp_buffer; /* for return to caller */
+ };
+
+ void jpeg_saver_error_exit (j_common_ptr cinfo)
+ {
+ /* cinfo->err really points to a jpeg_saver_error_mgr struct, so coerce pointer */
+ jpeg_saver_error_mgr* myerr = (jpeg_saver_error_mgr*) cinfo->err;
+
+ /* Return control to the setjmp point */
+ longjmp(myerr->setjmp_buffer, 1);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void save_jpeg (
+ const array2d<rgb_pixel>& img,
+ const std::string& filename,
+ int quality
+ )
+ {
+ // make sure requires clause is not broken
+ DLIB_CASSERT(img.size() != 0,
+ "\t save_jpeg()"
+ << "\n\t You can't save an empty image as a JPEG."
+ );
+ DLIB_CASSERT(0 <= quality && quality <= 100,
+ "\t save_jpeg()"
+ << "\n\t Invalid quality value."
+ << "\n\t quality: " << quality
+ );
+
+ FILE* outfile = fopen(filename.c_str(), "wb");
+ if (!outfile)
+ throw image_save_error("Can't open file " + filename + " for writing.");
+
+ jpeg_compress_struct cinfo;
+
+ jpeg_saver_error_mgr jerr;
+ cinfo.err = jpeg_std_error(&jerr.pub);
+ jerr.pub.error_exit = jpeg_saver_error_exit;
+ /* Establish the setjmp return context for my_error_exit to use. */
+ if (setjmp(jerr.setjmp_buffer))
+ {
+ /* If we get here, the JPEG code has signaled an error.
+ * We need to clean up the JPEG object, close the input file, and return.
+ */
+ jpeg_destroy_compress(&cinfo);
+ fclose(outfile);
+ throw image_save_error("save_jpeg: error while writing " + filename);
+ }
+
+ jpeg_create_compress(&cinfo);
+ jpeg_stdio_dest(&cinfo, outfile);
+
+ cinfo.image_width = img.nc();
+ cinfo.image_height = img.nr();
+ cinfo.input_components = 3;
+ cinfo.in_color_space = JCS_RGB;
+ jpeg_set_defaults(&cinfo);
+ jpeg_set_quality (&cinfo, quality, TRUE);
+ jpeg_start_compress(&cinfo, TRUE);
+
+ // now write out the rows one at a time
+ while (cinfo.next_scanline < cinfo.image_height) {
+ JSAMPROW row_pointer = (JSAMPROW) &img[cinfo.next_scanline][0];
+ jpeg_write_scanlines(&cinfo, &row_pointer, 1);
+ }
+
+ jpeg_finish_compress(&cinfo);
+ jpeg_destroy_compress(&cinfo);
+ fclose( outfile );
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ void save_jpeg (
+ const array2d<unsigned char>& img,
+ const std::string& filename,
+ int quality
+ )
+ {
+ // make sure requires clause is not broken
+ DLIB_CASSERT(img.size() != 0,
+ "\t save_jpeg()"
+ << "\n\t You can't save an empty image as a JPEG."
+ );
+ DLIB_CASSERT(0 <= quality && quality <= 100,
+ "\t save_jpeg()"
+ << "\n\t Invalid quality value."
+ << "\n\t quality: " << quality
+ );
+
+
+ FILE* outfile = fopen(filename.c_str(), "wb");
+ if (!outfile)
+ throw image_save_error("Can't open file " + filename + " for writing.");
+
+ jpeg_compress_struct cinfo;
+
+ jpeg_saver_error_mgr jerr;
+ cinfo.err = jpeg_std_error(&jerr.pub);
+ jerr.pub.error_exit = jpeg_saver_error_exit;
+ /* Establish the setjmp return context for my_error_exit to use. */
+ if (setjmp(jerr.setjmp_buffer))
+ {
+ /* If we get here, the JPEG code has signaled an error.
+ * We need to clean up the JPEG object, close the input file, and return.
+ */
+ jpeg_destroy_compress(&cinfo);
+ fclose(outfile);
+ throw image_save_error("save_jpeg: error while writing " + filename);
+ }
+
+ jpeg_create_compress(&cinfo);
+ jpeg_stdio_dest(&cinfo, outfile);
+
+ cinfo.image_width = img.nc();
+ cinfo.image_height = img.nr();
+ cinfo.input_components = 1;
+ cinfo.in_color_space = JCS_GRAYSCALE;
+ jpeg_set_defaults(&cinfo);
+ jpeg_set_quality (&cinfo, quality, TRUE);
+ jpeg_start_compress(&cinfo, TRUE);
+
+ // now write out the rows one at a time
+ while (cinfo.next_scanline < cinfo.image_height) {
+ JSAMPROW row_pointer = (JSAMPROW) &img[cinfo.next_scanline][0];
+ jpeg_write_scanlines(&cinfo, &row_pointer, 1);
+ }
+
+ jpeg_finish_compress(&cinfo);
+ jpeg_destroy_compress(&cinfo);
+ fclose( outfile );
+ }
+
+// ----------------------------------------------------------------------------------------
+
+}
+
+#endif // DLIB_JPEG_SUPPORT
+
+#endif // DLIB_JPEG_SAVER_CPp_
+
+
+
diff --git a/ml/dlib/dlib/image_saver/save_jpeg.h b/ml/dlib/dlib/image_saver/save_jpeg.h
new file mode 100644
index 000000000..fb1808c44
--- /dev/null
+++ b/ml/dlib/dlib/image_saver/save_jpeg.h
@@ -0,0 +1,82 @@
+// Copyright (C) 2014 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#ifndef DLIB_SAVE_JPEG_Hh_
+#define DLIB_SAVE_JPEG_Hh_
+
+#include "save_jpeg_abstract.h"
+
+#include "../enable_if.h"
+#include "../matrix.h"
+#include "../array2d.h"
+#include "../pixel.h"
+#include "../image_processing/generic_image.h"
+#include <string>
+
+namespace dlib
+{
+
+// ----------------------------------------------------------------------------------------
+
+ void save_jpeg (
+ const array2d<rgb_pixel>& img,
+ const std::string& filename,
+ int quality = 75
+ );
+
+// ----------------------------------------------------------------------------------------
+
+ void save_jpeg (
+ const array2d<unsigned char>& img,
+ const std::string& filename,
+ int quality = 75
+ );
+
+// ----------------------------------------------------------------------------------------
+
+ template <
+ typename image_type
+ >
+ typename disable_if<is_matrix<image_type> >::type save_jpeg(
+ const image_type& img,
+ const std::string& filename,
+ int quality = 75
+ )
+ {
+ // Convert any kind of grayscale image to an unsigned char image
+ if (pixel_traits<typename image_traits<image_type>::pixel_type>::grayscale)
+ {
+ array2d<unsigned char> temp;
+ assign_image(temp, img);
+ save_jpeg(temp, filename, quality);
+ }
+ else
+ {
+ // This is some other kind of color image so just save it as an RGB image.
+ array2d<rgb_pixel> temp;
+ assign_image(temp, img);
+ save_jpeg(temp, filename, quality);
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ template <
+ typename EXP
+ >
+ void save_jpeg(
+ const matrix_exp<EXP>& img,
+ const std::string& file_name,
+ int quality = 75
+ )
+ {
+ array2d<typename EXP::type> temp;
+ assign_image(temp, img);
+ save_jpeg(temp, file_name, quality);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+}
+
+#endif // DLIB_SAVE_JPEG_Hh_
+
diff --git a/ml/dlib/dlib/image_saver/save_jpeg_abstract.h b/ml/dlib/dlib/image_saver/save_jpeg_abstract.h
new file mode 100644
index 000000000..f441339b9
--- /dev/null
+++ b/ml/dlib/dlib/image_saver/save_jpeg_abstract.h
@@ -0,0 +1,52 @@
+// Copyright (C) 2014 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#undef DLIB_SAVE_JPEG_ABSTRACT_Hh_
+#ifdef DLIB_SAVE_JPEG_ABSTRACT_Hh_
+
+#include "../image_processing/generic_image.h"
+#include "../pixel.h"
+#include <string>
+
+namespace dlib
+{
+
+// ----------------------------------------------------------------------------------------
+
+ template <
+ typename image_type
+ >
+ void save_jpeg (
+ const image_type& img,
+ const std::string& filename,
+ int quality = 75
+ );
+ /*!
+ requires
+ - image_type == an image object that implements the interface defined in
+ dlib/image_processing/generic_image.h or a matrix expression
+ - image.size() != 0
+ - 0 <= quality <= 100
+ ensures
+ - writes the image to the file indicated by file_name in the JPEG format.
+ - image[0][0] will be in the upper left corner of the image.
+ - image[image.nr()-1][image.nc()-1] will be in the lower right corner of the
+ image.
+ - This routine can save images containing any type of pixel. However,
+ save_jpeg() can only natively store rgb_pixel and uint8 pixel types. All
+ other pixel types will be converted into one of these types as appropriate
+ before being saved to disk.
+ - The quality value determines how lossy the compression is. Larger quality
+ values result in larger output images but the images will look better.
+ throws
+ - image_save_error
+ This exception is thrown if there is an error that prevents us from saving
+ the image.
+ - std::bad_alloc
+ !*/
+
+// ----------------------------------------------------------------------------------------
+
+}
+
+#endif // DLIB_SAVE_JPEG_ABSTRACT_Hh_
+
diff --git a/ml/dlib/dlib/image_saver/save_png.cpp b/ml/dlib/dlib/image_saver/save_png.cpp
new file mode 100644
index 000000000..1c96b929c
--- /dev/null
+++ b/ml/dlib/dlib/image_saver/save_png.cpp
@@ -0,0 +1,124 @@
+// Copyright (C) 2011 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#ifndef DLIB_SAVE_PnG_CPPh_
+#define DLIB_SAVE_PnG_CPPh_
+
+// only do anything with this file if DLIB_PNG_SUPPORT is defined
+#ifdef DLIB_PNG_SUPPORT
+
+#include "save_png.h"
+#include <cstdio>
+#include <png.h>
+#include "../byte_orderer.h"
+
+namespace dlib
+{
+ // Don't do anything when libpng calls us to tell us about an error. Just return to
+ // our own code and throw an exception (at the long jump target).
+ void png_reader_user_error_fn_silent(png_structp png_struct, png_const_charp )
+ {
+ longjmp(png_jmpbuf(png_struct),1);
+ }
+ void png_reader_user_warning_fn_silent(png_structp , png_const_charp )
+ {
+ }
+
+ namespace impl
+ {
+ void impl_save_png (
+ const std::string& file_name,
+ std::vector<unsigned char*>& row_pointers,
+ const long width,
+ const png_type type,
+ const int bit_depth
+ )
+ {
+
+ FILE *fp;
+ png_structp png_ptr;
+ png_infop info_ptr;
+
+ /* Open the file */
+ fp = fopen(file_name.c_str(), "wb");
+ if (fp == NULL)
+ throw image_save_error("Unable to open " + file_name + " for writing.");
+
+ /* Create and initialize the png_struct with the desired error handler
+ * functions. If you want to use the default stderr and longjump method,
+ * you can supply NULL for the last three parameters. We also check that
+ * the library version is compatible with the one used at compile time,
+ * in case we are using dynamically linked libraries. REQUIRED.
+ */
+ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, &png_reader_user_error_fn_silent, &png_reader_user_warning_fn_silent);
+
+ if (png_ptr == NULL)
+ {
+ fclose(fp);
+ throw image_save_error("Error while writing PNG file " + file_name);
+ }
+
+ /* Allocate/initialize the image information data. REQUIRED */
+ info_ptr = png_create_info_struct(png_ptr);
+ if (info_ptr == NULL)
+ {
+ fclose(fp);
+ png_destroy_write_struct(&png_ptr, NULL);
+ throw image_save_error("Error while writing PNG file " + file_name);
+ }
+
+ /* Set error handling. REQUIRED if you aren't supplying your own
+ * error handling functions in the png_create_write_struct() call.
+ */
+ if (setjmp(png_jmpbuf(png_ptr)))
+ {
+ /* If we get here, we had a problem writing the file */
+ fclose(fp);
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+ throw image_save_error("Error while writing PNG file " + file_name);
+ }
+
+ int color_type = 0;
+ switch(type)
+ {
+ case png_type_rgb: color_type = PNG_COLOR_TYPE_RGB; break;
+ case png_type_rgb_alpha: color_type = PNG_COLOR_TYPE_RGB_ALPHA; break;
+ case png_type_gray: color_type = PNG_COLOR_TYPE_GRAY; break;
+ default:
+ {
+ fclose(fp);
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+ throw image_save_error("Invalid color type");
+ }
+ }
+
+
+ /* Set up the output control if you are using standard C streams */
+ png_init_io(png_ptr, fp);
+
+
+ int png_transforms = PNG_TRANSFORM_IDENTITY;
+ byte_orderer bo;
+ if (bo.host_is_little_endian())
+ png_transforms |= PNG_TRANSFORM_SWAP_ENDIAN;
+
+ const long height = row_pointers.size();
+
+
+ png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
+ png_set_rows(png_ptr, info_ptr, &row_pointers[0]);
+ png_write_png(png_ptr, info_ptr, png_transforms, NULL);
+
+ /* Clean up after the write, and free any memory allocated */
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+
+ /* Close the file */
+ fclose(fp);
+ }
+ }
+}
+
+#endif // DLIB_PNG_SUPPORT
+
+#endif // DLIB_SAVE_PnG_CPPh_
+
+
diff --git a/ml/dlib/dlib/image_saver/save_png.h b/ml/dlib/dlib/image_saver/save_png.h
new file mode 100644
index 000000000..cddf03ff6
--- /dev/null
+++ b/ml/dlib/dlib/image_saver/save_png.h
@@ -0,0 +1,162 @@
+// Copyright (C) 2011 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#ifndef DLIB_SAVE_PnG_Hh_
+#define DLIB_SAVE_PnG_Hh_
+
+#include "save_png_abstract.h"
+#include "image_saver.h"
+#include "../array2d.h"
+#include <vector>
+#include <string>
+#include "../pixel.h"
+#include "../matrix/matrix_exp.h"
+#include "../image_transforms/assign_image.h"
+
+namespace dlib
+{
+
+// ----------------------------------------------------------------------------------------
+
+ namespace impl
+ {
+ enum png_type
+ {
+ png_type_rgb,
+ png_type_rgb_alpha,
+ png_type_gray,
+ };
+
+ void impl_save_png (
+ const std::string& file_name,
+ std::vector<unsigned char*>& row_pointers,
+ const long width,
+ const png_type type,
+ const int bit_depth
+ );
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ template <
+ typename image_type
+ >
+ typename disable_if<is_matrix<image_type> >::type save_png(
+ const image_type& img_,
+ const std::string& file_name
+ )
+ {
+ const_image_view<image_type> img(img_);
+
+ // make sure requires clause is not broken
+ DLIB_CASSERT(img.size() != 0,
+ "\t save_png()"
+ << "\n\t You can't save an empty image as a PNG"
+ );
+
+
+#ifndef DLIB_PNG_SUPPORT
+ /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ You are getting this error because you are trying to use save_png()
+ but you haven't defined DLIB_PNG_SUPPORT. You must do so to use
+ this function. You must also make sure you set your build environment
+ to link against the libpng library.
+ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
+ COMPILE_TIME_ASSERT(sizeof(image_type) == 0);
+#else
+ std::vector<unsigned char*> row_pointers(img.nr());
+ typedef typename image_traits<image_type>::pixel_type pixel_type;
+
+ if (is_same_type<rgb_pixel,pixel_type>::value)
+ {
+ for (unsigned long i = 0; i < row_pointers.size(); ++i)
+ row_pointers[i] = (unsigned char*)(&img[i][0]);
+
+ impl::impl_save_png(file_name, row_pointers, img.nc(), impl::png_type_rgb, 8);
+ }
+ else if (is_same_type<rgb_alpha_pixel,pixel_type>::value)
+ {
+ for (unsigned long i = 0; i < row_pointers.size(); ++i)
+ row_pointers[i] = (unsigned char*)(&img[i][0]);
+
+ impl::impl_save_png(file_name, row_pointers, img.nc(), impl::png_type_rgb_alpha, 8);
+ }
+ else if (pixel_traits<pixel_type>::lab || pixel_traits<pixel_type>::hsi || pixel_traits<pixel_type>::rgb)
+ {
+ // convert from Lab or HSI to RGB (Or potentially RGB pixels that aren't laid out as R G B)
+ array2d<rgb_pixel> temp_img;
+ assign_image(temp_img, img_);
+ for (unsigned long i = 0; i < row_pointers.size(); ++i)
+ row_pointers[i] = (unsigned char*)(&temp_img[i][0]);
+
+ impl::impl_save_png(file_name, row_pointers, img.nc(), impl::png_type_rgb, 8);
+ }
+ else if (pixel_traits<pixel_type>::rgb_alpha)
+ {
+ // convert from RGBA pixels that aren't laid out as R G B A
+ array2d<rgb_alpha_pixel> temp_img;
+ assign_image(temp_img, img_);
+ for (unsigned long i = 0; i < row_pointers.size(); ++i)
+ row_pointers[i] = (unsigned char*)(&temp_img[i][0]);
+
+ impl::impl_save_png(file_name, row_pointers, img.nc(), impl::png_type_rgb_alpha, 8);
+ }
+ else // this is supposed to be grayscale
+ {
+ DLIB_CASSERT(pixel_traits<pixel_type>::grayscale, "impossible condition detected");
+
+ if (pixel_traits<pixel_type>::is_unsigned && sizeof(pixel_type) == 1)
+ {
+ for (unsigned long i = 0; i < row_pointers.size(); ++i)
+ row_pointers[i] = (unsigned char*)(&img[i][0]);
+
+ impl::impl_save_png(file_name, row_pointers, img.nc(), impl::png_type_gray, 8);
+ }
+ else if (pixel_traits<pixel_type>::is_unsigned && sizeof(pixel_type) == 2)
+ {
+ for (unsigned long i = 0; i < row_pointers.size(); ++i)
+ row_pointers[i] = (unsigned char*)(&img[i][0]);
+
+ impl::impl_save_png(file_name, row_pointers, img.nc(), impl::png_type_gray, 16);
+ }
+ else
+ {
+ // convert from whatever this is to 16bit grayscale
+ array2d<dlib::uint16> temp_img;
+ assign_image(temp_img, img_);
+ for (unsigned long i = 0; i < row_pointers.size(); ++i)
+ row_pointers[i] = (unsigned char*)(&temp_img[i][0]);
+
+ impl::impl_save_png(file_name, row_pointers, img.nc(), impl::png_type_gray, 16);
+ }
+ }
+
+
+#endif
+
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ template <
+ typename EXP
+ >
+ void save_png(
+ const matrix_exp<EXP>& img,
+ const std::string& file_name
+ )
+ {
+ array2d<typename EXP::type> temp;
+ assign_image(temp, img);
+ save_png(temp, file_name);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+}
+
+#ifdef NO_MAKEFILE
+#include "save_png.cpp"
+#endif
+
+#endif // DLIB_SAVE_PnG_Hh_
+
diff --git a/ml/dlib/dlib/image_saver/save_png_abstract.h b/ml/dlib/dlib/image_saver/save_png_abstract.h
new file mode 100644
index 000000000..ae495d1f2
--- /dev/null
+++ b/ml/dlib/dlib/image_saver/save_png_abstract.h
@@ -0,0 +1,50 @@
+// Copyright (C) 2011 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#undef DLIB_SAVE_PnG_ABSTRACT_
+#ifdef DLIB_SAVE_PnG_ABSTRACT_
+
+#include "../pixel.h"
+#include "../image_processing/generic_image.h"
+
+namespace dlib
+{
+
+// ----------------------------------------------------------------------------------------
+
+ template <
+ typename image_type
+ >
+ void save_png (
+ const image_type& image,
+ const std::string& file_name
+ );
+ /*!
+ requires
+ - image_type == an image object that implements the interface defined in
+ dlib/image_processing/generic_image.h or a matrix expression
+ - image.size() != 0
+ ensures
+ - writes the image to the file indicated by file_name in the PNG (Portable Network Graphics)
+ format.
+ - image[0][0] will be in the upper left corner of the image.
+ - image[image.nr()-1][image.nc()-1] will be in the lower right
+ corner of the image.
+ - This routine can save images containing any type of pixel. However, save_png() can
+ only natively store the following pixel types: rgb_pixel, rgb_alpha_pixel, uint8,
+ and uint16. All other pixel types will be converted into one of these types as
+ appropriate before being saved to disk.
+ throws
+ - image_save_error
+ This exception is thrown if there is an error that prevents us from saving
+ the image.
+ - std::bad_alloc
+ !*/
+
+// ----------------------------------------------------------------------------------------
+
+}
+
+#endif // DLIB_SAVE_PnG_ABSTRACT_
+
+
+