Репозиторий Sisyphus
Последнее обновление: 1 октября 2023 | Пакетов: 18631 | Посещений: 37885589
en ru br
Репозитории ALT

Группа :: Графика
Пакет: jpegquality

 Главная   Изменения   Спек   Патчи   Исходники   Загрузить   Gear   Bugs and FR  Repocop 

/*************************************************************
Copyright 2005-2007 Hacker Factor, All Rights Reserved.
By Neal Krawetz, www.hackerfactor.com
jpegquality:
Estimate the quality of the JPEG based on the quantization tables.

Neal's personal comment...
"Jpeg, and Exif in particular, is one of the most screwed up formats
that I have ever seen."

Licensing and distribution:
This code is provided as open source but is NOT licensed under the GPL
or other common open source licenses. This code may not be re-licensed
without the explicit, written permission of Neal Krawetz.

This software is provided AS-IS with no warranty expressed or implied.
It may not be accurate and many not be suitable for any specific need.
In locations where a warranty is required, this code may not be used.
No known patent issues exist, but if some are discovered then this
software may not be used. The copyright holder is not liable for any
costs associated with using this software.

This code, or portions of it, may be incorporated into other projects as
long as the code is not re-licensed and the following acknowledgement is
included along with any licensing files, copyright statements, and
source code:
This software includes code from jpegquality by Neal Krawetz,
Hacker Factor Solutions, Copyright 2005-2007.

Compiling instructions:
gcc jpegquality.c -o jpegquality

Usage:
jpegquality file.jpg
You may list one or more jpeg files for analysis.

Revision history:
This code has been stripped out of imgana by Hacker Factor Solutions.
(Imgana does much more than quality analysis, but that's all that is
being released right now.)
*************************************************************/

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <ctype.h>
#include <string.h>

int Debug=0;

#define Abs(x) ((x) < 0 ? -(x) : (x))

/***************************************************
Usage(): Display program usage.
***************************************************/
void Usage (char *Name)
{
fprintf(stderr,"Usage: %s file.jpg [file.jpg file.jpg...]\n",Name);
} /* Usage() */

/***************************************************
ReadJpegMarker(): Jpeg is a weird protocol.
There are markers in the stream.
Markers (1) begin with 0xff and (2) are not followed
by 0x00 or 0xff.
This function reads the next marker.
***************************************************/
int ReadJpegMarker (FILE *Fin)
{
int B1,B2;
long Pos;
long Len;

Pos = ftell(Fin); Len=0;
ReadAgainB1:
B1 = fgetc(Fin); Len++;
while(!feof(Fin) && (B1 != 0xff))
{
B1 = fgetc(Fin); Len++;
}
if (feof(Fin)) return(0);
ReadAgainB2:
B2 = fgetc(Fin); Len++;
if (B2 == 0xff) goto ReadAgainB2;
if (B2 == 0x00) goto ReadAgainB1;
return(B1*256+B2);
} /* ReadJpegMarker() */

