Talk:JPEG

From Wikipedia, the free encyclopedia
Jump to: navigation, search
Former good article nominee JPEG was a good articles nominee, but did not meet the good article criteria at the time. There are suggestions below for improving the article. Once these issues have been addressed, the article can be renominated. Editors may also seek a reassessment of the decision if they believe there was a mistake.
October 28, 2007 Good article nominee Not listed
WikiProject Computing / Software (Rated B-class, High-importance)
WikiProject icon This article is within the scope of WikiProject Computing, a collaborative effort to improve the coverage of computers, computing, and information technology on Wikipedia. If you would like to participate, please visit the project page, where you can join the discussion and see a list of open tasks.
B-Class article B  This article has been rated as B-Class on the project's quality scale.
 High  This article has been rated as High-importance on the project's importance scale.
Taskforce icon
This article is supported by WikiProject Software (marked as High-importance).
 


Vulnerabilities[edit]

Should this vulnerability be added to this article? As with many compressible file formats, the relatively small size of some JPEG files can hide the requirements to view or process some JPEG files. For example, the webpage has a link to a 618KB JPG file of a 10,000 x 10,000 pixel 24-bit image, which if a program converted to an uncompressed format would require at least 300MB of memory or file storage. • SbmeirowTalk • 08:08, 22 November 2014 (UTC)

If this topic isn't added to this article, should we create an article similar in concept to Zip bomb, E-mail bomb, Billion laughs articles. Possibly name the article "JPEG bomb"? • SbmeirowTalk • 08:16, 22 November 2014 (UTC)

Has anyone come across an article/blog on the internet that describes this vulnerability? • SbmeirowTalk • 08:19, 22 November 2014 (UTC)

It's probably not DCT, it's flood fill ![edit]

You make a balanced flood fill over the source image that aborts when the average of all covered pixels differs with the current pixel by more than a tolerance limit. The covered area is then filled with the average value of all of it's pixels. When you compress the result with RLE or ZIP, you'll see that a lot of redundancy can be won without completely ruining the image. When the resulting image doesn't look that good or photorealistic, you can still interpolate the areas with sinus or cosinus formed shades and it will get a bit better.

Does not explain compression levels 0-9 ?[edit]

I came here expecting to find some topic explaining the levels that are commonly used in picture software for jpeg. But there's none. — Preceding unsigned comment added by 218.252.34.131 (talk) 03:35, 28 May 2015 (UTC)

the truth could perhaps cause a economical loss of billions of dollars, but i don't know it for real[edit]

Here you got your shitty lame JPEG. It's like "Painting By Numbers". First write a bitmask for the borders of each area into the first file, then write the amounts of bytes skipped and then the luma value for the flood fill of the corresponding area in the another file ( here: dumped out at the command line ) in exchange. If i didn't make any programming mistakes, then this already beats JPEG. Compress the output with RAR and then compare it with JPEG ... I cannot test it because i haven't already wrote the decoder.


Jetzt wird der Flood-Fill in alle Richtungen gleichmaessig ausgebreitet. Er bricht ab, sobald der aktuelle Wert gegenueber dem Mittelwert der er- fassten Pixel eine Schwelle ueberschreitet. Die Schwelle gibt man an der Kommandozeile vom Flutprogramm hinter den Namen der Eingabe- und der Ausgabedatei danach an. Man braucht ein Windows-Bitmap mit der Aufloesung 320x200 und einer linearen Graustufentabelle. Bei dem loescht man den Header raus und tut es danach mit dem ersten Programm flutend filtern. Das Ergebnis packt man hinterher mit RAR oder WinZip und vergleicht die Dateigroesse. Wenn man hinterher mit dem zweiten Programm sinusfoermig die Uebergaenge zwischen den Flaechen der Ausgabe des ersten Programmes interpoliert ( Kommandozeile nacheinander Eingabe- und Ausgabedatei ) und anschliessend den rausgeloeschten BMP-Header darankopiert, kann man es direkt mit einem gleich grossen JPEG vergleichen. Dann habe ich gesehen, dass wenn man bei einem Bild einfach die Aufloesung verringert, danach die Farbzahl reduziert ( bei Graustufenbildern kann man naemlich auf 32 Farben runterposterisieren, und es sieht immer noch gut aus ) und es dann mit RAR packt, es auch eine sehr hohe Kompression ergibt. Ob das JPEG wirklich besser ist, koennte auch ein subjektiver Eindruck sein. Mehr Information ist auf jeden Fall nicht drin.

