23 /* |
26 /* |
24 * includes, defines, structure definitions |
27 * includes, defines, structure definitions |
25 * and typedefs come here. |
28 * and typedefs come here. |
26 */ |
29 */ |
27 |
30 |
28 #include <jpeglib.h> |
31 #include <stdio.h> |
29 #include <jerror.h> |
32 |
|
33 #ifndef NO_TESTING |
|
34 # include "../../support/libjpeg-6a/jpeglib.h" |
|
35 # include "../../support/libjpeg-6a/jerror.h" |
|
36 #else |
|
37 # include <jpeglib.h> |
|
38 # include <jerror.h> |
|
39 #endif |
|
40 |
|
41 %} |
|
42 ! ! |
|
43 |
|
44 !JPEGReader primitiveFunctions! |
|
45 %{ |
|
46 |
|
47 /* |
|
48 * any local C (helper) functions |
|
49 * come here (please, define as static) |
|
50 */ |
|
51 |
|
52 /* |
|
53 * Optional progress monitor: display a percent-done figure on stderr. |
|
54 */ |
|
55 |
|
56 #ifdef PROGRESS_REPORT |
|
57 |
|
58 void |
|
59 JPG_progress_monitor (j_common_ptr cinfo) |
|
60 { |
|
61 cd_progress_ptr prog = (cd_progress_ptr) cinfo->progress; |
|
62 int total_passes = prog->pub.total_passes + prog->total_extra_passes; |
|
63 int percent_done = (int) (prog->pub.pass_counter*100L/prog->pub.pass_limit); |
|
64 |
|
65 if (percent_done != prog->percent_done) { |
|
66 prog->percent_done = percent_done; |
|
67 if (total_passes > 1) { |
|
68 fprintf(stderr, "\rPass %d/%d: %3d%% ", |
|
69 prog->pub.completed_passes + prog->completed_extra_passes + 1, |
|
70 total_passes, percent_done); |
|
71 } else { |
|
72 fprintf(stderr, "\r %3d%% ", percent_done); |
|
73 } |
|
74 fflush(stderr); |
|
75 } |
|
76 } |
|
77 |
|
78 |
|
79 void |
|
80 JPG_start_progress_monitor (j_common_ptr cinfo, cd_progress_ptr progress) |
|
81 { |
|
82 /* Enable progress display, unless trace output is on */ |
|
83 if (cinfo->err->trace_level == 0) { |
|
84 progress->pub.progress_monitor = progress_monitor; |
|
85 progress->completed_extra_passes = 0; |
|
86 progress->total_extra_passes = 0; |
|
87 progress->percent_done = -1; |
|
88 cinfo->progress = &progress->pub; |
|
89 } |
|
90 } |
|
91 |
|
92 |
|
93 void |
|
94 JPG_end_progress_monitor (j_common_ptr cinfo) |
|
95 { |
|
96 /* Clear away progress display */ |
|
97 if (cinfo->err->trace_level == 0) { |
|
98 fprintf(stderr, "\r \r"); |
|
99 fflush(stderr); |
|
100 } |
|
101 } |
|
102 |
|
103 #endif |
30 |
104 |
31 %} |
105 %} |
32 ! ! |
106 ! ! |
33 |
107 |
34 !JPEGReader class methodsFor:'documentation'! |
108 !JPEGReader class methodsFor:'documentation'! |
81 Image addReader:self suffix:'jpeg'. |
155 Image addReader:self suffix:'jpeg'. |
82 |
156 |
83 "Modified: 1.2.1997 / 15:01:55 / cg" |
157 "Modified: 1.2.1997 / 15:01:55 / cg" |
84 ! ! |
158 ! ! |
85 |
159 |
86 !JPEGReader class methodsFor:'reading from file'! |
|
87 |
|
88 fromFile:aFileName |
|
89 "read a jpg image from a file. |
|
90 Make it the easy way: let djpeg convert it to gif, |
|
91 then let GIFReader read the file." |
|
92 |
|
93 |tempFileName reader| |
|
94 |
|
95 tempFileName := '/tmp/img' , (OperatingSystem getProcessId printString). |
|
96 |
|
97 'JPEGREADER [info]: converting to ppm ..' infoPrintCR. |
|
98 (OperatingSystem executeCommand:'djpeg -pnm ' , aFileName , ' > ' , tempFileName) |
|
99 ifFalse:[ |
|
100 (OperatingSystem executeCommand:'../../support/libjpeg/djpeg -pnm ' , aFileName , ' > ' , tempFileName) |
|
101 ifFalse:[ |
|
102 'JPEGREADER [warning]: conversion failed ..' errorPrintCR. |
|
103 'JPEGREADER [warning]: .. cannot execute converter: djpeg' errorPrintCR. |
|
104 ^ nil |
|
105 ]. |
|
106 ]. |
|
107 |
|
108 reader := PBMReader fromFile:tempFileName. |
|
109 OperatingSystem executeCommand:'rm ' , tempFileName. |
|
110 ^ reader |
|
111 |
|
112 " |
|
113 JPEGReader fromFile:'bitmaps/testimg.jpg' |
|
114 " |
|
115 |
|
116 "Modified: 11.4.1997 / 16:39:59 / cg" |
|
117 ! ! |
|
118 |
|
119 !JPEGReader class methodsFor:'testing'! |
160 !JPEGReader class methodsFor:'testing'! |
120 |
161 |
121 isValidImageFile:aFileName |
162 isValidImageFile:aFileName |
122 "return true, if aFileName contains a JPG image. |
163 "return true, if aFileName contains a JPG image. |
123 Only look at the files name here ..." |
164 Only look at the files name here ..." |
127 ^ false |
168 ^ false |
128 |
169 |
129 "Created: 11.4.1997 / 16:26:25 / cg" |
170 "Created: 11.4.1997 / 16:26:25 / cg" |
130 ! ! |
171 ! ! |
131 |
172 |
|
173 !JPEGReader methodsFor:'accessing'! |
|
174 |
|
175 forceDitherMode:something |
|
176 "set the dither mode, to one of #none or #ordered" |
|
177 |
|
178 forceDitherMode := something. |
|
179 |
|
180 "Modified: 16.4.1997 / 20:34:59 / cg" |
|
181 ! |
|
182 |
|
183 forceGrayscale:something |
|
184 "set the forceGrayscale mode; if true, grayScale images are |
|
185 returned, even if the input contains a color image." |
|
186 |
|
187 forceGrayscale := something. |
|
188 |
|
189 "Created: 16.4.1997 / 20:33:44 / cg" |
|
190 "Modified: 16.4.1997 / 20:34:29 / cg" |
|
191 ! ! |
|
192 |
|
193 !JPEGReader methodsFor:'private'! |
|
194 |
|
195 create_jpeg_decompress_struct |
|
196 |structSize fp| |
|
197 |
|
198 fp := inStream filePointer. |
|
199 fp isNil ifTrue:[ |
|
200 self error:'can only read from an external stream'. |
|
201 ^ self. |
|
202 ]. |
|
203 |
|
204 %{ |
|
205 structSize = __MKSMALLINT(sizeof(struct jpeg_error_mgr)); |
|
206 %}. |
|
207 |
|
208 jpeg_error_mgr_struct := ExternalBytes unprotectedNew:structSize. |
|
209 |
|
210 %{ |
|
211 structSize = __MKSMALLINT(sizeof(struct jpeg_decompress_struct)); |
|
212 %}. |
|
213 |
|
214 jpeg_decompress_struct := ExternalBytes unprotectedNew:structSize. |
|
215 |
|
216 %{ |
|
217 struct jpeg_decompress_struct *cinfoPtr; |
|
218 struct jpeg_error_mgr *jerrPtr; |
|
219 OBJ j_e_m = __INST(jpeg_error_mgr_struct); |
|
220 OBJ j_d_s = __INST(jpeg_decompress_struct); |
|
221 FILE *f = __FILEVal(fp); |
|
222 |
|
223 if (__isExternalBytes(j_d_s) |
|
224 && __isExternalBytes(j_e_m)) { |
|
225 cinfoPtr = (struct jpeg_decompress_struct *)(__externalBytesAddress(j_d_s)); |
|
226 jerrPtr = (struct jpeg_error_mgr *)(__externalBytesAddress(j_e_m)); |
|
227 |
|
228 /* |
|
229 * Initialize the JPEG decompression object with default error handling. |
|
230 */ |
|
231 cinfoPtr->err = jpeg_std_error(jerrPtr); |
|
232 |
|
233 jpeg_create_decompress(cinfoPtr); |
|
234 #if 0 |
|
235 /* |
|
236 * Insert custom COM marker processor. |
|
237 */ |
|
238 jpeg_set_marker_processor(cinfoPtr, JPEG_COM, COM_handler); |
|
239 #endif |
|
240 cinfoPtr->err->trace_level = 0; |
|
241 |
|
242 #if 0 |
|
243 /* colors setting */ |
|
244 cinfoPtr->desired_number_of_colors = val; |
|
245 cinfoPtr->quantize_colors = TRUE; |
|
246 #endif |
|
247 #if 0 |
|
248 /* dct setting */ |
|
249 cinfoPtr->dct_method = JDCT_ISLOW; |
|
250 or: cinfoPtr->dct_method = JDCT_IFAST; |
|
251 or: cinfoPtr->dct_method = JDCT_FLOAT; |
|
252 #endif |
|
253 |
|
254 /* dither setting */ |
|
255 cinfoPtr->dither_mode = JDITHER_FS; |
|
256 if (__INST(forceDitherMode) == @symbol(none)) { |
|
257 cinfoPtr->dither_mode = JDITHER_NONE; |
|
258 } else { |
|
259 if (__INST(forceDitherMode) == @symbol(ordered)) { |
|
260 cinfoPtr->dither_mode = JDITHER_ORDERED; |
|
261 } |
|
262 } |
|
263 |
|
264 #if 0 |
|
265 /* fast setting */ |
|
266 cinfoPtr->two_pass_quantize = FALSE; |
|
267 cinfoPtr->dither_mode = JDITHER_ORDERED; |
|
268 cinfoPtr->desired_number_of_colors = 216; |
|
269 cinfoPtr->dct_method = JDCT_FASTEST; |
|
270 cinfoPtr->do_fancy_upsampling = FALSE; |
|
271 #endif |
|
272 |
|
273 if (__INST(forceGrayscale) == true) { |
|
274 /* grayscale setting */ |
|
275 cinfoPtr->out_color_space = JCS_GRAYSCALE; |
|
276 } |
|
277 |
|
278 #if 0 |
|
279 /* maxmemory setting */ |
|
280 cinfoPtr->mem->max_memory_to_use = lval * 1000L; |
|
281 #endif |
|
282 #if 0 |
|
283 /* nosmooth setting */ |
|
284 cinfoPtr->do_fancy_upsampling = FALSE; |
|
285 #endif |
|
286 #if 0 |
|
287 /* onepass setting */ |
|
288 cinfoPtr->two_pass_quantize = FALSE; |
|
289 #endif |
|
290 |
|
291 /* Specify data source for decompression */ |
|
292 jpeg_stdio_src(cinfoPtr, f); |
|
293 |
|
294 /* Read file header, set default decompression parameters */ |
|
295 (void) jpeg_read_header(cinfoPtr, TRUE); |
|
296 |
|
297 /* Calculate output image dimensions so we can allocate space */ |
|
298 jpeg_calc_output_dimensions(cinfoPtr); |
|
299 |
|
300 __INST(width) = __MKSMALLINT(cinfoPtr->output_width); |
|
301 __INST(height) = __MKSMALLINT(cinfoPtr->output_height); |
|
302 __INST(colorComponents) = __MKSMALLINT(cinfoPtr->output_components); |
|
303 |
|
304 printf("colorComponents: %d\n", cinfoPtr->output_components); |
|
305 |
|
306 #if 0 |
|
307 /* could now set additional values in cinfo |
|
308 * (colormap) |
|
309 */ |
|
310 #endif |
|
311 } |
|
312 %} |
|
313 |
|
314 ! |
|
315 |
|
316 decompressChunk |
|
317 %{ |
|
318 struct jpeg_decompress_struct *cinfoPtr; |
|
319 char *rgbRow; |
|
320 OBJ j_d_s = __INST(jpeg_decompress_struct); |
|
321 int num_scanlines; |
|
322 JSAMPROW rowPointers[4]; |
|
323 |
|
324 if (__isExternalBytes(j_d_s) |
|
325 && __isByteArray(__INST(decompressBuffer))) { |
|
326 cinfoPtr = (struct jpeg_decompress_struct *)(__externalBytesAddress(j_d_s)); |
|
327 rgbRow = __ByteArrayInstPtr(__INST(decompressBuffer))->ba_element; |
|
328 |
|
329 rowPointers[0] = (JSAMPROW) rgbRow; |
|
330 rowPointers[1] = NULL; |
|
331 rowPointers[2] = NULL; |
|
332 rowPointers[3] = NULL; |
|
333 |
|
334 if (cinfoPtr->output_scanline < cinfoPtr->output_height) { |
|
335 num_scanlines = jpeg_read_scanlines(cinfoPtr, |
|
336 rowPointers, |
|
337 1); |
|
338 RETURN (__MKSMALLINT(num_scanlines)); |
|
339 } |
|
340 RETURN (__MKSMALLINT(0)); |
|
341 } |
|
342 %}. |
|
343 self halt. |
|
344 ! |
|
345 |
|
346 decompressChunkInto:aByteArray startingAt:index |
|
347 %{ |
|
348 struct jpeg_decompress_struct *cinfoPtr; |
|
349 char *rowPtr; |
|
350 OBJ j_d_s = __INST(jpeg_decompress_struct); |
|
351 int num_scanlines; |
|
352 char *rowPointers[4]; |
|
353 |
|
354 if (__isExternalBytes(j_d_s) |
|
355 && __isByteArray(aByteArray)) { |
|
356 cinfoPtr = (struct jpeg_decompress_struct *)(__externalBytesAddress(j_d_s)); |
|
357 rowPtr = (char *)(__ByteArrayInstPtr(aByteArray)->ba_element); |
|
358 rowPtr += __intVal(index) - 1; |
|
359 |
|
360 rowPointers[0] = rowPtr; |
|
361 rowPointers[1] = NULL; |
|
362 rowPointers[2] = NULL; |
|
363 rowPointers[3] = NULL; |
|
364 |
|
365 if (cinfoPtr->output_scanline < cinfoPtr->output_height) { |
|
366 num_scanlines = jpeg_read_scanlines(cinfoPtr, |
|
367 rowPointers, |
|
368 1); |
|
369 RETURN (__MKSMALLINT(num_scanlines)); |
|
370 } |
|
371 RETURN (__MKSMALLINT(0)); |
|
372 } |
|
373 %}. |
|
374 self halt. |
|
375 ! |
|
376 |
|
377 finish_decompress |
|
378 %{ |
|
379 struct jpeg_decompress *cinfoPtr; |
|
380 OBJ j_d_s = __INST(jpeg_decompress_struct); |
|
381 |
|
382 if (__isExternalBytes(j_d_s)) { |
|
383 cinfoPtr = (struct jpeg_decompress *)(__externalBytesAddress(j_d_s)); |
|
384 |
|
385 /* Start decompressor */ |
|
386 (void) jpeg_finish_decompress(cinfoPtr); |
|
387 (void) jpeg_destroy_decompress(cinfoPtr); |
|
388 } |
|
389 %} |
|
390 |
|
391 |
|
392 ! |
|
393 |
|
394 start_decompress |
|
395 decompressBuffer := ByteArray new:(width * colorComponents). |
|
396 |
|
397 %{ |
|
398 struct jpeg_decompress *cinfoPtr; |
|
399 OBJ j_d_s = __INST(jpeg_decompress_struct); |
|
400 |
|
401 if (__isExternalBytes(j_d_s)) { |
|
402 cinfoPtr = (struct jpeg_decompress *)(__externalBytesAddress(j_d_s)); |
|
403 |
|
404 /* Start decompressor */ |
|
405 (void) jpeg_start_decompress(cinfoPtr); |
|
406 } |
|
407 %} |
|
408 ! ! |
|
409 |
|
410 !JPEGReader methodsFor:'reading from stream'! |
|
411 |
|
412 fromStream:aStream |
|
413 "read a JPG image from a stream" |
|
414 |
|
415 |dataIdx bytesPerRow| |
|
416 |
|
417 inStream := aStream. |
|
418 |
|
419 self create_jpeg_decompress_struct. |
|
420 self start_decompress. |
|
421 |
|
422 data := ByteArray uninitializedNew:(width * height * colorComponents). |
|
423 dataIdx := 1. |
|
424 bytesPerRow := colorComponents * width. |
|
425 |
|
426 [(self decompressChunkInto:data startingAt:dataIdx) ~~ 0] whileTrue:[ |
|
427 "/ got a row in the buffer ... |
|
428 dataIdx := dataIdx + bytesPerRow |
|
429 ]. |
|
430 |
|
431 self finish_decompress. |
|
432 |
|
433 colorComponents == 3 ifTrue:[ |
|
434 photometric := #rgb. |
|
435 samplesPerPixel := 3. |
|
436 bitsPerSample := #(8 8 8). |
|
437 ] ifFalse:[ |
|
438 self halt:'unexpected value' |
|
439 ]. |
|
440 |
|
441 " |
|
442 JPEGReader fromFile:'../../support/libjpeg-6a/testimg.jpg' |
|
443 " |
|
444 " |
|
445 |stream reader| |
|
446 |
|
447 stream := '../../support/libjpeg-6a/testimg.jpg' asFilename readStream. |
|
448 reader := JPEGReader new. |
|
449 reader forceGrayscale:true. |
|
450 reader forceDitherMode:#ordered. |
|
451 reader fromStream:stream. |
|
452 ^ reader image |
|
453 " |
|
454 |
|
455 "Modified: 16.4.1997 / 20:36:12 / cg" |
|
456 ! ! |
|
457 |
132 !JPEGReader class methodsFor:'documentation'! |
458 !JPEGReader class methodsFor:'documentation'! |
133 |
459 |
134 version |
460 version |
135 ^ '$Header: /cvs/stx/stx/libview2/JPEGReader.st,v 1.19 1997-04-11 14:44:54 cg Exp $' |
461 ^ '$Header: /cvs/stx/stx/libview2/JPEGReader.st,v 1.20 1997-04-16 20:11:53 cg Exp $' |
136 ! ! |
462 ! ! |
137 JPEGReader initialize! |
463 JPEGReader initialize! |