176 lines
5.5 KiB
C++
176 lines
5.5 KiB
C++
// 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_
|
|
|
|
|
|
|