JPEGReader.st
changeset 528 e7bc0efceac9
parent 522 93a9f3a8caae
child 532 66aa3109df17
--- a/JPEGReader.st	Mon Apr 14 17:11:16 1997 +0200
+++ b/JPEGReader.st	Wed Apr 16 22:11:53 1997 +0200
@@ -10,8 +10,11 @@
  hereby transferred.
 "
 
+'From Smalltalk/X, Version:3.1.6 on 16-apr-1997 at 9:09:50 pm'                  !
+
 ImageReader subclass:#JPEGReader
-	instanceVariableNames:''
+	instanceVariableNames:'jpeg_decompress_struct jpeg_error_mgr_struct decompressBuffer
+		colorComponents forceGrayscale forceDitherMode'
 	classVariableNames:''
 	poolDictionaries:''
 	category:'Graphics-Images-Support'
@@ -25,8 +28,79 @@
  * and typedefs come here.
  */
 
-#include <jpeglib.h>
-#include <jerror.h>
+#include <stdio.h>
+
+#ifndef NO_TESTING
+# include "../../support/libjpeg-6a/jpeglib.h"
+# include "../../support/libjpeg-6a/jerror.h"
+#else
+# include <jpeglib.h>
+# include <jerror.h>
+#endif
+
+%}
+! !
+
+!JPEGReader primitiveFunctions!
+%{
+
+/* 
+ * any local C (helper) functions
+ * come here (please, define as static)
+ */
+
+/*
+ * Optional progress monitor: display a percent-done figure on stderr.
+ */
+
+#ifdef PROGRESS_REPORT
+
+void
+JPG_progress_monitor (j_common_ptr cinfo)
+{
+  cd_progress_ptr prog = (cd_progress_ptr) cinfo->progress;
+  int total_passes = prog->pub.total_passes + prog->total_extra_passes;
+  int percent_done = (int) (prog->pub.pass_counter*100L/prog->pub.pass_limit);
+
+  if (percent_done != prog->percent_done) {
+    prog->percent_done = percent_done;
+    if (total_passes > 1) {
+      fprintf(stderr, "\rPass %d/%d: %3d%% ",
+              prog->pub.completed_passes + prog->completed_extra_passes + 1,
+              total_passes, percent_done);
+    } else {
+      fprintf(stderr, "\r %3d%% ", percent_done);
+    }
+    fflush(stderr);
+  }
+}
+
+
+void
+JPG_start_progress_monitor (j_common_ptr cinfo, cd_progress_ptr progress)
+{
+  /* Enable progress display, unless trace output is on */
+  if (cinfo->err->trace_level == 0) {
+    progress->pub.progress_monitor = progress_monitor;
+    progress->completed_extra_passes = 0;
+    progress->total_extra_passes = 0;
+    progress->percent_done = -1;
+    cinfo->progress = &progress->pub;
+  }
+}
+
+
+void
+JPG_end_progress_monitor (j_common_ptr cinfo)
+{
+  /* Clear away progress display */
+  if (cinfo->err->trace_level == 0) {
+    fprintf(stderr, "\r                \r");
+    fflush(stderr);
+  }
+}
+
+#endif
 
 %}
 ! !
@@ -83,39 +157,6 @@
     "Modified: 1.2.1997 / 15:01:55 / cg"
 ! !
 
-!JPEGReader class methodsFor:'reading from file'!
-
-fromFile:aFileName
-    "read a jpg image from a file.
-     Make it the easy way: let djpeg convert it to gif,
-     then let GIFReader read the file."
-
-    |tempFileName reader|
-
-    tempFileName := '/tmp/img' , (OperatingSystem getProcessId printString).
-
-    'JPEGREADER [info]: converting to ppm ..' infoPrintCR.
-    (OperatingSystem executeCommand:'djpeg -pnm ' , aFileName , ' > ' , tempFileName)
-    ifFalse:[
-        (OperatingSystem executeCommand:'../../support/libjpeg/djpeg -pnm ' , aFileName , ' > ' , tempFileName)    
-        ifFalse:[
-            'JPEGREADER [warning]: conversion failed ..' errorPrintCR.
-            'JPEGREADER [warning]: .. cannot execute converter: djpeg' errorPrintCR.
-            ^ nil
-        ].
-    ].
-
-    reader := PBMReader fromFile:tempFileName.
-    OperatingSystem executeCommand:'rm ' , tempFileName.
-    ^ reader
-
-    "
-     JPEGReader fromFile:'bitmaps/testimg.jpg'
-    "
-
-    "Modified: 11.4.1997 / 16:39:59 / cg"
-! !
-
 !JPEGReader class methodsFor:'testing'!
 
 isValidImageFile:aFileName
@@ -129,9 +170,294 @@
     "Created: 11.4.1997 / 16:26:25 / cg"
 ! !
 
