From 0d51d47d24e89280e4ecb23b9a720cef1bf105fd Mon Sep 17 00:00:00 2001 From: Matthias Wandel Date: Sun, 21 Mar 2021 15:18:53 -0300 Subject: [PATCH] Now also show jpeg quality in view.cgi program under view details --- browse/makefile | 3 +- browse/view.c | 2 +- src/jhead.h | 5 ++ src/jpgfile.c | 7 +++ src/jpgqguess.c | 161 ++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 176 insertions(+), 2 deletions(-) create mode 100755 src/jpgqguess.c diff --git a/browse/makefile b/browse/makefile index 36e77cd..94e2896 100755 --- a/browse/makefile +++ b/browse/makefile @@ -15,7 +15,8 @@ OBJECTS_BROWSE = $(OBJ)/view.o \ $(OBJ)/utility.o OBJECTS_SHARED = $(OBJ)/jpgfile.o \ - $(OBJ)/exif.o + $(OBJ)/exif.o \ + $(OBJ)/jpgqguess.o $(OBJ)/%.o:../src/%.c ../src/jhead.h ${CC} -O3 -Wall -c $< -o $@ diff --git a/browse/view.c b/browse/view.c index f677811..2df849b 100755 --- a/browse/view.c +++ b/browse/view.c @@ -162,7 +162,7 @@ void DoJpegView(char * ImagePath) printf(" (Process=%02x",ImageInfo.Process); } } - printf("
\n"); + printf(" Quality=%d
\n", ImageInfo.QualityGuess); if (ImageInfo.ExposureTime || ImageInfo.ISOequivalent || ImageInfo.ApertureFNumber){ printf("Exposure: "); diff --git a/src/jhead.h b/src/jhead.h index c1699ca..39e723c 100644 --- a/src/jhead.h +++ b/src/jhead.h @@ -89,6 +89,8 @@ typedef struct { float yResolution; int ResolutionUnit; + int QualityGuess; + // unsigned ThumbnailOffset; // Exif offset to thumbnail // unsigned ThumbnailSize; // Size of thumbnail. // unsigned LargestExifOffset; // Last exif data referenced (to check if thumbnail is at end) @@ -124,6 +126,9 @@ int Get32s(void * Long); void Put32u(void * Value, unsigned PutValue); void create_EXIF(void); +// Prototypes from jpgqguess.c +void process_DQT (const uchar * Data, int length); + //-------------------------------------------------------------------------- // Exif format descriptor stuff extern const int BytesPerFormat[]; diff --git a/src/jpgfile.c b/src/jpgfile.c index e0e7310..159c011 100755 --- a/src/jpgfile.c +++ b/src/jpgfile.c @@ -143,6 +143,13 @@ static int FindExifInFile (FILE * infile) have_exif = 1; } break; + +#ifdef VIEWCGI // We only care to guess jpg quality fiew view.cgi program. + case M_DQT: + // Use for jpeg quality guessing + process_DQT(Data, itemlen); + break; +#endif case M_SOF0: case M_SOF1: case M_SOF2: diff --git a/src/jpgqguess.c b/src/jpgqguess.c new file mode 100755 index 0000000..072ad10 --- /dev/null +++ b/src/jpgqguess.c @@ -0,0 +1,161 @@ +//-------------------------------------------------------------------------- +// Program to pull the information out of various types of EXIF digital +// camera files and show it in a reasonably consistent way +// +// This module handles guessing of jpeg quality from quantization table +// +// Using code from Andy Spiegl +//-------------------------------------------------------------------------- +#include "jhead.h" + +// for the DQT marker -- start -- +// Sample quantization tables from JPEG spec --- only needed for +// guesstimate of quality factor. Note these are in zigzag order. + +static int std_luminance_quant_tbl[64] = { + 16, 11, 12, 14, 12, 10, 16, 14, + 13, 14, 18, 17, 16, 19, 24, 40, + 26, 24, 22, 22, 24, 49, 35, 37, + 29, 40, 58, 51, 61, 60, 57, 51, + 56, 55, 64, 72, 92, 78, 64, 68, + 87, 69, 55, 56, 80, 109, 81, 87, + 95, 98, 103, 104, 103, 62, 77, 113, + 121, 112, 100, 120, 92, 101, 103, 99 +}; + +static int std_chrominance_quant_tbl[64] = { + 17, 18, 18, 24, 21, 24, 47, 26, + 26, 47, 99, 66, 56, 66, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99 +}; + +static int *deftabs[2] = + { std_luminance_quant_tbl, std_chrominance_quant_tbl }; + +// jpeg_zigzag_order[i] is the zigzag-order position of the i'th element +// of a DCT block read in natural order (left to right, top to bottom). + +static int jpeg_zigzag_order[64] = { + 0, 1, 5, 6, 14, 15, 27, 28, + 2, 4, 7, 13, 16, 26, 29, 42, + 3, 8, 12, 17, 25, 30, 41, 43, + 9, 11, 18, 24, 31, 40, 44, 53, + 10, 19, 23, 32, 39, 45, 52, 54, + 20, 22, 33, 38, 46, 51, 55, 60, + 21, 34, 37, 47, 50, 56, 59, 61, + 35, 36, 48, 49, 57, 58, 62, 63 +}; +// for the DQT marker -- end -- + + + + + +//-------------------------------------------------------------------------- +// Process an DQT (Define Quantization Table) marker. +// +// Code mostly "stolen" from jpegdump: +// Copyright (c) 1992 Handmade Software, Inc. +// by Allan N. Hessenflow +// +// We want to print out the "Approximate quality factor" +//-------------------------------------------------------------------------- +// +// The numbers printed in the `Approximate quality factor' line are as follows: +// Quality: an estimate of the quality factor used when cjpeg was run. +// Scaling factor (scale): mean ratio between quantization table entries +// and JPEG sample table entries, times 100. +// Variance (var): squared standard deviation of the above ratio. +// If this is larger than about 2, then the table is not a simple +// multiple of the standard's sample table, so the file was NOT +// generated by cjpeg and the quality estimate is dubious. +//-------------------------------------------------------------------------- +void process_DQT (const uchar * Data, int length) +{ + int a; + int c; + int tableindex, coefindex, row, col; + unsigned int table[64]; + int *reftable = NULL; + double cumsf = 0.0, cumsf2 = 0.0; + int allones = 1; + + a=2; // first two bytes is length + while (a1){ + printf("DQT: table %d precision %d\n", tableindex, (c>>4) ? 16 : 8); + } + if (tableindex < 2){ + reftable = deftabs[tableindex]; + } + + // Read in the table, compute statistics relative to reference table + if (a+64 > length) { + ErrNonfatal("DQT section too short",0,0); + return; + } + for (coefindex = 0; coefindex < 64; coefindex++) { + unsigned int val; + if (c>>4) { + register unsigned int temp; + temp=(unsigned int) (Data[a++]); + temp *= 256; + val=(unsigned int) Data[a++] + temp; + } else { + val=(unsigned int) Data[a++]; + } + table[coefindex] = val; + if (reftable) { + double x; + // scaling factor in percent + x = 100.0 * (double)val / (double)reftable[coefindex]; + cumsf += x; + cumsf2 += x * x; + // separate check for all-ones table (Q 100) + if (val != 1) allones = 0; + } + } + // If requested, print table in normal array order + if (ShowTags>2){ + for (row=0; row<8; row++) { + printf(" "); + for (col=0; col<8; col++) { + printf("%5u ", table[jpeg_zigzag_order[row*8+col]]); + } + printf("\n"); + } + } + // Print summary stats + if (reftable) { // terse output includes quality + double qual, var; + cumsf /= 64.0; // mean scale factor + cumsf2 /= 64.0; + var = cumsf2 - (cumsf * cumsf); // variance + if (allones){ // special case for all-ones table + qual = 100.0; + }else if (cumsf <= 100.0){ + qual = (200.0 - cumsf) / 2.0; + }else{ + qual = 5000.0 / cumsf; + } + if (ShowTags>1) printf(" "); + + if (ShowTags){ + printf("Approximate quality factor for qtable %d: %.0f (scale %.2f, var %.2f)\n", + tableindex, qual, cumsf, var); + } + if (tableindex == 0){ + ImageInfo.QualityGuess = (int)(qual+0.5); + } + } + } +} +