Jetzt wurde das Flutprogramm so umgebaut, dass es nur noch die Raender der zu fuellenden Flaeche in einer binaeren Bitmaske markiert und den Mittelwert der Koordinaten, an denen die Flutung startete, an der Kommandozeile ausgibt. Also genau wie "Malen Nach Zahlen". Die Umrandung der zu fuellenden Flaeche und mittendrin der Fuellwert.

Die Bitmaske packt es schon ganz ordentlich. Braucht nur 4KB bei nahezu verlustfreier Quaelitaet. Bloss die Lumawerte brauchen einen Haufen Speicher, auch weil man die Koordinaten, an denen der Flood-Fill beim Dekomprimieren startet, mitspeichern muss.

Ich habe naemlich den schweren Verdacht, dass JPEG eine Mogelpackung ist. Es koennte sich zum Beispiel um Betriebsgeheimnisse handeln.

((x+ len )*(x+len) - x*x ) / len entspricht ( 2*len*x + len*len ) / len

Wenn aber jetzt beim Differentialquotient x gegen unendlich geht, kann man len auch nicht rausschmeissen, wenn sie gegen 0 strebt Schon da koennte es haken. Ein Fundament der DCT ist ja die Differentialrechnung. Aber schon die kann niemand wirklich kapieren. Und dann noch Limes--Miles (=Soldat). Ihr duckmaeusert vor der Autoritaet der "hohen Mathematiker", weil ihr das Denken lieber Anderen ueberlasst ... ? Ich bin mir nicht sicher, aber es koennte sich bewahrheiten ... immerhin bleiben bei meiner Version die Kanten scharf, auch wenn es relativ haesslich aussieht. Aber fuer den ersten Versuch--es wurden ja noch nicht alle Register gezogen...


--Flood Fill-Filter-- /*

 Man erzeugt ein 256-Farben-Graustufen-BMP und loescht den Header raus.
 Der Graustufenheader muss eine lineare Graustufenpalette enthalten.
 Der Header, das sind die ersten paar Bytes, sodass unten 64000 Byte uebrigbleiben.
 Mit dem Hex-Editor kann man es meist gut erkennen, wo er aufhoert.

 Das Bitmap muss die Aufloesung 320x200 haben.

 An der Kommandozeile gibt man ein: Programmname [Eingangsrohdatei ohne Header]
  [Ausgabedatei].

  Man kann versuchen, die Ausgabedatei mit RAR oder ZIP zu komprimieren und sieht:
  es ist genauso gut wie JPEG.

  Dann kopiert man den alten Header vor die Ausgabedatei und das Bitmap ist fertig.

  Mit SCHWELLE kann man die Toleranzschwelle fuer den Flood-Fill festlegen.

  Ganz einfach: Flood-Fill, bis der tiefste erfasste Wert mit dem Hoechsten eine
  frei waehlbare Diskrepanz erreicht.
  Den vom Flood-Fill erfassten Bereich fuellt man mit dessen arithmetischen Mittel-
  Wert.

  MPEG ueberlappt Folgebilder zu einem 3D-Array und tut da dasselbe.
  Auf die Bewegungssuche ist geschissen. Sie braucht nur einen Haufen Rechenleistung.

  Sie kochen alle nur mit Wasser.


  • /


  1. include <fcntl.h>
  2. include <stdio.h>
  3. include <stdlib.h>
  4. include <math.h>
  1. define SCHWELLE schwelle
  2. define SHIFT 3
  3. define TOINIT 257

unsigned char bild[64000]; unsigned char maske[64000]; unsigned char linemaske[64000]; unsigned char ausgabe[64000];

int iter_buf[64000][4]; int iter_count;

float mvalue, mvalue_sum; float hellst, dunkelst; long int rec_count; signed long int abbruch; long int highest_depth;

long int schwelle;

void backsort(void) {

int count1, count2;
int buf[4];

count2=0;

while ( count2 < iter_count )
{

  count1=iter_count-1;
 while ( count1 > count2 )
 {

 if ( iter_buf[count1][2] < iter_buf[count1-1][2] )
  {

    buf[0]=iter_buf[count1-1][0];
    buf[1]=iter_buf[count1-1][1];
    buf[2]=iter_buf[count1-1][2];
    buf[3]=iter_buf[count1-1][3];

    iter_buf[count1-1][0]=iter_buf[count1][0];
    iter_buf[count1-1][1]=iter_buf[count1][1];
    iter_buf[count1-1][2]=iter_buf[count1][2];
    iter_buf[count1-1][3]=iter_buf[count1][3];

    iter_buf[count1][0]=buf[0];
    iter_buf[count1][1]=buf[1];
    iter_buf[count1][2]=buf[2];
    iter_buf[count1][3]=buf[3];

  }

  count1--;

 }

 count2++;

}

/* Kettendumpen debug

count2=0;
while( count2 < iter_count )
{
 printf("Position %d X: %d Y: %d Aktivierung %d Zaehlerwert %d\n",
        count2, iter_buf[count2][0], iter_buf[count2][1], iter_buf[count2][3],
         iter_buf[count2][2] );

 count2++;
}

bis hier */

}