+!JPEGReader methodsFor:'accessing'!
+
+forceDitherMode:something
+    "set the dither mode, to one of #none or #ordered"
+
+    forceDitherMode := something.
+
+    "Modified: 16.4.1997 / 20:34:59 / cg"
+!
+
+forceGrayscale:something
+    "set the forceGrayscale mode; if true, grayScale images are
+     returned, even if the input contains a color image."
+
+    forceGrayscale := something.
+
+    "Created: 16.4.1997 / 20:33:44 / cg"
+    "Modified: 16.4.1997 / 20:34:29 / cg"
+! !
+
+!JPEGReader methodsFor:'private'!
+
+create_jpeg_decompress_struct
+    |structSize fp|
+
+    fp := inStream filePointer.
+    fp isNil ifTrue:[
+        self error:'can only read from an external stream'.
+        ^ self.
+    ].
+
+%{
+    structSize = __MKSMALLINT(sizeof(struct jpeg_error_mgr));
+%}.
+
+    jpeg_error_mgr_struct := ExternalBytes unprotectedNew:structSize.
+
+%{
+    structSize = __MKSMALLINT(sizeof(struct jpeg_decompress_struct));
+%}.
+
+    jpeg_decompress_struct := ExternalBytes unprotectedNew:structSize.
+
+%{
+    struct jpeg_decompress_struct *cinfoPtr;
+    struct jpeg_error_mgr *jerrPtr;
+    OBJ j_e_m = __INST(jpeg_error_mgr_struct);
+    OBJ j_d_s = __INST(jpeg_decompress_struct);
+    FILE *f = __FILEVal(fp);
+
+    if (__isExternalBytes(j_d_s)
+     && __isExternalBytes(j_e_m)) {
+        cinfoPtr = (struct jpeg_decompress_struct *)(__externalBytesAddress(j_d_s));
+        jerrPtr = (struct jpeg_error_mgr *)(__externalBytesAddress(j_e_m));
+
+        /* 
+         * Initialize the JPEG decompression object with default error handling.
+         */
+        cinfoPtr->err = jpeg_std_error(jerrPtr);
+
+        jpeg_create_decompress(cinfoPtr);
+#if 0
+        /* 
+         * Insert custom COM marker processor.
+         */
+        jpeg_set_marker_processor(cinfoPtr, JPEG_COM, COM_handler);
+#endif
+        cinfoPtr->err->trace_level = 0;
+
+#if 0
+        /* colors setting */
+        cinfoPtr->desired_number_of_colors = val;
+        cinfoPtr->quantize_colors = TRUE;
+#endif
+#if 0
+        /* dct setting */
+        cinfoPtr->dct_method = JDCT_ISLOW;
+        or: cinfoPtr->dct_method = JDCT_IFAST;
+        or: cinfoPtr->dct_method = JDCT_FLOAT;
+#endif
+
+        /* dither setting */
+        cinfoPtr->dither_mode = JDITHER_FS;
+        if (__INST(forceDitherMode) == @symbol(none)) {
+            cinfoPtr->dither_mode = JDITHER_NONE;
+        } else {
+            if (__INST(forceDitherMode) == @symbol(ordered)) {
+                cinfoPtr->dither_mode = JDITHER_ORDERED;
+            }
+        }
+
+#if 0
+        /* fast setting */
+        cinfoPtr->two_pass_quantize = FALSE;
+        cinfoPtr->dither_mode = JDITHER_ORDERED;
+        cinfoPtr->desired_number_of_colors = 216;
+        cinfoPtr->dct_method = JDCT_FASTEST;
+        cinfoPtr->do_fancy_upsampling = FALSE;
+#endif
+
+        if (__INST(forceGrayscale) == true) {
+            /* grayscale setting */
+            cinfoPtr->out_color_space = JCS_GRAYSCALE;
+        }
+
+#if 0
+        /* maxmemory setting */
+        cinfoPtr->mem->max_memory_to_use = lval * 1000L;
+#endif
+#if 0
+        /* nosmooth setting */
+        cinfoPtr->do_fancy_upsampling = FALSE;
+#endif
+#if 0
+        /* onepass setting */
+        cinfoPtr->two_pass_quantize = FALSE;
+#endif
+
+        /* Specify data source for decompression */
+        jpeg_stdio_src(cinfoPtr, f);
+
+        /* Read file header, set default decompression parameters */
+        (void) jpeg_read_header(cinfoPtr, TRUE);
+
+        /* Calculate output image dimensions so we can allocate space */
+        jpeg_calc_output_dimensions(cinfoPtr);
+
+        __INST(width) = __MKSMALLINT(cinfoPtr->output_width);
+        __INST(height) = __MKSMALLINT(cinfoPtr->output_height);
+        __INST(colorComponents) = __MKSMALLINT(cinfoPtr->output_components);
+
+        printf("colorComponents: %d\n", cinfoPtr->output_components);
+
+#if 0
+        /* could now set additional values in cinfo
+         * (colormap)
+         */
+#endif
+    }
+%} 
+
+!
+
+decompressChunk
+%{
+    struct jpeg_decompress_struct *cinfoPtr;
+    char *rgbRow;
+    OBJ j_d_s = __INST(jpeg_decompress_struct);
+    int num_scanlines;
+    JSAMPROW rowPointers[4];
+
+    if (__isExternalBytes(j_d_s)
+     && __isByteArray(__INST(decompressBuffer))) {
+        cinfoPtr = (struct jpeg_decompress_struct *)(__externalBytesAddress(j_d_s));
+        rgbRow = __ByteArrayInstPtr(__INST(decompressBuffer))->ba_element;
+
+        rowPointers[0] = (JSAMPROW) rgbRow;
+        rowPointers[1] = NULL;
+        rowPointers[2] = NULL;
+        rowPointers[3] = NULL;
+
+        if (cinfoPtr->output_scanline < cinfoPtr->output_height) {
+            num_scanlines = jpeg_read_scanlines(cinfoPtr, 
+                                                rowPointers,
+                                                1);
+            RETURN (__MKSMALLINT(num_scanlines));
+        }
+        RETURN (__MKSMALLINT(0));
+    }
+%}.
+    self halt.
+!
+
+decompressChunkInto:aByteArray startingAt:index
+%{
+    struct jpeg_decompress_struct *cinfoPtr;
+    char *rowPtr;
+    OBJ j_d_s = __INST(jpeg_decompress_struct);
+    int num_scanlines;
+    char *rowPointers[4];
+
+    if (__isExternalBytes(j_d_s)
+     && __isByteArray(aByteArray)) {
+        cinfoPtr = (struct jpeg_decompress_struct *)(__externalBytesAddress(j_d_s));
+        rowPtr = (char *)(__ByteArrayInstPtr(aByteArray)->ba_element);
+        rowPtr += __intVal(index) - 1;
+
+        rowPointers[0] = rowPtr;
+        rowPointers[1] = NULL;
+        rowPointers[2] = NULL;
+        rowPointers[3] = NULL;
+
+        if (cinfoPtr->output_scanline < cinfoPtr->output_height) {
+            num_scanlines = jpeg_read_scanlines(cinfoPtr, 
+                                                rowPointers,
+                                                1);
+            RETURN (__MKSMALLINT(num_scanlines));
+        }
+        RETURN (__MKSMALLINT(0));
+    }
+%}.
+    self halt.
+!
+
+finish_decompress
+%{
+    struct jpeg_decompress *cinfoPtr;
+    OBJ j_d_s = __INST(jpeg_decompress_struct);
+
+    if (__isExternalBytes(j_d_s)) {
+        cinfoPtr = (struct jpeg_decompress *)(__externalBytesAddress(j_d_s));
+
+        /* Start decompressor */
+        (void) jpeg_finish_decompress(cinfoPtr);
+        (void) jpeg_destroy_decompress(cinfoPtr);
+    }
+%}
+
+
+!
+
+start_decompress
+    decompressBuffer := ByteArray new:(width * colorComponents).
+
+%{
+    struct jpeg_decompress *cinfoPtr;
+    OBJ j_d_s = __INST(jpeg_decompress_struct);
+
+    if (__isExternalBytes(j_d_s)) {
+        cinfoPtr = (struct jpeg_decompress *)(__externalBytesAddress(j_d_s));
+
+        /* Start decompressor */
+        (void) jpeg_start_decompress(cinfoPtr);
+    }
+%}
+! !
+
+!JPEGReader methodsFor:'reading from stream'!
+
+fromStream:aStream
+    "read a JPG image from a stream"
+
+    |dataIdx bytesPerRow|
+
+    inStream := aStream.
+
+    self create_jpeg_decompress_struct.
+    self start_decompress.
+
+    data := ByteArray uninitializedNew:(width * height * colorComponents).
+    dataIdx := 1.
+    bytesPerRow := colorComponents * width.
+
+    [(self decompressChunkInto:data startingAt:dataIdx) ~~ 0] whileTrue:[
+        "/ got a row in the buffer ...
+        dataIdx := dataIdx + bytesPerRow
+    ].    
+
+    self finish_decompress.
+
+    colorComponents == 3 ifTrue:[
+        photometric := #rgb.
+        samplesPerPixel := 3.
+        bitsPerSample := #(8 8 8).
+    ] ifFalse:[
+        self halt:'unexpected value'
+    ].
+
+    "
+     JPEGReader fromFile:'../../support/libjpeg-6a/testimg.jpg'
+    "
+    "
+     |stream reader|
+
+     stream := '../../support/libjpeg-6a/testimg.jpg' asFilename readStream.
+     reader := JPEGReader new.
+     reader forceGrayscale:true.
+     reader forceDitherMode:#ordered.
+     reader fromStream:stream.
+     ^ reader image
+    "
+
+    "Modified: 16.4.1997 / 20:36:12 / cg"
+! !
+
 !JPEGReader class methodsFor:'documentation'!
 
 version
-    ^ '$Header: /cvs/stx/stx/libview2/JPEGReader.st,v 1.19 1997-04-11 14:44:54 cg Exp $'
+    ^ '$Header: /cvs/stx/stx/libview2/JPEGReader.st,v 1.20 1997-04-16 20:11:53 cg Exp $'
 ! !
 JPEGReader initialize!