/***************************************************
ProcessJPEG(): Process a JPEG for comments
Returns: 0=processed JPEG 1=not a JPEG!
***************************************************/
int ProcessJPEG (FILE *Fin)
{
int Header[15];
int i;
int Type;
int Length;
float Diff=0; /* difference between quantization tables */
float QualityAvg[3] = {0,0,0}; /* allow up to 3 quantization tables */
float QualityF; /* quality as a float */
int QualityI; /* quality as an integer */
float Total;
float TotalNum;
int Precision,Index;

/***
JPEGs are in a fixed file format:
6 bytes = header
Optional global
Set of blocks.
Each block has a type, size, and data.

The quantization tables are type 0xffdb.
Each type 0xffdb may contain 1 or more quantization tables.
The tables define the compression based in luminance (Y),
chrominance-red (Cr) and chrominance-blue (Cb).
- Most programs use two tables: one for Y and one for both Cr and Cb.
Some programs use one 0xffdb with both tables in it, while other
programs use one 0xffdb for each quantization table.
- Some programs (mostly digital cameras) use three tables: Y, Cr, Cb.
I have never seen a case where Cr != Cb, but it is possible.
I usually see one 0xffdb with all 3 tables in it.
However, it is possible to have two or three 0xffdb tags.
This code does not check if there are 2 or 3 tables. It blindly
prints out the average after each chrominance table.
If there are 3 tables, then you should look at the last average
quality since it is computed correctly.

In addition to multiple quantization tables per image, a JPEG may
contain multiple images at different resolutions. This program will
pull out the quantization tables found in each image.
***/

/* read the initial header */
for(i=0; i<2; i++)
{
Header[i] = fgetc(Fin);
}

/* Check the header */
/** JPEG header begins with "ffd8" **/
if ((Header[0] != 0xFF) || (Header[1] != 0xD8))
{
printf("ERROR: Not a supported JPEG format\n");
return(1); /* not a JPEG! */
}

/* Now, search for the quantization tables. */
while(!feof(Fin))
{
/* All "Type" markers begin with "FF" and are followed by anything
except 0x00 or 0xFF. (Very weird standard.) */
Type = ReadJpegMarker(Fin);
if (Type==0) return(0);
/* If it got here, then it is a quantization table, but validate the
length just to be sure. */
Length = fgetc(Fin) * 256 + fgetc(Fin); /* 2 bytes */
/** The length is always too long by 2 bytes. Weird standard. **/
Length = Length - 2;
if (Length < 0) Length=0;

if (Type != 0xffdb)
{
/* not a quantization table */
for(i=0; i<Length; i++) fgetc(Fin);
continue;
}

if (Length%65 != 0)
{
printf("ERROR: Wrong size for quantization table -- this contains %d bytes (%d bytes short or %d bytes long)\n",Length,65-Length%65,Length%65);
}

/* Process quantization tables */
printf("\nQuantization table\n");

/** precision is specified by the higher four bits and index is
specified by the lower four bits **/
while(Length > 0)
{
Precision = fgetc(Fin);
Length--;
Index = Precision & 0x0f;
Precision = (Precision & 0xf0) / 16;
printf(" Precision=%d; Table index=%d (%s)\n",Precision,Index,Index ? "chrominance":"luminance");

/* Quantization tables have 1 DC value and 63 AC values */
/** Average AC table values to estimate compression level **/
Total=0;
TotalNum=0;
while((Length > 0) && (TotalNum<64))
{
i = fgetc(Fin);
if (TotalNum!=0) Total += i; /* ignore first value */
Length--;
/* Show quantization table */
if (((int)TotalNum%8) == 0) printf(" ");
printf("%4d",i);
if (((int)TotalNum%8) == 7) printf("\n");
TotalNum++;
}
TotalNum--; /* we read 64 bytes, but only care about 63 values */
if (Index < 3) /* Only track the first 3 quantization tables */
{
QualityAvg[Index] = 100.0-Total/TotalNum;
printf(" Estimated quality level = %5.2f%%\n",QualityAvg[Index]);
if (QualityAvg[Index] <= 0)
printf(" Quality too low; estimate may be incorrect.\n");
/* copy over the Q tables for initialization (in case Cr==Cb) */
for(i=Index+1; i<3; i++) QualityAvg[i]=QualityAvg[Index];
}

/*****
Technically, JPEG uses YCrCb.
R = Y + (R-Y) = Y + Cr
G = Y - 0.51(R-Y) - 0.186(B-Y) = Y - 0.51Cr -0.186Cb
B = Y + (B-Y) = Y + Cb
and in reverse (YCrCb):
Luminance = Y = 0.299R + 0.587G + 0.114B
Cr = R-Y = R - (0.299R + 0.587G + 0.114B)
Cb = B-Y = B - (0.299R + 0.587G + 0.114B)
The quantization tables are based on Y and CrCb and
they mainly differ by a factor of 0.51 (from determining G).
Thus, we compute the difference using 1 - 0.51 = 0.49.
The results will be off by a fraction, but that's noise
considering all of the integer rounding.
*****/
if (Index > 0)
{
/* Diff is a really rough estimate for converting YCrCb to RGB */
Diff = Abs(QualityAvg[0]-QualityAvg[1]) * 0.49;
Diff += Abs(QualityAvg[0]-QualityAvg[2]) * 0.49;
/* If you know that Cr==Cb and don't mind a little more error,
then you can take a short-cut and simply say
Diff = Abs(QualityAvg[0]-QualityAvg[1]); */
QualityF = (QualityAvg[0]+QualityAvg[1]+QualityAvg[2])/3.0 + Diff;
QualityI = (QualityF+0.5); /* round quality to int */
printf("Average quality: %5.2f%% (%d%%)\n",QualityF,QualityI);
} /* if all tables loaded */
} /* for each set of 65 bytes */
} /* while read file */
return(0);
} /* ProcessJPEG() */

/**************************************************************/
int main (int argc, char *argv[])
{
int c;
FILE *Fin;
int rc;

/* process command lines */
/** Uh, imgana has command line options, but jpegquality does not **/
opterr=0;
while ((c=getopt(argc,argv,"")) != -1)
{
switch (c)
{
default:
Usage(argv[0]);
exit(-1);
}
}

/* process each file */
if (argc - optind < 1)
{
Usage(argv[0]);
exit(-1);
}

for( ; optind < argc; optind++)
{
Fin = fopen(argv[optind],"rb");
if (!Fin)
{
fprintf(stderr,"ERROR: failed to open %s\n",argv[optind]);
continue;
}
printf("#File: %s\n",argv[optind]);
rc=ProcessJPEG(Fin);
fclose(Fin);
if (optind+1 < argc) printf("\n");
}
return(0);
} /* main() */

 
дизайн и разработка: Vladimir Lettiev aka crux © 2004-2005, Andrew Avramenko aka liks © 2007-2008
текущий майнтейнер: Michael Shigorin