void insert(int x, int y, int depth) {

 float buf;

if ( hellst==TOINIT ) hellst=bild[x+y*320];
if ( dunkelst==TOINIT ) dunkelst=bild[x+y*320];

 if ( bild[x+y*320] > hellst )
   if ( abs( (float)bild[x+y*320]-dunkelst ) < SCHWELLE  )
       hellst=bild[x+y*320];
    /*    else return; */
    
 if ( bild[x+y*320] < dunkelst )
   if ( abs( (float)hellst-bild[x+y*320] ) < SCHWELLE  )
       dunkelst=bild[x+y*320];
    /*    else return; */


    if ( rec_count > 0 )
    {
     buf= mvalue_sum/rec_count;


      /*
     if ( fabs ( hellst-buf ) > SCHWELLE ) { return; }
     if ( fabs ( dunkelst-buf ) > SCHWELLE ) { return; }
       */


     if ( rec_count > 1024 ){ linemaske[x+y*320]=1 ; return ; }


      if ( fabs ( bild[x+y*320] - buf ) > SCHWELLE  ){ linemaske[x+y*320]=1 ; return; }


    }


 mvalue_sum+=bild[x+y*320];
 rec_count++;

  maske[x+y*320]=1;


iter_buf[iter_count][0]=x;
iter_buf[iter_count][1]=y;
iter_buf[iter_count][2]=depth;
iter_buf[iter_count][3]=0;
iter_count++;

}


int flood(int x, int y, int depth ) {

 int buf2; int buf3;

 if ( iter_count==0 ) insert ( x, y, depth );


  buf2=0; while ( iter_buf[buf2][3]==1 ) buf2++;

x=iter_buf[buf2][0];
y=iter_buf[buf2][1];
depth=iter_buf[buf2][2];
iter_buf[buf2][3]=1;


/* printf("%d %d \n", x,y ); */


   if ( x < 319 && y < 199 ) if ( maske[x+1+(y+1)*320]==0 )
   {
    insert( x+1, y +1, iter_buf[0][2]+1 );

    }
   if ( x > 0 && y > 0)  if ( maske[x-1+(y-1)*320]==0 )
   {
    insert( x-1, y -1, iter_buf[0][2]+1 );
 
   }
   if ( y < 199 && x > 0) if ( maske[(x-1)+(y+1)*320]==0 )
   {
    insert( x-1, y+1 , iter_buf[0][2]+1 );

   }
   if ( y > 0 && x < 319 ) if ( maske[x+1+(y-1)*320]==0 )
   {
    insert( x+1, y-1 , iter_buf[0][2]+1 );

   }


   if ( x < 319 ) if ( maske[x+1+y*320]==0 )
   {
    insert( x+1, y , iter_buf[0][2]+1 );

    }
   if ( x > 0 )  if ( maske[x-1+y*320]==0 )
   {
    insert( x-1, y , iter_buf[0][2]+1 );
 
   }
   if ( y < 199 ) if ( maske[x+(y+1)*320]==0 )
   {
    insert( x, y+1 , iter_buf[0][2]+1 );

   }
   if ( y > 0 ) if ( maske[x+(y-1)*320]==0 )
   {
    insert( x, y-1 , iter_buf[0][2]+1 );

   }


      abbruch= -1;
  buf3=0; while ( buf3 < iter_count ) { if ( iter_buf[buf3][3]==0 ) abbruch=1; buf3++; }


}


