diff -r 822b6d67ea95 -r 8946f8362c63 JPEGReader.st --- a/JPEGReader.st Wed Feb 17 17:31:16 2016 +0100 +++ b/JPEGReader.st Thu Feb 18 13:46:54 2016 +0100 @@ -1,3 +1,5 @@ +"{ Encoding: utf8 }" + " COPYRIGHT (c) 1993 by Claus Gittinger All Rights Reserved @@ -11,9 +13,12 @@ " "{ Package: 'stx:libview2' }" +"{ NameSpace: Smalltalk }" + ImageReader subclass:#JPEGReader - instanceVariableNames:'jpeg_decompress_struct jpeg_compress_struct jpeg_error_mgr_struct colorComponents - forceGrayscale forceDitherMode app1SegmentHandler compressQuality bytesPerRow' + instanceVariableNames:'jpeg_decompress_struct jpeg_compress_struct jpeg_error_mgr_struct + colorComponents forceGrayscale forceDitherMode app1SegmentHandler + compressQuality bytesPerRow' classVariableNames:'ErrorPrinting' poolDictionaries:'' category:'Graphics-Images-Readers' @@ -174,13 +179,81 @@ This uses the libpeg library to read the image - Only reading of files is supported. + Only writing of depth24 images is currently supported. [See also:] - Image Form Icon - BlitImageReader FaceReader GIFReader PBMReader PCXReader - ST80FormReader SunRasterReader TargaReader TIFFReader WindowsIconReader - XBMReader XPMReader XWDReader + Image Form Icon + BlitImageReader FaceReader GIFReader PBMReader PCXReader + ST80FormReader SunRasterReader TargaReader TIFFReader WindowsIconReader + XBMReader XPMReader XWDReader +" +! + +examples +" + good quality: + [exBegin] + |i i24 i2| + + Transcript printf:'gif original %d\n' with:( '../../goodies/bitmaps/gifImages/garfield.gif' asFilename fileSize ). + i := Image fromFile:'../../goodies/bitmaps/gifImages/garfield.gif'. + i24 := Depth24Image fromImage:i. + JPEGReader save:i24 onFile:'test100.jpg'. + i2 := Image fromFile:'test100.jpg'. + Transcript printf:'jpg 100%% %d\n' with:( 'test100.jpg' asFilename fileSize ). + i2 inspect + [exEnd] + + + normal quality: + [exBegin] + |i i24 i2| + + Transcript printf:'gif original %d\n' with:( '../../goodies/bitmaps/gifImages/garfield.gif' asFilename fileSize ). + i := Image fromFile:'../../goodies/bitmaps/gifImages/garfield.gif'. + i24 := Depth24Image fromImage:i. + JPEGReader save:i24 onFile:'test80.jpg'. + i2 := Image fromFile:'test80.jpg'. + Transcript printf:'jpg 80%% %d\n' with:( 'test80.jpg' asFilename fileSize ). + i2 inspect + [exEnd] + + + low quality: + [exBegin] + |i i24 i2| + + i := Image fromFile:'../../goodies/bitmaps/gifImages/garfield.gif'. + i24 := Depth24Image fromImage:i. + JPEGReader new save:i24 onStream:('test50.jpg' asFilename writeStream) compressQuality:50. + i2 := Image fromFile:'test50.jpg'. + Transcript printf:'jpg 50%% %d\n' with:( 'test50.jpg' asFilename fileSize ). + i2 inspect + [exEnd] + + bad quality: + [exBegin] + |i i24 i2| + + i := Image fromFile:'../../goodies/bitmaps/gifImages/garfield.gif'. + i24 := Depth24Image fromImage:i. + JPEGReader new save:i24 onStream:('test20.jpg' asFilename writeStream) compressQuality:20. + i2 := Image fromFile:'test20.jpg'. + Transcript printf:'jpg 20%% %d\n' with:( 'test20.jpg' asFilename fileSize ). + i2 inspect + [exEnd] + + very bad quality: + [exBegin] + |i i24 i2| + + i := Image fromFile:'../../goodies/bitmaps/gifImages/garfield.gif'. + i24 := Depth24Image fromImage:i. + JPEGReader new save:i24 onStream:('test10.jpg' asFilename writeStream) compressQuality:10. + i2 := Image fromFile:'test10.jpg'. + Transcript printf:'jpg 10%% %d\n' with:( 'test10.jpg' asFilename fileSize ). + i2 inspect + [exEnd] " ! ! @@ -196,6 +269,12 @@ "Modified: 1.2.1997 / 15:01:55 / cg" ! ! +!JPEGReader class methodsFor:'defaults'! + +defaultCompressQuality + ^ 85 +! ! + !JPEGReader class methodsFor:'testing'! isValidImageFile:aFilenameOrString @@ -255,6 +334,85 @@ ^ cb code. "can be passed to C." ! +create_jpeg_compress_struct + |errMgrStructSize compressStructSize fp errorOccurred| + + self assert:(photometric == #rgb). + self assert:(samplesPerPixel == 3). + self assert:(bitsPerSample asArray = #(8 8 8)). + + fp := outStream filePointer. + fp isNil ifTrue:[ + self error:'can only write to an external stream'. + ^ false. + ]. + +%{ + errMgrStructSize = __mkSmallInteger(sizeof(struct my_error_mgr)); + compressStructSize = __mkSmallInteger(sizeof(struct jpeg_compress_struct)); +%}. + + jpeg_error_mgr_struct := ExternalBytes unprotectedNew:errMgrStructSize. + jpeg_compress_struct := ExternalBytes unprotectedNew:compressStructSize. + errorOccurred := false. + +%{ /* STACK: 400000 */ + struct jpeg_compress_struct *cinfoPtr; + struct my_error_mgr *jerrPtr; + OBJ j_e_m = __INST(jpeg_error_mgr_struct); + OBJ j_c_s = __INST(jpeg_compress_struct); + FILE *f = __FILEVal(fp); + char *outBuffer; + + if (__isExternalBytesLike(j_c_s) + && __isExternalBytesLike(j_e_m)) { + cinfoPtr = (struct jpeg_compress_struct *)(__externalBytesAddress(j_c_s)); + jerrPtr = (struct my_error_mgr *)(__externalBytesAddress(j_e_m)); + + /* + * Initialize the JPEG decompression object with default error handling. + */ + cinfoPtr->err = jpeg_std_error(&jerrPtr->pub); + + /* + * prepare to handle errors smoothly ... + */ + jerrPtr->pub.error_exit = my_error_exit; + if (setjmp(jerrPtr->setjmp_buffer)) { + /* + * error occurred ... + */ + jpeg_destroy_compress(cinfoPtr); + RETURN (false); + } + + /* + * use my message print function + */ + jerrPtr->pub.output_message = my_output_message; + + jpeg_create_compress(cinfoPtr); + + /* Specify data destination for compression */ + jpeg_stdio_dest(cinfoPtr, f); + + cinfoPtr->image_width = __intVal(__INST(width)); + cinfoPtr->image_height = __intVal(__INST(height)); + cinfoPtr->input_components = __intVal(__INST(samplesPerPixel)); + cinfoPtr->in_color_space = JCS_RGB; + + jpeg_set_defaults(cinfoPtr); + /*set the quality [0..100] */ + jpeg_set_quality (cinfoPtr, __intVal(__INST(compressQuality)), 1); + jpeg_start_compress(cinfoPtr, 1); + + + cinfoPtr->err->trace_level = 0; + } +%}. + ^ true +! + create_jpeg_decompress_struct |errMgrStructSize decompressStructSize fp errorOccurred app1SegmentCallbackFunction| @@ -409,85 +567,6 @@ ^ true ! -create_jpeg_compress_struct - |errMgrStructSize compressStructSize fp errorOccurred| - - self assert:(photometric == #rgb). - self assert:(samplesPerPixel == 3). - self assert:(bitsPerSample asArray = #(8 8 8)). - - fp := outStream filePointer. - fp isNil ifTrue:[ - self error:'can only write to an external stream'. - ^ false. - ]. - -%{ - errMgrStructSize = __mkSmallInteger(sizeof(struct my_error_mgr)); - compressStructSize = __mkSmallInteger(sizeof(struct jpeg_compress_struct)); -%}. - - jpeg_error_mgr_struct := ExternalBytes unprotectedNew:errMgrStructSize. - jpeg_compress_struct := ExternalBytes unprotectedNew:compressStructSize. - errorOccurred := false. - -%{ /* STACK: 400000 */ - struct jpeg_compress_struct *cinfoPtr; - struct my_error_mgr *jerrPtr; - OBJ j_e_m = __INST(jpeg_error_mgr_struct); - OBJ j_c_s = __INST(jpeg_compress_struct); - FILE *f = __FILEVal(fp); - char *outBuffer; - - if (__isExternalBytesLike(j_c_s) - && __isExternalBytesLike(j_e_m)) { - cinfoPtr = (struct jpeg_compress_struct *)(__externalBytesAddress(j_c_s)); - jerrPtr = (struct my_error_mgr *)(__externalBytesAddress(j_e_m)); - - /* - * Initialize the JPEG decompression object with default error handling. - */ - cinfoPtr->err = jpeg_std_error(&jerrPtr->pub); - - /* - * prepare to handle errors smoothly ... - */ - jerrPtr->pub.error_exit = my_error_exit; - if (setjmp(jerrPtr->setjmp_buffer)) { - /* - * error occurred ... - */ - jpeg_destroy_compress(cinfoPtr); - RETURN (false); - } - - /* - * use my message print function - */ - jerrPtr->pub.output_message = my_output_message; - - jpeg_create_compress(cinfoPtr); - - /* Specify data destination for compression */ - jpeg_stdio_dest(cinfoPtr, f); - - cinfoPtr->image_width = __intVal(__INST(width)); - cinfoPtr->image_height = __intVal(__INST(height)); - cinfoPtr->input_components = __intVal(__INST(samplesPerPixel)); - cinfoPtr->in_color_space = JCS_RGB; - - jpeg_set_defaults(cinfoPtr); - /*set the quality [0..100] */ - jpeg_set_quality (cinfoPtr, __intVal(__INST(compressQuality)), 1); - jpeg_start_compress(cinfoPtr, 1); - - - cinfoPtr->err->trace_level = 0; - } -%}. - ^ true -! - decompressChunkInto:aByteArray startingAt:index %{ /* STACK: 400000 */ struct jpeg_decompress_struct *cinfoPtr; @@ -563,6 +642,31 @@ app1SegmentHandler value:data. ! +finish_compress +%{ /* STACK: 400000 */ + struct jpeg_compress_struct *cinfoPtr; + struct my_error_mgr *jerrPtr; + OBJ j_c_s = __INST(jpeg_compress_struct); + OBJ j_e_m = __INST(jpeg_error_mgr_struct); + + if (__isExternalBytesLike(j_c_s) + && __isExternalBytesLike(j_e_m)) { + cinfoPtr = (struct jpeg_compress_struct *)(__externalBytesAddress(j_c_s)); + jerrPtr = (struct my_error_mgr *)(__externalBytesAddress(j_e_m)); + + if (setjmp(jerrPtr->setjmp_buffer)) { + jpeg_destroy_compress(cinfoPtr); + RETURN (false); + } + + /* finish decompressor */ + (void) jpeg_finish_compress(cinfoPtr); + (void) jpeg_destroy_compress(cinfoPtr); + RETURN (true); + } +%} +! + finish_decompress %{ /* STACK: 400000 */ struct jpeg_decompress_struct *cinfoPtr; @@ -588,31 +692,6 @@ %} ! -finish_compress -%{ /* STACK: 400000 */ - struct jpeg_compress_struct *cinfoPtr; - struct my_error_mgr *jerrPtr; - OBJ j_c_s = __INST(jpeg_compress_struct); - OBJ j_e_m = __INST(jpeg_error_mgr_struct); - - if (__isExternalBytesLike(j_c_s) - && __isExternalBytesLike(j_e_m)) { - cinfoPtr = (struct jpeg_compress_struct *)(__externalBytesAddress(j_c_s)); - jerrPtr = (struct my_error_mgr *)(__externalBytesAddress(j_e_m)); - - if (setjmp(jerrPtr->setjmp_buffer)) { - jpeg_destroy_compress(cinfoPtr); - RETURN (false); - } - - /* finish decompressor */ - (void) jpeg_finish_compress(cinfoPtr); - (void) jpeg_destroy_compress(cinfoPtr); - RETURN (true); - } -%} -! - get_error_message %{ j_common_ptr cinfoPtr; @@ -781,17 +860,60 @@ "Modified: / 12-12-2011 / 21:34:48 / cg" ! ! -!JPEGReader class methodsFor:'defaults'! -defaultCompressQuality - ^ 85 -! ! +!JPEGReader methodsFor:'writing'! + +compressScanlines +%{ + unsigned char *rowPtr; + int bpr = __intVal(__INST(bytesPerRow)); + int row; + int __height = __intVal(__INST(height)); + struct jpeg_compress_struct *cinfoPtr; + struct my_error_mgr *jerrPtr; + OBJ j_c_s = __INST(jpeg_compress_struct); + OBJ j_e_m = __INST(jpeg_error_mgr_struct); + OBJ __data = __INST(data); -!JPEGReader methodsFor:'writing'! + if (__isByteArray(__data)) { + rowPtr = (char *)(__ByteArrayInstPtr(__data)->ba_element); + } else if (__isExternalBytesLike(__data)) { + rowPtr = __externalBytesAddress(__data); + } + + if (__isExternalBytesLike(j_c_s) + && __isExternalBytesLike(j_e_m)) { + cinfoPtr = (struct jpeg_compress_struct *)(__externalBytesAddress(j_c_s)); + jerrPtr = (struct my_error_mgr *)(__externalBytesAddress(j_e_m)); + + if (setjmp(jerrPtr->setjmp_buffer)) { + jpeg_destroy_compress(cinfoPtr); + RETURN (false); + } + + for (row=0; row<__height; row++) { + jpeg_write_scanlines(cinfoPtr, &rowPtr, 1); + rowPtr += bpr; + } + } +%} +! save:image onStream:aStream "save image in JPG-file-format onto aStream" self save:image onStream:aStream compressQuality:(self class defaultCompressQuality) + + " + |i i24 i2| + + i := Image fromFile:'../../goodies/bitmaps/gifImages/garfield.gif'. + i24 := Depth24Image fromImage:i. + JPEGReader save:i24 onFile:'test.jpg'. + i2 := Image fromFile:'test.jpg'. + i2 inspect + " + + "Modified (comment): / 18-02-2016 / 02:36:44 / cg" ! save:image onStream:aStream compressQuality:qualityInPercent @@ -827,42 +949,6 @@ self compressScanlines. self finish_compress. -! - -compressScanlines -%{ - unsigned char *rowPtr; - int bpr = __intVal(__INST(bytesPerRow)); - int row; - int __height = __intVal(__INST(height)); - struct jpeg_compress_struct *cinfoPtr; - struct my_error_mgr *jerrPtr; - OBJ j_c_s = __INST(jpeg_compress_struct); - OBJ j_e_m = __INST(jpeg_error_mgr_struct); - OBJ __data = __INST(data); - - if (__isByteArray(__data)) { - rowPtr = (char *)(__ByteArrayInstPtr(__data)->ba_element); - } else if (__isExternalBytesLike(__data)) { - rowPtr = __externalBytesAddress(__data); - } - - if (__isExternalBytesLike(j_c_s) - && __isExternalBytesLike(j_e_m)) { - cinfoPtr = (struct jpeg_compress_struct *)(__externalBytesAddress(j_c_s)); - jerrPtr = (struct my_error_mgr *)(__externalBytesAddress(j_e_m)); - - if (setjmp(jerrPtr->setjmp_buffer)) { - jpeg_destroy_compress(cinfoPtr); - RETURN (false); - } - - for (row=0; row<__height; row++) { - jpeg_write_scanlines(cinfoPtr, &rowPtr, 1); - rowPtr += bpr; - } - } -%} ! ! !JPEGReader class methodsFor:'documentation'!