Write jpeg with header comment – boost generic image library (gil)
I had to hack the living daylights out of something today, and although I am not proud of it, needs must where the devil drives!
I was using the boost generic image library (gil) for managing some camera images and using jpeg_write_view() for saving them as JPEGs. A requirement emerged to insert a comment into the header of the saved images, but the gil does not support this out of the box.
The gil uses libjpeg for writing its JPEGs and adding a comment in libjped is as easy as calling jpeg_write_marker(). The problem was that the gil buries libjpeg calls under a few classes so I had to copy and paste some of this in order to redefine a new writer which supports comments.
Anyway I have included the extra code inline below, it adds a new helper function called jpeg_write_view_comment()
Use this new function like this:
1 2 | int quality = 70; jpeg_write_view_comment("image1.jpg", view, quality, "a comment damn it!!!"); |
Here is the extra code which I placed in a file called jpeg_writer_comment.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | #pragma once #include "boost/gil/extension/io/dynamic_io.hpp" using namespace boost; using namespace boost::gil; using namespace boost::gil::detail; class jpeg_writer_comment : public file_mgr { jpeg_compress_struct _cinfo; jpeg_error_mgr _jerr; void init() { _cinfo.err=jpeg_std_error(&_jerr); jpeg_create_compress(&_cinfo); jpeg_stdio_dest(&_cinfo,_fp.get()); } public: jpeg_writer_comment(FILE* file) : file_mgr(file) { init(); } jpeg_writer_comment(const char* filename) : file_mgr(filename, "wb") { init(); } ~jpeg_writer_comment() { jpeg_destroy_compress(&_cinfo); } template <typename View> void apply(const View& view,int quality=100, const char* comment = NULL) { _cinfo.image_width = (JDIMENSION)view.width(); _cinfo.image_height = (JDIMENSION)view.height(); _cinfo.input_components=num_channels<View>::value; _cinfo.in_color_space = jpeg_write_support_private<typename channel_type<View>::type, typename color_space_type<View>::type>::color_type; jpeg_set_defaults(&_cinfo); jpeg_set_quality(&_cinfo, quality, TRUE); jpeg_start_compress(&_cinfo, TRUE); if (comment) { jpeg_write_marker(&_cinfo, JPEG_COM, (const JOCTET*)comment, strlen(comment)); } std::vector<pixel<bits8,layout<typename color_space_type<View>::type> > > row(view.width()); JSAMPLE* row_address=(JSAMPLE*)&row.front(); for (int y=0;y<view.height(); ++y) { std::copy(view.row_begin(y),view.row_end(y),row.begin()); io_error_if(jpeg_write_scanlines(&_cinfo,(JSAMPARRAY)&row_address,1) != 1, "jpeg_writer::apply(): fail to write file"); } jpeg_finish_compress(&_cinfo); } }; class jpeg_writer_dynamic_comment : public jpeg_writer_comment { int _quality; public: jpeg_writer_dynamic_comment(FILE* file, int quality=100) : jpeg_writer_comment(file) , _quality(quality) {} jpeg_writer_dynamic_comment(const char* filename, int quality=100) : jpeg_writer_comment(filename), _quality(quality) {} template <typename Views> void write_view(const any_image_view<Views>& runtime_view) { dynamic_io_fnobj<jpeg_write_is_supported, jpeg_writer_comment> op(this); apply_operation(runtime_view,op); } }; template <typename View> inline void jpeg_write_view_comment(const char* filename,const View& view,int quality=100, const char* comment = NULL) { BOOST_STATIC_ASSERT(jpeg_write_support<View>::is_supported); jpeg_writer_comment m(filename); m.apply(view, quality, comment); } |