int main(int argc, char*argv[]) {

 FILE *input, *output;
 int n=0, n2=0, n_old=0;

  int x,y;
  unsigned int buf;
  unsigned char bildcopy[64000];
 
 
 input=fopen(argv[1],"rb");
 
 if ( argc != 4 )
 {
  printf("Falsche Anzahl Argumente!\n");
  return 1;
 
 }

 schwelle=atoi(argv[3] );

 if ( input == NULL )
 {
  printf("Datei nicht gefunden!\n");
  return 1;
 }


 output=fopen(argv[2],"wb");
 if ( output==NULL )
 {
  printf("E/A-Fehler.\n");
  return 1;
 }

fread( bild, sizeof(unsigned char), 64000, input);
fclose(input);

/*
 n=0;
while(n<64000) { maske[n]=0; linemaske[n]=0;n++; }

  y=0;
  while ( y < 199 )
  {
   x=0;
   while ( x < 319 )
   {
     buf= (bild[x+y*320]+bild[x+1+y*320]+
           bild[x+(y+1)*320]+bild[x+1+(y+1)*320]
           )/4;

      bildcopy[x+y*320]=buf;

    x++;
   }
   y++;
  }

 n=0;
 while ( n < 64000 )bild[x+y*320]=bildcopy[x+y*320], n++;
 */

n2=0;
while ( n2 < 64000)
{
 n2=0;
 rec_count=0;
 abbruch=0;
 highest_depth=1;

 mvalue_sum=0;
 hellst=TOINIT, dunkelst=TOINIT;

 while( maske[n2]!=0 && n2 < 64000) n2++;
 if ( n2== 64000 ) break;

  while ( n2 - n_old > 254 )printf("%c", n2-n_old > 254 ? 255 : 254), n_old+=254;

  n_old=n2;

  iter_count=0;

  do{  flood(n2%320, n2/320 , 1 ); backsort(); }  while ( abbruch >= 0 ) ;

 if ( rec_count > 0 ) mvalue=mvalue_sum/rec_count;


   printf("%c", (unsigned char)mvalue );

 n=0;
 while(n < 64000 )
 {
  if ( maske[n]==1 ) maske[n]=2;
  if ( linemaske[n]==1 )
  {
   if ( n%8 == 0 )
    ausgabe[n/8]|= 1;
   else
   if ( n%8 == 1 )
    ausgabe[n/8]|= 2;
   else
   if ( n%8 == 2 )
    ausgabe[n/8]|=4;
   else
   if ( n%8 == 3 )
    ausgabe[n/8]|= 8;
   else
   if ( n%8 == 4 )
    ausgabe[n/8]|= 16;
   else
   if ( n%8 == 5 )
    ausgabe[n/8]|= 32;
   else
   if ( n%8 == 6 )
    ausgabe[n/8]|= 64;
   else
   if ( n%8 == 7 )
    ausgabe[n/8]|= 128;

  }

  n++;
 }
 
 
 n2++;
}  

fwrite ( ausgabe, sizeof(unsigned char), 8000, output );
/* You could as well write the filtered bitmap into the output file */
fflush(output );

 fclose(output);

}

--Sinus interpolation afterwards ( might not be necessary ) --

  1. include <stdio.h>
  2. include <math.h>
  3. include <fcntl.h>

