Wed, 05 Aug 2009 17:10:56 +0100
add README
1 /*
2 #
3 # File : deprecated.h
4 # ( C++ header file - CImg plug-in )
5 #
6 # Description : This CImg plug-in provide functions to load and save jpeg images
7 # directly from/to memory buffers of JOCTET buffers, using the
8 # JPEG library (required to compile !)
9 # This file is a part of the CImg Library project.
10 # ( http://cimg.sourceforge.net )
11 #
12 # Copyright : Paolo Prete
13 # ( p4olo_prete@yahoo.it )
14 #
15 # License : CeCILL v2.0
16 # ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html )
17 #
18 # This software is governed by the CeCILL license under French law and
19 # abiding by the rules of distribution of free software. You can use,
20 # modify and/ or redistribute the software under the terms of the CeCILL
21 # license as circulated by CEA, CNRS and INRIA at the following URL
22 # "http://www.cecill.info".
23 #
24 # As a counterpart to the access to the source code and rights to copy,
25 # modify and redistribute granted by the license, users are provided only
26 # with a limited warranty and the software's author, the holder of the
27 # economic rights, and the successive licensors have only limited
28 # liability.
29 #
30 # In this respect, the user's attention is drawn to the risks associated
31 # with loading, using, modifying and/or developing or reproducing the
32 # software by the user in light of its specific status of free software,
33 # that may mean that it is complicated to manipulate, and that also
34 # therefore means that it is reserved for developers and experienced
35 # professionals having in-depth computer knowledge. Users are therefore
36 # encouraged to load and test the software's suitability as regards their
37 # requirements in conditions enabling the security of their systems and/or
38 # data to be ensured and, more generally, to use and operate it in the
39 # same conditions as regards security.
40 #
41 # The fact that you are presently reading this means that you have had
42 # knowledge of the CeCILL license and that you accept its terms.
43 #
44 */
46 /*-----------------------------------------------------------------------------------
48 IMPORTANT NOTE :
50 You *need* to include the following two lines in your own code to use this plugin :
52 #include <cstdio>
53 #include <jpeglib.h>
54 #include <jerror.h>
56 (see example file provided in examples/jpeg_buffer.cpp).
58 ------------------------------------------------------------------------------------*/
60 ///////////////////////////////////////////////////////////////////////////////////////
61 //
62 // extension of libjpeg (helper functions for loading images from JOCTET arrays)
63 // hacked from
64 // http://www.koders.com/cpp/fidB5A4549ABB5CB01824058F57A43D095D3F95AB40.aspx
65 //
66 ///////////////////////////////////////////////////////////////////////////////////////
68 #define INPUT_BUF_SIZE 4096
70 struct my_source_mem {
71 struct jpeg_source_mgr pub; // Public fields
72 int indexinmem;
73 JOCTET * inmem; // Source stream
74 JOCTET * buffer; // Start of buffer
75 int lenght; // Size of buffer in memory
76 boolean start_of_file; // Have we gotten any data yet?
77 };
79 struct my_source_mgr {
80 struct jpeg_source_mgr pub; // public fields
81 FILE * infile; // source stream
82 JOCTET * buffer; // start of buffer
83 boolean start_of_file; // have we gotten any data yet?
84 };
86 typedef my_source_mem *my_src_mptr;
87 typedef my_source_mgr *my_src_ptr;
89 static boolean fill_minput_buffer(j_decompress_ptr cinfo) {
90 my_src_mptr src = (my_src_mptr) cinfo->src;
91 size_t nbytes;
92 if (src->indexinmem+INPUT_BUF_SIZE>src->lenght) nbytes=src->lenght-src->indexinmem;
93 else nbytes = INPUT_BUF_SIZE;
94 std::memcpy(src->buffer,src->inmem,nbytes);
95 src->inmem += nbytes;
96 src->indexinmem += (int)nbytes;
97 src->pub.next_input_byte = src->buffer;
98 src->pub.bytes_in_buffer = INPUT_BUF_SIZE;
99 src->start_of_file = FALSE;
100 return TRUE;
101 }
103 static void skip_minput_data(j_decompress_ptr cinfo, long num_bytes) {
104 my_src_ptr src = (my_src_ptr)cinfo->src;
105 if (num_bytes > 0) {
106 while (num_bytes > (long) src->pub.bytes_in_buffer) {
107 num_bytes -= (long) src->pub.bytes_in_buffer;
108 fill_minput_buffer(cinfo);
109 // note we assume that fill_input_buffer will never return FALSE,
110 // so suspension need not be handled.
111 //
112 }
113 src->pub.next_input_byte += (size_t) num_bytes;
114 src->pub.bytes_in_buffer -= (size_t) num_bytes;
115 }
116 }
118 static void init_msource(j_decompress_ptr cinfo) {
119 my_src_mptr src = (my_src_mptr)cinfo->src;
120 src->start_of_file = TRUE;
121 }
123 static void term_source(j_decompress_ptr) {
124 // no work necessary here
125 }
127 static void jpeg_mem_src(j_decompress_ptr cinfo, JOCTET * memptr,int lenght) {
128 my_src_mptr src;
130 // The source object and input buffer are made permanent so that a series
131 //of JPEG images can be read from the same file by calling jpeg_stdio_src
132 // only before the first one. (If we discarded the buffer at the end of
133 // one image, we'd likely lose the start of the next one.)
134 // This makes it unsafe to use this manager and a different source
135 // manager serially with the same JPEG object. Caveat programmer.
136 //
138 // first time for this JPEG object?
139 if (cinfo->src == NULL) {
140 cinfo->src = (struct jpeg_source_mgr*)(*cinfo->mem->alloc_small)((j_common_ptr) cinfo, JPOOL_PERMANENT,sizeof(my_source_mem));
141 src = (my_src_mptr) cinfo->src;
142 src->buffer = (JOCTET *)(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,INPUT_BUF_SIZE * sizeof(JOCTET));
143 }
145 src = (my_src_mptr) cinfo->src;
146 src->pub.init_source = init_msource;
147 src->pub.fill_input_buffer = fill_minput_buffer;
148 src->pub.skip_input_data = skip_minput_data;
149 //src->pub.resync_to_restart = jpeg_resync_to_restart; // use default method
150 src->pub.term_source = term_source;
151 src->inmem = memptr;
152 src->indexinmem = 0;
153 src->lenght = lenght;
154 src->pub.bytes_in_buffer = 0; // forces fill_input_buffer on first read
155 src->pub.next_input_byte = NULL; // until buffer loaded
156 }
158 // The following declarations and 5 functions are jpeg related
159 // functions used by put_jpeg_grey_memory and put_jpeg_yuv420p_memory
160 //
161 struct mem_destination_mgr {
162 struct jpeg_destination_mgr pub;
163 JOCTET *buf;
164 size_t bufsize;
165 size_t jpegsize;
166 };
168 typedef mem_destination_mgr *mem_dest_ptr;
170 static void init_destination(j_compress_ptr cinfo) {
171 mem_dest_ptr dest = (mem_dest_ptr) cinfo->dest;
172 dest->pub.next_output_byte = dest->buf;
173 dest->pub.free_in_buffer = dest->bufsize;
174 dest->jpegsize = 0;
175 }
177 static boolean empty_output_buffer(j_compress_ptr cinfo) {
178 mem_dest_ptr dest = (mem_dest_ptr) cinfo->dest;
179 dest->pub.next_output_byte = dest->buf;
180 dest->pub.free_in_buffer = dest->bufsize;
181 return FALSE;
182 ERREXIT(cinfo, JERR_BUFFER_SIZE);
183 }
185 static void term_destination(j_compress_ptr cinfo) {
186 mem_dest_ptr dest = (mem_dest_ptr) cinfo->dest;
187 dest->jpegsize = dest->bufsize - dest->pub.free_in_buffer;
188 }
190 static void jpeg_mem_dest(j_compress_ptr cinfo, JOCTET* buf, size_t bufsize) {
191 mem_dest_ptr dest;
192 if (cinfo->dest == NULL) {
193 cinfo->dest = (struct jpeg_destination_mgr *)
194 (*cinfo->mem->alloc_small)((j_common_ptr)cinfo, JPOOL_PERMANENT,sizeof(mem_destination_mgr));
195 }
196 dest = (mem_dest_ptr) cinfo->dest;
197 dest->pub.init_destination = init_destination;
198 dest->pub.empty_output_buffer = empty_output_buffer;
199 dest->pub.term_destination = term_destination;
200 dest->buf = buf;
201 dest->bufsize = bufsize;
202 dest->jpegsize = 0;
203 }
205 static unsigned jpeg_mem_size(j_compress_ptr cinfo) {
206 mem_dest_ptr dest = (mem_dest_ptr) cinfo->dest;
207 return dest->jpegsize;
208 }
210 /////////////////////////////////////////////////////////////////
211 //
212 // Define main CImg plugin functions.
213 // (you should use these functions only in your own code)
214 //
215 /////////////////////////////////////////////////////////////////
217 //! Load image from a jpeg-coded memory buffer.
218 /**
219 \param buffer Memory buffer containing the jpeg-coded image data.
220 \param buffer_size Size of the memory buffer, in bytes.
221 **/
222 static CImg get_load_jpeg_buffer(const JOCTET *const buffer, const unsigned buffer_size) {
223 struct jpeg_decompress_struct cinfo;
224 struct jpeg_error_mgr jerr;
225 cinfo.err = jpeg_std_error(&jerr);
226 jpeg_create_decompress(&cinfo);
227 jpeg_mem_src(&cinfo, const_cast<JOCTET*>(buffer), buffer_size);
228 jpeg_read_header(&cinfo,TRUE);
229 jpeg_start_decompress(&cinfo);
231 const unsigned int row_stride = cinfo.output_width * cinfo.output_components;
232 JOCTET *buf = new JOCTET[cinfo.output_width*cinfo.output_height*cinfo.output_components];
233 const JOCTET *buf2 = buf;
234 JSAMPROW row_pointer[1];
235 while (cinfo.output_scanline < cinfo.output_height) {
236 row_pointer[0] = buf + cinfo.output_scanline*row_stride;
237 jpeg_read_scanlines(&cinfo,row_pointer,1);
238 }
239 jpeg_finish_decompress(&cinfo);
240 jpeg_destroy_decompress(&cinfo);
242 CImg<T> dest(cinfo.output_width,cinfo.output_height,1,cinfo.output_components);
243 switch (dest.dim) {
244 case 1: {
245 T *ptr_g = dest.ptr(0,0,0,0);
246 cimg_foroff(dest,off) *(ptr_g++) = (T)*(buf2++);
247 } break;
248 case 3: {
249 T
250 *ptr_r = dest.ptr(0,0,0,0),
251 *ptr_g = dest.ptr(0,0,0,1),
252 *ptr_b = dest.ptr(0,0,0,2);
253 cimg_forXY(dest,x,y) {
254 *(ptr_r++) = (T)*(buf2++);
255 *(ptr_g++) = (T)*(buf2++);
256 *(ptr_b++) = (T)*(buf2++);
257 }
258 } break;
259 case 4: {
260 T
261 *ptr_r = dest.ptr(0,0,0,0),
262 *ptr_g = dest.ptr(0,0,0,1),
263 *ptr_b = dest.ptr(0,0,0,2),
264 *ptr_a = dest.ptr(0,0,0,3);
265 cimg_forXY(dest,x,y) {
266 *(ptr_r++) = (T)*(buf2++);
267 *(ptr_g++) = (T)*(buf2++);
268 *(ptr_b++) = (T)*(buf2++);
269 *(ptr_a++) = (T)*(buf2++);
270 }
271 } break;
272 }
273 delete[] buf;
275 return dest;
276 }
278 //! Load image from a jpeg-coded memory buffer (in-place version)
279 /**
280 \param buffer Memory buffer containing the jpeg-coded image data.
281 \param buffer_size Size of the memory buffer, in bytes.
282 **/
283 CImg& load_jpeg_buffer(const JOCTET *const buffer, const unsigned buffer_size) {
284 return get_load_jpeg_buffer(buffer,buffer_size).transfer_to(*this);
285 }
287 //! Save image in a memory buffer, directly as a jpeg-coded file
288 /**
289 \param buffer Memory buffer that will be written with the jpeg-coded image data.
290 \param buffer_size Initial size of the memory buffer. When the function returns, the variable
291 contains the effective length needed to fill the buffer.
292 \param quality Quality of the jpeg compression.
293 **/
294 const CImg& save_jpeg_buffer(JOCTET *const buffer, unsigned int &buffer_size, const int quality=100) const {
296 // Fill pixel buffer
297 JOCTET *buf;
298 unsigned int dimbuf=0;
299 J_COLOR_SPACE colortype=JCS_RGB;
300 switch (dim) {
301 case 1: {
302 // Greyscale images
303 JOCTET *buf2 = buf = new JOCTET[width*height*(dimbuf=1)];
304 const T
305 *ptr_g = ptr();
306 colortype = JCS_GRAYSCALE;
307 cimg_foroff(*this,off) *(buf2++) = (JOCTET)*(ptr_g++);
308 } break;
309 case 2:
310 case 3: {
311 // RGB images
312 JOCTET *buf2 = buf = new JOCTET[width*height*(dimbuf=3)];
313 const T
314 *ptr_r = ptr(0,0,0,0),
315 *ptr_g = ptr(0,0,0,1),
316 *ptr_b = ptr(0,0,0,dim>2?2:0);
317 colortype = JCS_RGB;
318 cimg_forXY(*this,x,y) {
319 *(buf2++) = (JOCTET)*(ptr_r++);
320 *(buf2++) = (JOCTET)*(ptr_g++);
321 *(buf2++) = (JOCTET)*(ptr_b++);
322 }
323 } break;
324 default: {
325 // YCMYK images
326 JOCTET *buf2 = buf = new JOCTET[width*height*(dimbuf=4)];
327 const T
328 *ptr_r = ptr(0,0,0,0),
329 *ptr_g = ptr(0,0,0,1),
330 *ptr_b = ptr(0,0,0,2),
331 *ptr_a = ptr(0,0,0,3);
332 colortype = JCS_CMYK;
333 cimg_forXY(*this,x,y) {
334 *(buf2++) = (JOCTET)*(ptr_r++);
335 *(buf2++) = (JOCTET)*(ptr_g++);
336 *(buf2++) = (JOCTET)*(ptr_b++);
337 *(buf2++) = (JOCTET)*(ptr_a++);
338 }
339 } break;
340 }
342 // Call libjpeg functions
343 struct jpeg_compress_struct cinfo;
344 struct jpeg_error_mgr jerr;
345 cinfo.err = jpeg_std_error(&jerr);
346 jpeg_create_compress(&cinfo);
347 jpeg_mem_dest(&cinfo, buffer, buffer_size);
348 cinfo.image_width = width;
349 cinfo.image_height = height;
350 cinfo.input_components = dimbuf;
351 cinfo.in_color_space = colortype;
352 jpeg_set_defaults(&cinfo);
353 jpeg_set_quality(&cinfo,quality<100?quality:100,TRUE);
354 jpeg_start_compress(&cinfo,TRUE);
356 const unsigned int row_stride = width*dimbuf;
357 JSAMPROW row_pointer[1];
358 while (cinfo.next_scanline < cinfo.image_height) {
359 row_pointer[0] = &buf[cinfo.next_scanline*row_stride];
360 jpeg_write_scanlines(&cinfo,row_pointer,1);
361 }
362 jpeg_finish_compress(&cinfo);
363 delete[] buf;
364 jpeg_destroy_compress(&cinfo);
365 buffer_size = jpeg_mem_size(&cinfo);
366 return *this;
367 }