JPEGReader.st
changeset 3564 8946f8362c63
parent 3562 822b6d67ea95
child 3572 a5f900593881
equal deleted inserted replaced
3562:822b6d67ea95 3564:8946f8362c63
       
     1 "{ Encoding: utf8 }"
       
     2 
     1 "
     3 "
     2  COPYRIGHT (c) 1993 by Claus Gittinger
     4  COPYRIGHT (c) 1993 by Claus Gittinger
     3 	      All Rights Reserved
     5 	      All Rights Reserved
     4 
     6 
     5  This software is furnished under a license and may be used
     7  This software is furnished under a license and may be used
     9  other person.  No title to or ownership of the software is
    11  other person.  No title to or ownership of the software is
    10  hereby transferred.
    12  hereby transferred.
    11 "
    13 "
    12 "{ Package: 'stx:libview2' }"
    14 "{ Package: 'stx:libview2' }"
    13 
    15 
       
    16 "{ NameSpace: Smalltalk }"
       
    17 
    14 ImageReader subclass:#JPEGReader
    18 ImageReader subclass:#JPEGReader
    15 	instanceVariableNames:'jpeg_decompress_struct jpeg_compress_struct jpeg_error_mgr_struct colorComponents
    19 	instanceVariableNames:'jpeg_decompress_struct jpeg_compress_struct jpeg_error_mgr_struct
    16 		forceGrayscale forceDitherMode app1SegmentHandler compressQuality bytesPerRow'
    20 		colorComponents forceGrayscale forceDitherMode app1SegmentHandler
       
    21 		compressQuality bytesPerRow'
    17 	classVariableNames:'ErrorPrinting'
    22 	classVariableNames:'ErrorPrinting'
    18 	poolDictionaries:''
    23 	poolDictionaries:''
    19 	category:'Graphics-Images-Readers'
    24 	category:'Graphics-Images-Readers'
    20 !
    25 !
    21 
    26 
   172 "
   177 "
   173     Reader for JPEG images.
   178     Reader for JPEG images.
   174 
   179 
   175     This uses the libpeg library to read the image
   180     This uses the libpeg library to read the image
   176 
   181 
   177     Only reading of files is supported.
   182     Only writing of depth24 images is currently supported.
   178 
   183 
   179     [See also:]
   184     [See also:]
   180 	Image Form Icon
   185         Image Form Icon
   181 	BlitImageReader FaceReader GIFReader PBMReader PCXReader
   186         BlitImageReader FaceReader GIFReader PBMReader PCXReader
   182 	ST80FormReader SunRasterReader TargaReader TIFFReader WindowsIconReader
   187         ST80FormReader SunRasterReader TargaReader TIFFReader WindowsIconReader
   183 	XBMReader XPMReader XWDReader
   188         XBMReader XPMReader XWDReader
       
   189 "
       
   190 !
       
   191 
       
   192 examples
       
   193 "
       
   194     good quality:
       
   195                                                                 [exBegin]
       
   196      |i i24 i2|
       
   197 
       
   198      Transcript printf:'gif original %d\n' with:( '../../goodies/bitmaps/gifImages/garfield.gif' asFilename fileSize ).
       
   199      i := Image fromFile:'../../goodies/bitmaps/gifImages/garfield.gif'.
       
   200      i24 := Depth24Image fromImage:i.
       
   201      JPEGReader save:i24 onFile:'test100.jpg'.
       
   202      i2 := Image fromFile:'test100.jpg'.
       
   203      Transcript printf:'jpg 100%% %d\n' with:( 'test100.jpg' asFilename fileSize ).
       
   204      i2 inspect
       
   205                                                                 [exEnd]
       
   206 
       
   207 
       
   208     normal quality:
       
   209                                                                 [exBegin]
       
   210      |i i24 i2|
       
   211 
       
   212      Transcript printf:'gif original %d\n' with:( '../../goodies/bitmaps/gifImages/garfield.gif' asFilename fileSize ).
       
   213      i := Image fromFile:'../../goodies/bitmaps/gifImages/garfield.gif'.
       
   214      i24 := Depth24Image fromImage:i.
       
   215      JPEGReader save:i24 onFile:'test80.jpg'.
       
   216      i2 := Image fromFile:'test80.jpg'.
       
   217      Transcript printf:'jpg 80%% %d\n' with:( 'test80.jpg' asFilename fileSize ).
       
   218      i2 inspect
       
   219                                                                 [exEnd]
       
   220 
       
   221 
       
   222     low quality:
       
   223                                                                 [exBegin]
       
   224      |i i24 i2|
       
   225 
       
   226      i := Image fromFile:'../../goodies/bitmaps/gifImages/garfield.gif'.
       
   227      i24 := Depth24Image fromImage:i.
       
   228      JPEGReader new save:i24 onStream:('test50.jpg' asFilename writeStream) compressQuality:50.
       
   229      i2 := Image fromFile:'test50.jpg'.
       
   230      Transcript printf:'jpg 50%% %d\n' with:( 'test50.jpg' asFilename fileSize ).
       
   231      i2 inspect
       
   232                                                                 [exEnd]
       
   233 
       
   234     bad quality:
       
   235                                                                 [exBegin]
       
   236      |i i24 i2|
       
   237 
       
   238      i := Image fromFile:'../../goodies/bitmaps/gifImages/garfield.gif'.
       
   239      i24 := Depth24Image fromImage:i.
       
   240      JPEGReader new save:i24 onStream:('test20.jpg' asFilename writeStream) compressQuality:20.
       
   241      i2 := Image fromFile:'test20.jpg'.
       
   242      Transcript printf:'jpg 20%% %d\n' with:( 'test20.jpg' asFilename fileSize ).
       
   243      i2 inspect
       
   244                                                                 [exEnd]
       
   245 
       
   246     very bad quality:
       
   247                                                                 [exBegin]
       
   248      |i i24 i2|
       
   249 
       
   250      i := Image fromFile:'../../goodies/bitmaps/gifImages/garfield.gif'.
       
   251      i24 := Depth24Image fromImage:i.
       
   252      JPEGReader new save:i24 onStream:('test10.jpg' asFilename writeStream) compressQuality:10.
       
   253      i2 := Image fromFile:'test10.jpg'.
       
   254      Transcript printf:'jpg 10%% %d\n' with:( 'test10.jpg' asFilename fileSize ).
       
   255      i2 inspect
       
   256                                                                 [exEnd]
   184 "
   257 "
   185 ! !
   258 ! !
   186 
   259 
   187 !JPEGReader class methodsFor:'initialization'!
   260 !JPEGReader class methodsFor:'initialization'!
   188 
   261 
   192 
   265 
   193     MIMETypes defineImageType:'image/jpeg' suffix:'jpg'  reader:self.
   266     MIMETypes defineImageType:'image/jpeg' suffix:'jpg'  reader:self.
   194     MIMETypes defineImageType:nil          suffix:'jpeg' reader:self.
   267     MIMETypes defineImageType:nil          suffix:'jpeg' reader:self.
   195 
   268 
   196     "Modified: 1.2.1997 / 15:01:55 / cg"
   269     "Modified: 1.2.1997 / 15:01:55 / cg"
       
   270 ! !
       
   271 
       
   272 !JPEGReader class methodsFor:'defaults'!
       
   273 
       
   274 defaultCompressQuality
       
   275     ^ 85
   197 ! !
   276 ! !
   198 
   277 
   199 !JPEGReader class methodsFor:'testing'!
   278 !JPEGReader class methodsFor:'testing'!
   200 
   279 
   201 isValidImageFile:aFilenameOrString
   280 isValidImageFile:aFilenameOrString
   251     cb := ExternalFunctionCallback new.
   330     cb := ExternalFunctionCallback new.
   252     cb returnType:#bool argumentTypes:#(pointer).
   331     cb returnType:#bool argumentTypes:#(pointer).
   253     cb generateClosure.
   332     cb generateClosure.
   254     cb action:[:args | self fetchApp1SegmentData. true].
   333     cb action:[:args | self fetchApp1SegmentData. true].
   255     ^ cb code.  "can be passed to C."
   334     ^ cb code.  "can be passed to C."
       
   335 !
       
   336 
       
   337 create_jpeg_compress_struct
       
   338     |errMgrStructSize compressStructSize fp errorOccurred|
       
   339 
       
   340     self assert:(photometric == #rgb).
       
   341     self assert:(samplesPerPixel == 3).
       
   342     self assert:(bitsPerSample asArray = #(8 8 8)).
       
   343 
       
   344     fp := outStream filePointer.
       
   345     fp isNil ifTrue:[
       
   346 	self error:'can only write to an external stream'.
       
   347 	^ false.
       
   348     ].
       
   349 
       
   350 %{
       
   351     errMgrStructSize = __mkSmallInteger(sizeof(struct my_error_mgr));
       
   352     compressStructSize = __mkSmallInteger(sizeof(struct jpeg_compress_struct));
       
   353 %}.
       
   354 
       
   355     jpeg_error_mgr_struct := ExternalBytes unprotectedNew:errMgrStructSize.
       
   356     jpeg_compress_struct := ExternalBytes unprotectedNew:compressStructSize.
       
   357     errorOccurred := false.
       
   358 
       
   359 %{  /* STACK: 400000 */
       
   360     struct jpeg_compress_struct *cinfoPtr;
       
   361     struct my_error_mgr *jerrPtr;
       
   362     OBJ j_e_m = __INST(jpeg_error_mgr_struct);
       
   363     OBJ j_c_s = __INST(jpeg_compress_struct);
       
   364     FILE *f = __FILEVal(fp);
       
   365     char *outBuffer;
       
   366 
       
   367     if (__isExternalBytesLike(j_c_s)
       
   368      && __isExternalBytesLike(j_e_m)) {
       
   369 	cinfoPtr = (struct jpeg_compress_struct *)(__externalBytesAddress(j_c_s));
       
   370 	jerrPtr = (struct my_error_mgr *)(__externalBytesAddress(j_e_m));
       
   371 
       
   372 	/*
       
   373 	 * Initialize the JPEG decompression object with default error handling.
       
   374 	 */
       
   375 	cinfoPtr->err = jpeg_std_error(&jerrPtr->pub);
       
   376 
       
   377 	/*
       
   378 	 * prepare to handle errors smoothly ...
       
   379 	 */
       
   380 	jerrPtr->pub.error_exit = my_error_exit;
       
   381 	if (setjmp(jerrPtr->setjmp_buffer)) {
       
   382 	    /*
       
   383 	     * error occurred ...
       
   384 	     */
       
   385 	    jpeg_destroy_compress(cinfoPtr);
       
   386 	    RETURN (false);
       
   387 	}
       
   388 
       
   389 	/*
       
   390 	 * use my message print function
       
   391 	 */
       
   392 	jerrPtr->pub.output_message = my_output_message;
       
   393 
       
   394 	jpeg_create_compress(cinfoPtr);
       
   395 
       
   396 	/* Specify data destination for compression */
       
   397 	jpeg_stdio_dest(cinfoPtr, f);
       
   398 
       
   399 	cinfoPtr->image_width      = __intVal(__INST(width));
       
   400 	cinfoPtr->image_height     = __intVal(__INST(height));
       
   401 	cinfoPtr->input_components = __intVal(__INST(samplesPerPixel));
       
   402 	cinfoPtr->in_color_space   = JCS_RGB;
       
   403 
       
   404 	jpeg_set_defaults(cinfoPtr);
       
   405 	/*set the quality [0..100]  */
       
   406 	jpeg_set_quality (cinfoPtr, __intVal(__INST(compressQuality)), 1);
       
   407 	jpeg_start_compress(cinfoPtr, 1);
       
   408 
       
   409 
       
   410 	cinfoPtr->err->trace_level = 0;
       
   411     }
       
   412 %}.
       
   413     ^ true
   256 !
   414 !
   257 
   415 
   258 create_jpeg_decompress_struct
   416 create_jpeg_decompress_struct
   259     |errMgrStructSize decompressStructSize fp errorOccurred app1SegmentCallbackFunction|
   417     |errMgrStructSize decompressStructSize fp errorOccurred app1SegmentCallbackFunction|
   260 
   418 
   407     }
   565     }
   408 %}.
   566 %}.
   409     ^ true
   567     ^ true
   410 !
   568 !
   411 
   569 
   412 create_jpeg_compress_struct
       
   413     |errMgrStructSize compressStructSize fp errorOccurred|
       
   414 
       
   415     self assert:(photometric == #rgb).
       
   416     self assert:(samplesPerPixel == 3).
       
   417     self assert:(bitsPerSample asArray = #(8 8 8)).
       
   418 
       
   419     fp := outStream filePointer.
       
   420     fp isNil ifTrue:[
       
   421 	self error:'can only write to an external stream'.
       
   422 	^ false.
       
   423     ].
       
   424 
       
   425 %{
       
   426     errMgrStructSize = __mkSmallInteger(sizeof(struct my_error_mgr));
       
   427     compressStructSize = __mkSmallInteger(sizeof(struct jpeg_compress_struct));
       
   428 %}.
       
   429 
       
   430     jpeg_error_mgr_struct := ExternalBytes unprotectedNew:errMgrStructSize.
       
   431     jpeg_compress_struct := ExternalBytes unprotectedNew:compressStructSize.
       
   432     errorOccurred := false.
       
   433 
       
   434 %{  /* STACK: 400000 */
       
   435     struct jpeg_compress_struct *cinfoPtr;
       
   436     struct my_error_mgr *jerrPtr;
       
   437     OBJ j_e_m = __INST(jpeg_error_mgr_struct);
       
   438     OBJ j_c_s = __INST(jpeg_compress_struct);
       
   439     FILE *f = __FILEVal(fp);
       
   440     char *outBuffer;
       
   441 
       
   442     if (__isExternalBytesLike(j_c_s)
       
   443      && __isExternalBytesLike(j_e_m)) {
       
   444 	cinfoPtr = (struct jpeg_compress_struct *)(__externalBytesAddress(j_c_s));
       
   445 	jerrPtr = (struct my_error_mgr *)(__externalBytesAddress(j_e_m));
       
   446 
       
   447 	/*
       
   448 	 * Initialize the JPEG decompression object with default error handling.
       
   449 	 */
       
   450 	cinfoPtr->err = jpeg_std_error(&jerrPtr->pub);
       
   451 
       
   452 	/*
       
   453 	 * prepare to handle errors smoothly ...
       
   454 	 */
       
   455 	jerrPtr->pub.error_exit = my_error_exit;
       
   456 	if (setjmp(jerrPtr->setjmp_buffer)) {
       
   457 	    /*
       
   458 	     * error occurred ...
       
   459 	     */
       
   460 	    jpeg_destroy_compress(cinfoPtr);
       
   461 	    RETURN (false);
       
   462 	}
       
   463 
       
   464 	/*
       
   465 	 * use my message print function
       
   466 	 */
       
   467 	jerrPtr->pub.output_message = my_output_message;
       
   468 
       
   469 	jpeg_create_compress(cinfoPtr);
       
   470 
       
   471 	/* Specify data destination for compression */
       
   472 	jpeg_stdio_dest(cinfoPtr, f);
       
   473 
       
   474 	cinfoPtr->image_width      = __intVal(__INST(width));
       
   475 	cinfoPtr->image_height     = __intVal(__INST(height));
       
   476 	cinfoPtr->input_components = __intVal(__INST(samplesPerPixel));
       
   477 	cinfoPtr->in_color_space   = JCS_RGB;
       
   478 
       
   479 	jpeg_set_defaults(cinfoPtr);
       
   480 	/*set the quality [0..100]  */
       
   481 	jpeg_set_quality (cinfoPtr, __intVal(__INST(compressQuality)), 1);
       
   482 	jpeg_start_compress(cinfoPtr, 1);
       
   483 
       
   484 
       
   485 	cinfoPtr->err->trace_level = 0;
       
   486     }
       
   487 %}.
       
   488     ^ true
       
   489 !
       
   490 
       
   491 decompressChunkInto:aByteArray startingAt:index
   570 decompressChunkInto:aByteArray startingAt:index
   492 %{  /* STACK: 400000 */
   571 %{  /* STACK: 400000 */
   493     struct jpeg_decompress_struct *cinfoPtr;
   572     struct jpeg_decompress_struct *cinfoPtr;
   494     struct my_error_mgr *jerrPtr;
   573     struct my_error_mgr *jerrPtr;
   495     char *rowPtr = NULL;
   574     char *rowPtr = NULL;
   561     ].
   640     ].
   562     self breakPoint:#cg.
   641     self breakPoint:#cg.
   563     app1SegmentHandler value:data.
   642     app1SegmentHandler value:data.
   564 !
   643 !
   565 
   644 
       
   645 finish_compress
       
   646 %{  /* STACK: 400000 */
       
   647     struct jpeg_compress_struct *cinfoPtr;
       
   648     struct my_error_mgr *jerrPtr;
       
   649     OBJ j_c_s = __INST(jpeg_compress_struct);
       
   650     OBJ j_e_m = __INST(jpeg_error_mgr_struct);
       
   651 
       
   652     if (__isExternalBytesLike(j_c_s)
       
   653      && __isExternalBytesLike(j_e_m)) {
       
   654 	cinfoPtr = (struct jpeg_compress_struct *)(__externalBytesAddress(j_c_s));
       
   655 	jerrPtr = (struct my_error_mgr *)(__externalBytesAddress(j_e_m));
       
   656 
       
   657 	if (setjmp(jerrPtr->setjmp_buffer)) {
       
   658 	    jpeg_destroy_compress(cinfoPtr);
       
   659 	    RETURN (false);
       
   660 	}
       
   661 
       
   662 	/* finish decompressor */
       
   663 	(void) jpeg_finish_compress(cinfoPtr);
       
   664 	(void) jpeg_destroy_compress(cinfoPtr);
       
   665 	RETURN (true);
       
   666     }
       
   667 %}
       
   668 !
       
   669 
   566 finish_decompress
   670 finish_decompress
   567 %{  /* STACK: 400000 */
   671 %{  /* STACK: 400000 */
   568     struct jpeg_decompress_struct *cinfoPtr;
   672     struct jpeg_decompress_struct *cinfoPtr;
   569     struct my_error_mgr *jerrPtr;
   673     struct my_error_mgr *jerrPtr;
   570     OBJ j_d_s = __INST(jpeg_decompress_struct);
   674     OBJ j_d_s = __INST(jpeg_decompress_struct);
   581 	}
   685 	}
   582 
   686 
   583 	/* finish decompressor */
   687 	/* finish decompressor */
   584 	(void) jpeg_finish_decompress(cinfoPtr);
   688 	(void) jpeg_finish_decompress(cinfoPtr);
   585 	(void) jpeg_destroy_decompress(cinfoPtr);
   689 	(void) jpeg_destroy_decompress(cinfoPtr);
   586 	RETURN (true);
       
   587     }
       
   588 %}
       
   589 !
       
   590 
       
   591 finish_compress
       
   592 %{  /* STACK: 400000 */
       
   593     struct jpeg_compress_struct *cinfoPtr;
       
   594     struct my_error_mgr *jerrPtr;
       
   595     OBJ j_c_s = __INST(jpeg_compress_struct);
       
   596     OBJ j_e_m = __INST(jpeg_error_mgr_struct);
       
   597 
       
   598     if (__isExternalBytesLike(j_c_s)
       
   599      && __isExternalBytesLike(j_e_m)) {
       
   600 	cinfoPtr = (struct jpeg_compress_struct *)(__externalBytesAddress(j_c_s));
       
   601 	jerrPtr = (struct my_error_mgr *)(__externalBytesAddress(j_e_m));
       
   602 
       
   603 	if (setjmp(jerrPtr->setjmp_buffer)) {
       
   604 	    jpeg_destroy_compress(cinfoPtr);
       
   605 	    RETURN (false);
       
   606 	}
       
   607 
       
   608 	/* finish decompressor */
       
   609 	(void) jpeg_finish_compress(cinfoPtr);
       
   610 	(void) jpeg_destroy_compress(cinfoPtr);
       
   611 	RETURN (true);
   690 	RETURN (true);
   612     }
   691     }
   613 %}
   692 %}
   614 !
   693 !
   615 
   694 
   779     "
   858     "
   780 
   859 
   781     "Modified: / 12-12-2011 / 21:34:48 / cg"
   860     "Modified: / 12-12-2011 / 21:34:48 / cg"
   782 ! !
   861 ! !
   783 
   862 
   784 !JPEGReader class methodsFor:'defaults'!
       
   785 defaultCompressQuality
       
   786     ^ 85
       
   787 ! !
       
   788 
       
   789 !JPEGReader methodsFor:'writing'!
   863 !JPEGReader methodsFor:'writing'!
   790 
       
   791 save:image onStream:aStream
       
   792     "save image in JPG-file-format onto aStream"
       
   793 
       
   794     self save:image onStream:aStream compressQuality:(self class defaultCompressQuality)
       
   795 !
       
   796 
       
   797 save:image onStream:aStream compressQuality:qualityInPercent
       
   798     "save image in JPG-file-format onto aStream"
       
   799 
       
   800     image depth ~~ 24 ifTrue:[
       
   801 	^ Image cannotRepresentImageSignal
       
   802 	    raiseWith:image
       
   803 	    errorString:('JPG (currently) only supports depth24 images').
       
   804     ].
       
   805 
       
   806     outStream := aStream.
       
   807     outStream binary.
       
   808 
       
   809 "/    mask := image mask.
       
   810 "/    mask notNil ifTrue:[
       
   811 "/        self assignTransparentPixelIn:image
       
   812 "/    ].
       
   813 
       
   814     width := image width.
       
   815     height := image height.
       
   816     photometric := image photometric.
       
   817     samplesPerPixel := image samplesPerPixel.
       
   818     bitsPerSample := image bitsPerSample.
       
   819     colorMap := image colorMap.
       
   820     bytesPerRow := image bytesPerRow.
       
   821     data := image bits.
       
   822     compressQuality := qualityInPercent.
       
   823 
       
   824     (self create_jpeg_compress_struct not) ifTrue:[
       
   825 	self errir:'JPG: setup error'.
       
   826     ].
       
   827 
       
   828     self compressScanlines.
       
   829     self finish_compress.
       
   830 !
       
   831 
   864 
   832 compressScanlines
   865 compressScanlines
   833 %{
   866 %{
   834     unsigned char *rowPtr;
   867     unsigned char *rowPtr;
   835     int bpr = __intVal(__INST(bytesPerRow));
   868     int bpr = __intVal(__INST(bytesPerRow));
   861 	    jpeg_write_scanlines(cinfoPtr, &rowPtr, 1);
   894 	    jpeg_write_scanlines(cinfoPtr, &rowPtr, 1);
   862 	    rowPtr += bpr;
   895 	    rowPtr += bpr;
   863 	}
   896 	}
   864     }
   897     }
   865 %}
   898 %}
       
   899 !
       
   900 
       
   901 save:image onStream:aStream
       
   902     "save image in JPG-file-format onto aStream"
       
   903 
       
   904     self save:image onStream:aStream compressQuality:(self class defaultCompressQuality)
       
   905 
       
   906     "
       
   907      |i i24 i2|
       
   908 
       
   909      i := Image fromFile:'../../goodies/bitmaps/gifImages/garfield.gif'.
       
   910      i24 := Depth24Image fromImage:i.
       
   911      JPEGReader save:i24 onFile:'test.jpg'.
       
   912      i2 := Image fromFile:'test.jpg'.
       
   913      i2 inspect
       
   914     "
       
   915 
       
   916     "Modified (comment): / 18-02-2016 / 02:36:44 / cg"
       
   917 !
       
   918 
       
   919 save:image onStream:aStream compressQuality:qualityInPercent
       
   920     "save image in JPG-file-format onto aStream"
       
   921 
       
   922     image depth ~~ 24 ifTrue:[
       
   923 	^ Image cannotRepresentImageSignal
       
   924 	    raiseWith:image
       
   925 	    errorString:('JPG (currently) only supports depth24 images').
       
   926     ].
       
   927 
       
   928     outStream := aStream.
       
   929     outStream binary.
       
   930 
       
   931 "/    mask := image mask.
       
   932 "/    mask notNil ifTrue:[
       
   933 "/        self assignTransparentPixelIn:image
       
   934 "/    ].
       
   935 
       
   936     width := image width.
       
   937     height := image height.
       
   938     photometric := image photometric.
       
   939     samplesPerPixel := image samplesPerPixel.
       
   940     bitsPerSample := image bitsPerSample.
       
   941     colorMap := image colorMap.
       
   942     bytesPerRow := image bytesPerRow.
       
   943     data := image bits.
       
   944     compressQuality := qualityInPercent.
       
   945 
       
   946     (self create_jpeg_compress_struct not) ifTrue:[
       
   947 	self errir:'JPG: setup error'.
       
   948     ].
       
   949 
       
   950     self compressScanlines.
       
   951     self finish_compress.
   866 ! !
   952 ! !
   867 
   953 
   868 !JPEGReader class methodsFor:'documentation'!
   954 !JPEGReader class methodsFor:'documentation'!
   869 
   955 
   870 version
   956 version