Merge evaluate() functionnality into find_edges(), get delta for missed edges.
[goir.git] / sImLib / Image.cc
blob2d09a04d86d2fdd86896e812033c206c77060a6b
1 #include "Image.hh"
2 #include "img_path.hh"
4 #include <cassert>
5 #include <cstdio>
6 #include <cstdlib>
7 #include <cstring>
8 #include <cerrno>
10 #include <fcntl.h>
11 #include <unistd.h>
12 // for random
13 #include <sys/time.h>
15 #include <png.h>
16 #include <jpeglib.h>
17 #if 0
18 // libjpeg needs it, but libpng wants to do the include itself
19 #include <setjmp.h>
20 #endif
22 // the class' methods themselves...
23 namespace sImLib {
25 // forward decls for implementation
26 static int read_JPEG_file (const char * filename,
27 pixel** outbufferp,
28 unsigned* widthp, unsigned* heightp);
29 static void write_JPEG_file (int fd, const pixel *const buffer,
30 unsigned width, unsigned height,
31 int quality);
32 static int write_PNG_file(int fd, const sImLib::Image * const imgp,
33 bool quick);
35 Image::Image(const std::string & _filename)
36 : filename(_filename) {
37 if (!read_JPEG_file(filename.c_str(), &data, &width, &height)) {
38 fprintf(stderr, "cannot read jpeg file\n");
39 exit(1);
42 // see rng for empfile creation
43 struct timeval tv;
44 if (gettimeofday(&tv, NULL) < 0) {
45 fprintf(stderr, "cannot read time to seed rng: %s\n", strerror(errno));
46 exit(1);
48 srandom(tv.tv_sec);
51 Image::Image(const Image& image)
52 : width(image.width)
53 , height(image.height)
54 , filename(image.filename) {
55 unsigned size = width * height * sizeof(pixel);
56 data = (pixel*)malloc(size);
57 memcpy(data, image.data, size);
60 Image::~Image() {
61 free(data);
64 int Image::write_jpeg(const std::string & out_filename, int quality) const {
65 int fd = open(out_filename.c_str(), O_WRONLY|O_CREAT,
66 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
67 if (fd < 0) {
68 fprintf(stderr, "can't open %s: %s\n", out_filename.c_str(), strerror(errno));
69 exit(1);
71 this->write_jpeg(fd, quality);
72 return 1; // FIXME
75 int Image::write_jpeg(int fd, int quality) const {
76 write_JPEG_file(fd, data, width, height, quality);
77 return 1; // FIXME
80 int Image::write_png(const std::string & out_filename, bool quick) const {
81 int fd = open(out_filename.c_str(), O_WRONLY|O_CREAT,
82 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
83 if (fd < 0) {
84 fprintf(stderr, "can't open %s: %s\n", out_filename.c_str(), strerror(errno));
85 exit(1);
87 return this->write_png(fd, quick);
90 int Image::write_png(int fd, bool quick) const {
91 return write_PNG_file(fd, this, quick);
94 void Image::display() const {
95 // Write to temporary image file
96 const char pattern[] = "/tmp/goir-tmp%05lu.png";
97 char tmpname[sizeof(pattern) + 1];
98 sprintf(tmpname, pattern, random() % 100000);
99 int tmpfd = open(tmpname, O_WRONLY|O_CREAT,
100 O_EXCL|S_IRUSR|S_IWUSR);
101 this->write_png(tmpfd, true);
103 // display using imagemagick
104 const char cmdname[]="gm display";
105 char cmd[sizeof(pattern) + sizeof(cmdname) + 2];
106 snprintf(cmd, sizeof(cmd), "%s %s", cmdname, tmpname);
107 system(cmd);
109 //cleanup
110 close(tmpfd);
111 unlink(tmpname);
114 void Image::draw_line(const int x0, const int y0, const int x1, const int y1,
115 const pixel& color, const float opacity) {
116 assert (opacity >= 0.0 && opacity <= 1.0);
117 if (opacity == 1.0)
118 sImLib_forline(this, ptrd, x0, y0, x1, y1, memcpy(ptrd, &color, 3) );
119 else {
120 const float copacity = 1.0 - opacity;
121 const float scaled_color[3] = { color[0]*opacity,
122 color[1]*opacity,
123 color[2]*opacity };
124 sImLib_forline(this, ptrd, x0, y0, x1, y1,
125 for (unsigned k=0; k<3; k++)
126 (*ptrd)[k] = (component)(scaled_color[k] + copacity * *(ptrd)[k]);
131 //////////////////////////////////////////////////
132 // Code mostly stolen from libjpeg's own example.
135 * Sample routine for JPEG compression. We assume that the target file name
136 * and a compression quality factor are passed in.
139 static void write_JPEG_file (int fd, const pixel *const buffer,
140 unsigned width, unsigned height,
141 int quality)
143 /* This struct contains the JPEG compression parameters and pointers to
144 * working space (which is allocated as needed by the JPEG library).
145 * It is possible to have several such structures, representing multiple
146 * compression/decompression processes, in existence at once. We refer
147 * to any one struct (and its associated working data) as a "JPEG object".
149 struct jpeg_compress_struct cinfo;
150 /* This struct represents a JPEG error handler. It is declared separately
151 * because applications often want to supply a specialized error handler
152 * (see the second half of this file for an example). But here we just
153 * take the easy way out and use the standard error handler, which will
154 * print a message on stderr and call exit() if compression fails.
155 * Note that this struct must live as long as the main JPEG parameter
156 * struct, to avoid dangling-pointer problems.
158 struct jpeg_error_mgr jerr;
159 /* More stuff */
160 FILE * outfile; /* target file */
161 JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */
163 /* Step 1: allocate and initialize JPEG compression object */
165 /* We have to set up the error handler first, in case the initialization
166 * step fails. (Unlikely, but it could happen if you are out of memory.)
167 * This routine fills in the contents of struct jerr, and returns jerr's
168 * address which we place into the link field in cinfo.
170 cinfo.err = jpeg_std_error(&jerr);
171 /* Now we can initialize the JPEG compression object. */
172 jpeg_create_compress(&cinfo);
174 /* Step 2: specify data destination (eg, a file) */
175 /* Note: steps 2 and 3 can be done in either order. */
177 /* Here we use the library-supplied code to send compressed data to a
178 * stdio stream. You can also write your own code to do something else.
179 * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
180 * requires it in order to write binary files.
182 if ((outfile = fdopen(fd, "wb")) == NULL) {
183 fprintf(stderr, "can't fdopen %d: %s\n", fd, strerror(errno));
184 exit(1);
186 jpeg_stdio_dest(&cinfo, outfile);
188 /* Step 3: set parameters for compression */
190 /* First we supply a description of the input image.
191 * Four fields of the cinfo struct must be filled in:
193 cinfo.image_width = width; /* image width and height, in pixels */
194 cinfo.image_height = height;
195 cinfo.input_components = 3; /* # of color components per pixel */
196 cinfo.in_color_space = JCS_RGB; /* colorspace of input image */
197 /* Now use the library's routine to set default compression parameters.
198 * (You must set at least cinfo.in_color_space before calling this,
199 * since the defaults depend on the source color space.)
201 jpeg_set_defaults(&cinfo);
202 /* Now you can set any non-default parameters you wish to.
203 * Here we just illustrate the use of quality (quantization table) scaling:
205 jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);
207 /* Step 4: Start compressor */
209 /* TRUE ensures that we will write a complete interchange-JPEG file.
210 * Pass TRUE unless you are very sure of what you're doing.
212 jpeg_start_compress(&cinfo, TRUE);
214 /* Step 5: while (scan lines remain to be written) */
215 /* jpeg_write_scanlines(...); */
217 /* Here we use the library's state variable cinfo.next_scanline as the
218 * loop counter, so that we don't have to keep track ourselves.
219 * To keep things simple, we pass one scanline per call; you can pass
220 * more if you wish, though.
222 while (cinfo.next_scanline < cinfo.image_height) {
223 /* jpeg_write_scanlines expects an array of pointers to scanlines.
224 * Here the array is only one element long, but you could pass
225 * more than one scanline at a time if that's more convenient.
227 row_pointer[0] = (JSAMPLE*) & buffer[cinfo.next_scanline * width];
228 (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
231 /* Step 6: Finish compression */
233 jpeg_finish_compress(&cinfo);
234 /* After finish_compress, we can close the output file. */
235 fclose(outfile);
237 /* Step 7: release JPEG compression object */
239 /* This is an important step since it will release a good deal of memory. */
240 jpeg_destroy_compress(&cinfo);
242 /* And we're done! */
247 * ERROR HANDLING:
249 * The JPEG library's standard error handler (jerror.c) is divided into
250 * several "methods" which you can override individually. This lets you
251 * adjust the behavior without duplicating a lot of code, which you might
252 * have to update with each future release.
254 * Our example here shows how to override the "error_exit" method so that
255 * control is returned to the library's caller when a fatal error occurs,
256 * rather than calling exit() as the standard error_exit method does.
258 * We use C's setjmp/longjmp facility to return control. This means that the
259 * routine which calls the JPEG library must first execute a setjmp() call to
260 * establish the return point. We want the replacement error_exit to do a
261 * longjmp(). But we need to make the setjmp buffer accessible to the
262 * error_exit routine. To do this, we make a private extension of the
263 * standard JPEG error handler object. (If we were using C++, we'd say we
264 * were making a subclass of the regular error handler.)
266 * Here's the extended error handler struct:
269 struct my_error_mgr {
270 struct jpeg_error_mgr pub; /* "public" fields */
272 jmp_buf setjmp_buffer; /* for return to caller */
275 typedef struct my_error_mgr * my_error_ptr;
278 * Here's the routine that will replace the standard error_exit method:
281 METHODDEF(void)
282 my_error_exit (j_common_ptr cinfo)
284 /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
285 my_error_ptr myerr = (my_error_ptr) cinfo->err;
287 /* Always display the message. */
288 /* We could postpone this until after returning, if we chose. */
289 (*cinfo->err->output_message) (cinfo);
291 /* Return control to the setjmp point */
292 longjmp(myerr->setjmp_buffer, 1);
297 * Sample routine for JPEG decompression. We assume that the source file name
298 * is passed in. We want to return 1 on success, 0 on error.
300 static int read_JPEG_file (const char * filename, pixel** outbufferp,
301 unsigned* widthp, unsigned* heightp)
303 /* This struct contains the JPEG decompression parameters and pointers to
304 * working space (which is allocated as needed by the JPEG library).
306 struct jpeg_decompress_struct cinfo;
307 /* We use our private extension JPEG error handler.
308 * Note that this struct must live as long as the main JPEG parameter
309 * struct, to avoid dangling-pointer problems.
311 struct my_error_mgr jerr;
312 /* More stuff */
313 FILE * infile; /* source file */
314 JSAMPARRAY buffer; /* Output row buffer */
315 int row_stride; /* physical row width in output buffer */
316 pixel* buffer_lineptr;
318 /* In this example we want to open the input file before doing anything else,
319 * so that the setjmp() error recovery below can assume the file is open.
320 * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
321 * requires it in order to read binary files.
324 if ((infile = fopen(filename, "rb")) == NULL) {
325 fprintf(stderr, "can't open %s\n", filename);
326 return 0;
329 /* Step 1: allocate and initialize JPEG decompression object */
331 /* We set up the normal JPEG error routines, then override error_exit. */
332 cinfo.err = jpeg_std_error(&jerr.pub);
333 jerr.pub.error_exit = my_error_exit;
334 /* Establish the setjmp return context for my_error_exit to use. */
335 if (setjmp(jerr.setjmp_buffer)) {
336 /* If we get here, the JPEG code has signaled an error.
337 * We need to clean up the JPEG object, close the input file, and return.
339 jpeg_destroy_decompress(&cinfo);
340 fclose(infile);
341 return 0;
343 /* Now we can initialize the JPEG decompression object. */
344 jpeg_create_decompress(&cinfo);
345 /* Step 2: specify data source (eg, a file) */
347 jpeg_stdio_src(&cinfo, infile);
349 /* Step 3: read file parameters with jpeg_read_header() */
351 (void) jpeg_read_header(&cinfo, TRUE);
352 /* We can ignore the return value from jpeg_read_header since
353 * (a) suspension is not possible with the stdio data source, and
354 * (b) we passed TRUE to reject a tables-only JPEG file as an error.
355 * See libjpeg.doc for more info.
358 /* Step 4: set parameters for decompression */
360 /* In this example, we don't need to change any of the defaults set by
361 * jpeg_read_header(), so we do nothing here.
364 /* Step 5: Start decompressor */
366 (void) jpeg_start_decompress(&cinfo);
367 /* We can ignore the return value since suspension is not possible
368 * with the stdio data source.
371 /* We may need to do some setup of our own at this point before reading
372 * the data. After jpeg_start_decompress() we have the correct scaled
373 * output image dimensions available, as well as the output colormap
374 * if we asked for color quantization.
375 * In this example, we need to make an output work buffer of the right size.
377 *widthp = cinfo.output_width;
378 *heightp = cinfo.output_height;
379 assert (cinfo.output_components == 3); // FIXME: lacks support for greyscale
380 assert (sizeof(pixel) == 3);
381 *outbufferp = (pixel*)malloc(cinfo.output_width * cinfo.output_height *
382 sizeof(pixel));
383 buffer_lineptr = *outbufferp;
385 /* JSAMPLEs per row in output buffer */
386 row_stride = cinfo.output_width * cinfo.output_components;
387 /* Make a one-row-high sample array that will go away when done with image */
388 buffer = (*cinfo.mem->alloc_sarray)
389 ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
391 /* Step 6: while (scan lines remain to be read) */
392 /* jpeg_read_scanlines(...); */
394 /* Here we use the library's state variable cinfo.output_scanline as the
395 * loop counter, so that we don't have to keep track ourselves.
397 while (cinfo.output_scanline < cinfo.output_height) {
398 /* jpeg_read_scanlines expects an array of pointers to scanlines.
399 * Here the array is only one element long, but you could ask for
400 * more than one scanline at a time if that's more convenient.
402 (void) jpeg_read_scanlines(&cinfo, buffer, 1);
403 /* Copy into our own buffer */
404 memcpy(buffer_lineptr, buffer[0], row_stride);
405 buffer_lineptr += cinfo.output_width;
408 /* Step 7: Finish decompression */
410 (void) jpeg_finish_decompress(&cinfo);
411 /* We can ignore the return value since suspension is not possible
412 * with the stdio data source.
415 /* Step 8: Release JPEG decompression object */
417 /* This is an important step since it will release a good deal of memory. */
418 jpeg_destroy_decompress(&cinfo);
420 /* After finish_decompress, we can close the input file.
421 * Here we postpone it until after no more JPEG errors are possible,
422 * so as to simplify the setjmp error logic above. (Actually, I don't
423 * think that jpeg_destroy can do an error exit, but why assume anything...)
425 fclose(infile);
427 /* At this point you may want to check to see whether any corrupt-data
428 * warnings occurred (test whether jerr.pub.num_warnings is nonzero).
431 /* And we're done! */
432 return 1;
436 ///////////////////////////////////////////////////////////////
437 // Code mostly stolen from libpng's public-domain own example.
439 /* write a png file */
440 static int write_PNG_file(int fd, const sImLib::Image * const imgp,
441 bool quick)
443 FILE *fp;
444 png_structp png_ptr;
445 png_infop info_ptr;
447 /* open the file */
448 fp = fdopen(fd, "wb");
449 if (fp == NULL)
450 return (-1);
452 /* Create and initialize the png_struct with the desired error handler
453 * functions. If you want to use the default stderr and longjump method,
454 * you can supply NULL for the last three parameters. We also check that
455 * the library version is compatible with the one used at compile time,
456 * in case we are using dynamically linked libraries. REQUIRED.
458 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
459 png_voidp_NULL,
460 png_error_ptr_NULL,
461 png_error_ptr_NULL);
463 if (png_ptr == NULL)
465 fclose(fp);
466 return (-1);
469 /* Allocate/initialize the image information data. REQUIRED */
470 info_ptr = png_create_info_struct(png_ptr);
471 if (info_ptr == NULL)
473 fclose(fp);
474 png_destroy_write_struct(&png_ptr, png_infopp_NULL);
475 return (-1);
478 /* Set error handling. REQUIRED if you aren't supplying your own
479 * error handling functions in the png_create_write_struct() call.
481 if (setjmp(png_jmpbuf(png_ptr)))
483 /* If we get here, we had a problem reading the file */
484 fclose(fp);
485 // FIXME: should copy cleanup calls from end of function here ?
486 png_destroy_write_struct(&png_ptr, &info_ptr);
487 return (-1);
490 /* Fill in image info */
491 png_set_IHDR(png_ptr, info_ptr, imgp->width, imgp->height, 8,
492 PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
493 PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
495 if (quick) {
496 png_set_compression_level(png_ptr, 1);
497 png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, PNG_FILTER_NONE);
500 /* Image data */
501 png_bytep* row_pointers =
502 (png_bytep*)png_malloc(png_ptr, imgp->height*png_sizeof(png_bytep));
503 for (unsigned i=0; i<imgp->height; i++)
504 row_pointers[i] = (png_bytep)imgp->ptr(0,i);
505 png_set_rows(png_ptr, info_ptr, row_pointers);
507 /* set up the output control if you are using standard C streams */
508 png_init_io(png_ptr, fp);
510 /* This is the easy way. Use it if you already have all the
511 * image info living info in the structure. You could "|" many
512 * PNG_TRANSFORM flags into the png_transforms integer here.
514 png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, png_voidp_NULL);
516 /* clean up after the write, and free any memory allocated */
517 png_free(png_ptr, row_pointers);
518 png_destroy_info_struct(png_ptr, &info_ptr);
519 png_destroy_write_struct(&png_ptr, &info_ptr);
521 /* close the file */
522 fclose(fp);
524 /* that's it */
525 return (0);