int main(int argc, char*argv[] ) {

FILE *input, *output;

 unsigned char bild[64000], ausgabe[64000];

 float length, lengthbuf, prevdot, line, nexdot, buf, buf2;
 float counter;
 int x,y;

 input=fopen(argv[1],"rb");
 
 if ( argc != 3 )
 {
  printf("Falsche Anzahl Argumente!\n");
  return 1;
 
 }
 if ( input == NULL )
 {
  printf("Datei nicht gefunden!\n");
  return 1;
 }


 output=fopen(argv[2],"wb");
 if ( output==NULL )
 {
  printf("E/A-Fehler.\n");
  return 1;
 }
 
 fread( bild, sizeof(unsigned char), 64000, input);



 y=0;
  while ( y < 200 )
  {
   x=0;
   while( x < 318 )
   {
    length=0;
    while ( bild[x+y*320]== bild[x+1+y*320] && x < 318 ) length++, x++;
    nexdot=bild[x+1+y*320], line=bild[x+y*320];

    x-=length;

     counter=0.0;

      lengthbuf=length;

     if ( lengthbuf != 0 )
     {
      length=0;
      while ( length <= lengthbuf )
      {

        buf2= length/lengthbuf;
        if ( buf2 < 0 ) buf2=0;
        else if ( buf2 > 1 ) buf2=1;


              buf=                     ( sin( (buf2)*1.59 ) * nexdot +
                                       (1.01 - sin( (buf2)*1.59 )) * line  );

              if ( buf < 0 ) buf=0, printf("zu klein\n",buf); if ( buf > 255 ) buf=255,printf("zu gross\n",buf);
           ausgabe[x+y*320]=buf/4;

        length++;
       x++;
      }

     }
     else
     {
      ausgabe[x+y*320]=bild[x+y*320]/4;
      x++;
     }

   }
   y++;

   }


  /* Vertikal 1 */


   x=0;
  while ( x < 320 )
  {
   y=0;
   while( y < 198 )
   {
    length=0;
    while ( bild[x+y*320]== bild[x+(y+1)*320] && y < 198 ) length++, y++;
    nexdot=bild[x+(y+1)*320], line=bild[x+y*320];

    y-=length;

     counter=0.0;

      lengthbuf=length;

     if ( lengthbuf != 0 )
     {
      length=0;
      while ( length <= lengthbuf )
      {

        buf2= length/lengthbuf;
        if ( buf2 < 0 ) buf2=0;
        else if ( buf2 > 1 ) buf2=1;


              buf=                     ( sin( (buf2)*1.59 ) * nexdot +
                                       (1.01 - sin( (buf2)*1.59 )) * line  );

              if ( buf < 0 ) buf=0, printf("zu klein\n",buf); if ( buf > 255 ) buf=255,printf("zu gross\n",buf);
           ausgabe[x+y*320]+=buf/4;


        length++;
       y++;
      }

     }
     else
     {
      ausgabe[x+y*320]+=bild[x+y*320]/4;
      y++;
     }

   }
   x++;

   }





 /* Horizontal 2 */


    y=0;
  while ( y < 200 )
  {
   x=319;
   while( x > 1 )
   {
    length=0;
    while ( bild[x+y*320]== bild[x-1+y*320] && x > 1 ) length++, x--;
    nexdot=bild[x-1+y*320], line=bild[x+y*320];

    x+=length;

     counter=0.0;

      lengthbuf=length;

     if ( lengthbuf != 0 )
     {
      length=0;
      while ( length <= lengthbuf )
      {

        buf2= length/lengthbuf;
        if ( buf2 < 0 ) buf2=0;
        else if ( buf2 > 1 ) buf2=1;


              buf=                     ( sin( (buf2)*1.59 ) * nexdot +
                                       (1.01 - sin( (buf2)*1.59 )) * line  );

              if ( buf < 0 ) buf=0, printf("zu klein\n",buf); if ( buf > 255 ) buf=255,printf("zu gross\n",buf);
           ausgabe[x+y*320]+=buf/4;

        length++;
       x--;
      }

     }
     else
     {
      ausgabe[x+y*320]+=bild[x+y*320]/4;
      x--;
     }

   }
   y++;

   }


  /* Vertikal 2 */


   x=0;
  while ( x < 320 )
  {
   y=199;
   while( y > 1 )
   {
    length=0;
    while ( bild[x+y*320]== bild[x+(y-1)*320] && y > 1 ) length++, y--;
    nexdot=bild[x+(y-1)*320], line=bild[x+y*320];

    y+=length;

     counter=0.0;

      lengthbuf=length;

     if ( lengthbuf != 0 )
     {
      length=0;
      while ( length <= lengthbuf )
      {

        buf2= length/lengthbuf;
        if ( buf2 < 0 ) buf2=0;
        else if ( buf2 > 1 ) buf2=1;


              buf=                     ( sin( (buf2)*1.59 ) * nexdot +
                                       (1.01 - sin( (buf2)*1.59 )) * line  );

              if ( buf < 0 ) buf=0, printf("zu klein\n",buf); if ( buf > 255 ) buf=255,printf("zu gross\n",buf);
           ausgabe[x+y*320]+=buf/4;


        length++;
       y--;
      }

     }
     else
     {
      ausgabe[x+y*320]+=bild[x+y*320]/4;
      y--;
     }

   }
   x++;

   }


   x=0;
   while ( x < 64000 ) ausgabe[x]= ( ausgabe[x]+ausgabe[x]+bild[x])/3 , x++ ;


 fwrite( ausgabe, sizeof(unsigned char), 64000, output);


 fclose(input), fclose(output);
 

}