1
/***********************************************************************/
5
/* Fran�ois Pessaux, projet Cristal, INRIA Rocquencourt */
6
/* Pierre Weis, projet Cristal, INRIA Rocquencourt */
7
/* Jun Furuse, projet Cristal, INRIA Rocquencourt */
9
/* Copyright 1999,2000 */
10
/* Institut National de Recherche en Informatique et en Automatique. */
11
/* Distributed only by permission. */
13
/***********************************************************************/
18
#include <caml/mlvalues.h>
19
#include <caml/alloc.h>
20
#include <caml/memory.h>
21
#include <caml/fail.h>
27
* Include file for users of JPEG library.
28
* You will need to have included system headers that define at least
29
* the typedefs FILE and size_t before you can include jpeglib.h.
30
* (stdio.h is sufficient on ANSI-conforming systems.)
31
* You may also wish to include "jerror.h".
37
* Sample routine for JPEG compression. We assume that the target file name
38
* and a compression quality factor are passed in.
41
extern char jpg_error_message[JMSG_LENGTH_MAX];
43
struct jpeg_error_mgr pub; /* "public" fields */
45
jmp_buf setjmp_buffer; /* for return to caller */
47
typedef struct my_error_mgr * my_error_ptr;
48
extern void my_error_exit (j_common_ptr);
51
write_JPEG_file (value file,
57
JSAMPLE *image_buffer;
63
/* This struct contains the JPEG compression parameters and pointers to
64
* working space (which is allocated as needed by the JPEG library).
65
* It is possible to have several such structures, representing multiple
66
* compression/decompression processes, in existence at once. We refer
67
* to any one struct (and its associated working data) as a "JPEG object".
69
struct jpeg_compress_struct cinfo;
70
/* This struct represents a JPEG error handler. It is declared separately
71
* because applications often want to supply a specialized error handler
72
* (see the second half of this file for an example). But here we just
73
* take the easy way out and use the standard error handler, which will
74
* print a message on stderr and call exit() if compression fails.
75
* Note that this struct must live as long as the main JPEG parameter
76
* struct, to avoid dangling-pointer problems.
78
struct jpeg_error_mgr jerr;
80
FILE * outfile; /* target file */
81
JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */
82
int row_stride; /* physical row width in image buffer */
84
image_buffer = String_val(buffer);
85
image_width = Int_val(width);
86
image_height = Int_val(height);
87
filename = String_val(file);
88
quality= Int_val(qual);
90
/* Step 1: allocate and initialize JPEG compression object */
92
/* We have to set up the error handler first, in case the initialization
93
* step fails. (Unlikely, but it could happen if you are out of memory.)
94
* This routine fills in the contents of struct jerr, and returns jerr's
95
* address which we place into the link field in cinfo.
97
cinfo.err = jpeg_std_error(&jerr);
98
/* Now we can initialize the JPEG compression object. */
99
jpeg_create_compress(&cinfo);
101
/* Step 2: specify data destination (eg, a file) */
102
/* Note: steps 2 and 3 can be done in either order. */
104
/* Here we use the library-supplied code to send compressed data to a
105
* stdio stream. You can also write your own code to do something else.
106
* VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
107
* requires it in order to write binary files.
109
if ((outfile = fopen(filename, "wb")) == NULL) {
110
failwith ("can't open %s\n");
112
jpeg_stdio_dest(&cinfo, outfile);
114
/* Step 3: set parameters for compression */
116
/* First we supply a description of the input image.
117
* Four fields of the cinfo struct must be filled in:
119
cinfo.image_width = image_width; /* image width and height, in pixels */
120
cinfo.image_height = image_height;
121
cinfo.input_components = 3; /* # of color components per pixel */
122
cinfo.in_color_space = JCS_RGB; /* colorspace of input image */
123
/* Now use the library's routine to set default compression parameters.
124
* (You must set at least cinfo.in_color_space before calling this,
125
* since the defaults depend on the source color space.)
127
jpeg_set_defaults(&cinfo);
128
/* Now you can set any non-default parameters you wish to.
129
* Here we just illustrate the use of quality (quantization table) scaling:
131
jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);
133
/* Step 4: Start compressor */
135
/* TRUE ensures that we will write a complete interchange-JPEG file.
136
* Pass TRUE unless you are very sure of what you're doing.
138
jpeg_start_compress(&cinfo, TRUE);
140
/* Step 5: while (scan lines remain to be written) */
141
/* jpeg_write_scanlines(...); */
143
/* Here we use the library's state variable cinfo.next_scanline as the
144
* loop counter, so that we don't have to keep track ourselves.
145
* To keep things simple, we pass one scanline per call; you can pass
146
* more if you wish, though.
148
row_stride = image_width * 3; /* JSAMPLEs per row in image_buffer */
150
while (cinfo.next_scanline < cinfo.image_height) {
151
/* jpeg_write_scanlines expects an array of pointers to scanlines.
152
* Here the array is only one element long, but you could pass
153
* more than one scanline at a time if that's more convenient.
155
row_pointer[0] = & image_buffer[cinfo.next_scanline * row_stride];
156
(void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
159
/* Step 6: Finish compression */
161
jpeg_finish_compress(&cinfo);
162
/* After finish_compress, we can close the output file. */
165
/* Step 7: release JPEG compression object */
167
/* This is an important step since it will release a good deal of memory. */
168
jpeg_destroy_compress(&cinfo);
170
/* And we're done! */
178
* In the above loop, we ignored the return value of jpeg_write_scanlines,
179
* which is the number of scanlines actually written. We could get away
180
* with this because we were only relying on the value of cinfo.next_scanline,
181
* which will be incremented correctly. If you maintain additional loop
182
* variables then you should be careful to increment them properly.
183
* Actually, for output to a stdio stream you needn't worry, because
184
* then jpeg_write_scanlines will write all the lines passed (or else exit
185
* with a fatal error). Partial writes can only occur if you use a data
186
* destination module that can demand suspension of the compressor.
187
* (If you don't know what that's for, you don't need it.)
189
* If the compressor requires full-image buffers (for entropy-coding
190
* optimization or a multi-scan JPEG file), it will create temporary
191
* files for anything that doesn't fit within the maximum-memory setting.
192
* (Note that temp files are NOT needed if you use the default parameters.)
193
* On some systems you may need to set up a signal handler to ensure that
194
* temporary files are deleted if the program is interrupted. See libjpeg.doc.
196
* Scanlines MUST be supplied in top-to-bottom order if you want your JPEG
197
* files to be compatible with everyone else's. If you cannot readily read
198
* your data in that order, you'll need an intermediate array to hold the
199
* image. See rdtarga.c or rdbmp.c for examples of handling bottom-to-top
200
* source data using the JPEG code's internal virtual-array mechanisms.
203
value open_jpeg_file_for_write_colorspace( name, width, height, qual, colorspace )
208
J_COLOR_SPACE colorspace;
215
struct jpeg_compress_struct* cinfop;
216
struct my_error_mgr *jerrp;
218
FILE * outfile; /* source file */
221
image_width= Int_val( width );
222
image_height= Int_val( height );
223
filename= String_val( name );
224
quality= Int_val(qual);
226
if ((outfile = fopen(filename, "wb")) == NULL) {
227
failwith("failed to open jpeg file");
230
cinfop = malloc(sizeof (struct jpeg_compress_struct));
231
jerrp = malloc(sizeof (struct my_error_mgr));
232
cinfop->err = jpeg_std_error(&jerrp->pub);
233
jerrp->pub.error_exit = my_error_exit;
235
if (setjmp(jerrp->setjmp_buffer)) {
236
/* If we get here, the JPEG code has signaled an error.
237
* We need to clean up the JPEG object, close the input file, and return.
239
jpeg_destroy_compress(cinfop);
242
failwith(jpg_error_message);
245
jpeg_create_compress(cinfop);
246
jpeg_stdio_dest(cinfop, outfile);
248
cinfop->image_width= image_width;
249
cinfop->image_height= image_height;
250
cinfop->input_components = (colorspace == JCS_RGB ? 3 : 4);
251
cinfop->in_color_space= colorspace /* JCS_RGB or JCS_CMYK */;
252
jpeg_set_defaults(cinfop);
253
jpeg_set_quality(cinfop, quality, TRUE);
254
jpeg_start_compress(cinfop, TRUE);
257
res = alloc_tuple(3);
258
Field(res, 0) = (value)cinfop;
259
Field(res, 1) = (value)outfile;
260
Field(res, 2) = (value)jerrp;
263
fprintf(stderr, "cinfop= %d outfile= %d %d %d \n", cinfop, infile, cinfop->output_scanline, cinfop->output_height);
269
value open_jpeg_file_for_write( name, width, height, qual )
276
open_jpeg_file_for_write_colorspace( name, width, height, qual, JCS_RGB );
279
value open_jpeg_file_for_write_cmyk( name, width, height, qual )
286
open_jpeg_file_for_write_colorspace( name, width, height, qual, JCS_CMYK );
289
value write_jpeg_scanline( jpegh, buf )
292
struct jpeg_compress_struct *cinfop;
295
cinfop = (struct jpeg_compress_struct *) Field( jpegh, 0 );
297
row[0] = String_val( buf );
299
jpeg_write_scanlines( cinfop, row, 1 );
303
value close_jpeg_file_for_write( jpegh )
306
struct jpeg_compress_struct *cinfop;
307
struct my_error_mgr *jerrp;
311
fprintf(stderr, "closing\n");
315
cinfop = (struct jpeg_compress_struct *) Field( jpegh, 0 );
316
outfile = (FILE *) Field( jpegh, 1 );
317
jerrp = (struct my_error_mgr *) Field( jpegh, 2 );
320
fprintf(stderr, "cinfop= %d outfile= %d %d %d \n", cinfop, outfile, cinfop->next_scanline, cinfop->image_height);
323
if( cinfop->next_scanline >= cinfop->image_height ){
325
fprintf(stderr, "finish\n");
328
jpeg_finish_compress( cinfop );
331
fprintf(stderr, "destroy\n");
334
jpeg_destroy_compress( cinfop );
339
fprintf(stderr, "file close\n");