JPEG再考(その3)

 DC,ACの符号量を量るために,Independet Jpeg Groupの"jpeg-6b"に改変したところを残しておきます.

 jpeglib.hにはdcbitsとacbits,どの係数を残すかを決めるmaskを追加しました.
 jchuff.cが,実際に符号量を計算しているところ.
 cjpeg.cで,maskをコマンドラインから取得しています.かなり秀逸な指定方法だと自負しているんだけど,どうだろう?

--- jpeglib.h	1998-02-22 04:48:14.000000000 +0900
+++ jpeglib.h	2007-11-21 20:01:26.000000000 +0900
@@ -403,6 +403,8 @@
   struct jpeg_entropy_encoder * entropy;
   jpeg_scan_info * script_space; /* workspace for jpeg_simple_progression */
   int script_space_size;
+  int dcbits, acbits;
+  JCOEF mask[DCTSIZE2];
 };
--- jchuff.c	1997-10-21 09:20:39.000000000 +0900
+++ jchuff.c	2007-11-21 20:33:42.000000000 +0900
@@ -356,9 +356,13 @@
   register int temp, temp2;
   register int nbits;
   register int k, r, i;
+  register int acbits;
+
+  acbits = 0;
   
   /* Encode the DC coefficient difference per section F.1.2.1 */
   
+  block[0] &= state->cinfo->mask[0];
   temp = temp2 = block[0] - last_dc_val;
 
   if (temp < 0) {
@@ -383,6 +387,7 @@
   /* Emit the Huffman-coded symbol for the number of bits */
   if (! emit_bits(state, dctbl->ehufco[nbits], dctbl->ehufsi[nbits]))
     return FALSE;
+  state->cinfo->dcbits += dctbl->ehufsi[nbits] + (nbits?nbits:0);
 
   /* Emit that number of bits of the value, if positive, */
   /* or the complement of its magnitude, if negative. */
@@ -395,6 +400,7 @@
   r = 0;			/* r = run length of zeros */
   
   for (k = 1; k < DCTSIZE2; k++) {
+    block[jpeg_natural_order[k]] &= state->cinfo->mask[k];
     if ((temp = block[jpeg_natural_order[k]]) == 0) {
       r++;
     } else {
@@ -403,6 +409,7 @@
 	if (! emit_bits(state, actbl->ehufco[0xF0], actbl->ehufsi[0xF0]))
 	  return FALSE;
 	r -= 16;
+        acbits += actbl->ehufsi[0xF0];
       }
 
       temp2 = temp;
@@ -424,11 +431,13 @@
       i = (r << 4) + nbits;
       if (! emit_bits(state, actbl->ehufco[i], actbl->ehufsi[i]))
 	return FALSE;
+      acbits += actbl->ehufsi[i];
 
       /* Emit that number of bits of the value, if positive, */
       /* or the complement of its magnitude, if negative. */
       if (! emit_bits(state, (unsigned int) temp2, nbits))
 	return FALSE;
+      acbits += nbits;
       
       r = 0;
     }
@@ -438,6 +447,9 @@
   if (r > 0)
     if (! emit_bits(state, actbl->ehufco[0], actbl->ehufsi[0]))
       return FALSE;
+  if (r > 0)
+      acbits += actbl->ehufsi[0];
+  state->cinfo->acbits += acbits;
 
   return TRUE;
 }
--- cjpeg.c	1998-03-21 10:21:49.000000000 +0900
+++ cjpeg.c	2007-11-23 12:29:18.000000000 +0900
@@ -411,6 +411,39 @@
       /* Input file is Targa format. */
       is_targa = TRUE;
 
+    } else if (keymatch(arg, "mask", 2)) {
+      /* Mask tables */
+      int i, c;
+      if (++argn >= argc)	/* advance to next argument */
+	usage();
+      i = 0;
+      while ((c = argv[argn][i]) && (i < 16)) {
+          if      ('0'<= c && c <= '9') {c -= '0'; } 
+          else if ('A'<= c && c <= 'F') {c -= 'A'-10; } 
+          else if ('a'<= c && c <= 'f') {c -= 'a'-10; } 
+          else                          {usage(); break;}
+          cinfo->mask[i*4+0] = (c&8)?(~0):(0);
+          cinfo->mask[i*4+1] = (c&4)?(~0):(0);
+          cinfo->mask[i*4+2] = (c&2)?(~0):(0);
+          cinfo->mask[i*4+3] = (c&1)?(~0):(0);
+          i++;
+      }
+      if (i < 16) {
+        c = argv[argn][i-1];
+        if      ('0'<= c && c <= '9') {c -= '0'; } 
+        else if ('A'<= c && c <= 'F') {c -= 'A'-10; } 
+        else if ('a'<= c && c <= 'f') {c -= 'a'-10; } 
+        else                          {usage(); break;}
+        c &= 1;
+        for (;i < 16; i++) {
+          cinfo->mask[i*4+0] = (c)?(~0):(0);
+          cinfo->mask[i*4+1] = (c)?(~0):(0);
+          cinfo->mask[i*4+2] = (c)?(~0):(0);
+          cinfo->mask[i*4+3] = (c)?(~0):(0);
+        }
+      }
+      //for (i=0;i<DCTSIZE2;i++) fprintf(stderr, "%d", cinfo->mask[i]&1);
+
     } else {
       usage();			/* bogus switch */
     }
@@ -483,6 +516,8 @@
   /* Initialize the JPEG compression object with default error handling. */
   cinfo.err = jpeg_std_error(&jerr);
   jpeg_create_compress(&cinfo);
+  cinfo.acbits = cinfo.dcbits = 0;
+  int i; for (i=0;i<DCTSIZE2;i++) cinfo.mask[i]=~0;
   /* Add some application-specific error messages (from cderror.h) */
   jerr.addon_message_table = cdjpeg_message_table;
   jerr.first_addon_message = JMSG_FIRSTADDONCODE;
@@ -599,6 +634,9 @@
 #ifdef PROGRESS_REPORT
   end_progress_monitor((j_common_ptr) &cinfo);
 #endif
+  int blks;
+  blks = cinfo.image_height*cinfo.image_width/DCTSIZE2;
+  fprintf(stderr, " %f %f\n", (double)cinfo.dcbits/blks, (double)cinfo.acbits/blks);
 
   /* All done. */
   exit(jerr.num_warnings ? EXIT_WARNING : EXIT_SUCCESS);