[alt.graphics.pixutils] solution: pixel aspect ratio in GIF images

ahg@mentor.cc.purdue.edu (Allen Braunsdorf) (07/17/90)

In article <9894@pt.cs.cmu.edu> tgl@zog.cs.cmu.edu (Tom Lane) writes:
>In article <9866@pt.cs.cmu.edu>, I asked:
>> The GIF documentation that I have makes no mention of the question of
>> pixel shape.  Is there any recognized convention about whether a GIF
>> image is set up for square or non-square pixels, and what the assumed
>> pixel aspect ratio is in the latter case?
>
>There seems to be general agreement that there isn't a recognized
>standard for pixel aspect ratio.

True and unfortunate.  An image format that claims to be for
interchange is worthless for exactly that purpose because of this
fact.

Watch my lips:  Putting an image into GIF without somehow documenting
the aspect ratio destroys the image.  The originally intended image
cannot be recovered with certainty.

>Erik Talvola (talvola@janus.Berkeley.EDU) points out that a GIF picture
>of size 320x200 pixels is almost surely intended for an IBM CGA display,

or a Commodore 64 or an Atari ST or an Amiga....  I know for a fact
that my 64 and my Amiga make different sized 320 x 200 screens on the
same monitor (the 64's is narrower).  Not to mention that the Amiga can
make three screens that are all 320 x 200, but have different aspect
ratios.

>It seems to me that a workable solution for GIF files would be to
>standardize on Brian's suggestion: let the screen dimensions in the
>file header represent a pixel area that fills a 4x3 physical area.
>A GIF reader could then rescale the image appropriately for its own
>screen.
>
>This is something of a hack, but it has several nice properties:
>	1. The file format doesn't change.
>	2. Existing GIF readers don't break (since they almost
>	   surely ignore the screen dimension info).
>	3. A large fraction of the GIF files out there have correct
>	   info in them already (namely, all the IBM-screen files).
>
>The main disadvantage is that readers using this convention would have
>to guard against computing a bogus aspect ratio when given a GIF file
>that doesn't adhere to the convention.  One easy defense is to reject
>any computed ratio that falls outside the expected range (probably
>1.0 to 1.4 would cover it).  A command-line switch to override the
>aspect ratio adjustment would be a good idea too.

Nonsense.  I make lots of images for display on my Amiga that have
pixels nearly twice as wide as they are tall.  Atari 8 bits have modes
where the pixels are far wider than that.  A PostScript printer can
print a picture of >any< size with >any< pixel aspect ratio.

This "solution" is almost as narrow minded and silly as GIF is to begin
with.  That's by no means an attack on any of the people in this
discussion, only on the idea that you can somehow determine the aspect
ratio of an unknown image.  It just can't be done.

The only real solution is to tell the aspect ratio of the image when
you post it or whatever.  If somebody is going to send me a GIF, I
always tell them to send the aspect ratio along with it, or forget it.

Archives typically have a file that shows how many colors each file has,
why not another column for pixel aspect ratio:

clown.gif	657 x 395 x 8 (1:1)
shuttle.gif	657 x 395 x 8 (12:7)
zebra.gif	657 x 395 x 8 (4:13)

That way nobody has to guess.  If you guessed from just the dimensions
of those images, you would have been wrong at least twice, right?

>Any comments?

Yeah, in general, I'm more interested in the pixel aspect ratio (the
shape of the pixels) than in the image aspect ratio.  Either can be
computed from the other for a known image size, but I prefer the pixel
dimensions.

Why?  Because on many displays, the image size is variable, but the
pixel aspect ratio is not.  Again, on my Amiga I'm free to make an
screen of nearly any size, but I only have three (four really)
different kinds of pixels.  Posting the image aspect ratio with each of
my images would be very confusing as it varies so much, but the pixel
aspect ratio stays the same.

I often move images from one of my machines to another.  I use the
pixel aspect ratios to make any necessary corrections.  That way, the
images don't get distorted any more than they need to.  If I didn't
have the aspect ratio of the image documented, or didn't know the
aspect ratio of the target device, I could not do this.

Assumption of aspect ratio is an evil thing.  If you find you do it
often, you should probably consider a different image storage format.
Try IFF ILBM's, coding it up as a PostScript program, or even TIFF.

I don't like the complexities of TIFF, but at least I >can< decode a
TIFF.  No such luck with a GIF.  (Though it is easy to get the
information that is encoded in a GIF, it's impossible to get what's
just not there.)

GIF's a toy, and a dangerous one.  If you want to play with it, use a
warning sticker that contains the (pixel, or at least image) aspect
ratio.  That way, people won't have to slaughter your images.

---
Allen Braunsdorf			Purdue University Computing Center
cc.purdue.edu!ahg			UNIX Systems Programmer

tgl@zog.cs.cmu.edu (Tom Lane) (07/17/90)

In article <12198@mentor.cc.purdue.edu>, ahg@mentor.cc.purdue.edu
(Allen Braunsdorf) writes (in response to a previous post of mine):
> >It seems to me that a workable solution for GIF files would be to
> >standardize on Brian's suggestion: let the screen dimensions in the
> >file header represent a pixel area that fills a 4x3 physical area.
> >A GIF reader could then rescale the image appropriately for its own
> >screen.
>
> This "solution" is almost as narrow minded and silly as GIF is to begin
> with.  That's by no means an attack on any of the people in this
> discussion, only on the idea that you can somehow determine the aspect
> ratio of an unknown image.  It just can't be done.

How about not using "fighting words" when you don't understand the proposal?

What I suggested was that the original creator of a GIF image document the
image's pixel aspect ratio by redefining the meaning of a currently useless
pair of numbers.  It should be obvious that there is no way to regenerate
this info (except by "eyeball adjustment") at any later date.

> Watch my lips:  Putting an image into GIF without somehow documenting
> the aspect ratio destroys the image.  The originally intended image
> cannot be recovered with certainty.

Exactly.  What I'm proposing is a way to include that number without
breaking the existing file format.

> >The main disadvantage is that readers using this convention would have
> >to guard against computing a bogus aspect ratio when given a GIF file
> >that doesn't adhere to the convention.  One easy defense is to reject
> >any computed ratio that falls outside the expected range (probably
> >1.0 to 1.4 would cover it).
> 
> Nonsense.  I make lots of images for display on my Amiga that have
> pixels nearly twice as wide as they are tall.  Atari 8 bits have modes
> where the pixels are far wider than that.

OK, I wasn't aware of that.  That means the range-check couldn't be as
tight as I suggested, but it doesn't render the proposal unworkable.

It would be easy to extend my proposal so that image creators could
unambiguously indicate that they were supplying aspect ratio data per the
new interpretation:  just put small numbers, say less than 64, into the
"screen dimensions" fields.  A reader seeing "4x3" could be certain that it
was computing a valid aspect ratio correction, whereas if it saw "320x200"
it might want to confirm the correction with its user.

> Assumption of aspect ratio is an evil thing.  If you find you do it
> often, you should probably consider a different image storage format.
> Try IFF ILBM's, coding it up as a PostScript program, or even TIFF.

I agree, but GIF is sufficiently popular and storage-efficient that
it's not likely to go away just because I don't like it.  Better to
offer a constructive and reasonably painless proposal for fixing it.

-- 
				tom lane
Internet: tgl@cs.cmu.edu
UUCP: <your favorite internet/arpanet gateway>!cs.cmu.edu!tgl
BITNET: tgl%cs.cmu.edu@cmuccvma
CompuServe: >internet:tgl@cs.cmu.edu

ahg@mentor.cc.purdue.edu (Allen Braunsdorf) (07/18/90)

In article <9922@pt.cs.cmu.edu> tgl@zog.cs.cmu.edu (Tom Lane) writes:
>In article <12198@mentor.cc.purdue.edu>, ahg@mentor.cc.purdue.edu
>(Allen Braunsdorf) writes (in response to a previous post of mine):
>
>How about not using "fighting words" when you don't understand the proposal?
>
>What I suggested was that the original creator of a GIF image document the
>image's pixel aspect ratio by redefining the meaning of a currently useless
>pair of numbers.  It should be obvious that there is no way to regenerate
>this info (except by "eyeball adjustment") at any later date.
>
>> Watch my lips:  Putting an image into GIF without somehow documenting
>> the aspect ratio destroys the image.  The originally intended image
>> cannot be recovered with certainty.
>
>Exactly.  What I'm proposing is a way to include that number without
>breaking the existing file format.

But it does break.  The screen size is in there so that multiple images
stored in one file have a place to go.  My GIF decoder makes a frame as
big as the screen and then renders each image into this frame.  And
it's not just me- that's the right thing to do.  If you record a bogus
screen size, you could really break things.  Even if it didn't break,
the picture might have a really funny border around it.

Multiple images in one file allow you to make a picture with many
colors by breaking it up into little tiles.  That way I could get more
than 256 colors in a picture if I wanted.  It's standard and it's
useful.  It's especially useful for broadcasting several little
"window" pictures to a terminal.  (I'm sure that was the original
idea.)

Since I don't use GIF locally here, my tool (giftorgb) creates three
files (foo.[rgb]) that are just raw byte dumps of the frame.  From
that, I can process the image any way I need and then recode it into
whatever format later.

>I agree, but GIF is sufficiently popular and storage-efficient that
>it's not likely to go away just because I don't like it.  Better to
>offer a constructive and reasonably painless proposal for fixing it.

Another poster proposed adding a new '!' block to the format.  That's
the right way, and a good idea.  My comments about that are under
separate cover.

---
Allen Braunsdorf			Purdue University Computing Center
cc.purdue.edu!ahg			UNIX Systems Programmer

tgl@zog.cs.cmu.edu (Tom Lane) (07/18/90)

In article <10454@odin.corp.sgi.com>, jindak@surfside.esd.sgi.com (Chris
Schoeneman) writes:
> ... instead of messing with the format (at least the
> format's meaning), why not extend GIF within it's framework?  GIF
> allows for "extension blocks" which all readers must accept.  So I
> propose the following extension:
> 
> [ straightforward extension block defining assumed pixel aspect ratio ]

That's the obvious solution, and certainly the logically cleanest one.
Why did I propose hacking up the screen size values instead?  Because
*not all GIF readers handle extension blocks*.  In particular, the
two that I have here (Patrick Naughton's gif2ras and xgif) choke on
any extension block.  These particular two seem to be descended from
a common ancestor, which may well have other progeny.  Sure, these
readers violate the published standard; but they are pretty widely used.

Meanwhile, in article <12234@mentor.cc.purdue.edu> ahg@mentor.cc.purdue.edu
(Allen Braunsdorf) writes:
>The screen size is in there so that multiple images
>stored in one file have a place to go.  My GIF decoder makes a frame as
>big as the screen and then renders each image into this frame.

[I assume Allen means "makes a frame as big as the logical screen size
indicated in the file header", not "as big as the display the decoder
is using".  I could argue that it wouldn't be difficult to handle
multiple images this way without using the file's screen size, but
that's really not the point here.]

So what we've got are two different proposals, each of which breaks
a different subset of the GIF readers currently out there.
On aesthetic grounds the extension-block approach is certainly
superior, but I'm not at all sure that it is superior on backwards
compatibility grounds.  It would be nice to get some hard data on the
following points:
	1. How many existing GIF readers pay any attention to the
	   screen size numbers (as opposed to the image size)?
	2. How many existing GIF readers correctly skip over
	   unrecognized extension blocks?
I don't have any easy way of finding out either of these things.
Perhaps someone on the net knows the answers.

Don't get me wrong --- I'd be glad to see Chris's proposal (or *any*
solution) adopted.  I just think that a high degree of backwards
compatibility is going to be necessary to make the thing fly.
I suspect that redefining the screen size fields would create fewer
compatibility problems than adding an extension block.

-- 
				tom lane
Internet: tgl@cs.cmu.edu
UUCP: <your favorite internet/arpanet gateway>!cs.cmu.edu!tgl
BITNET: tgl%cs.cmu.edu@cmuccvma
CompuServe: >internet:tgl@cs.cmu.edu

jef@well.sf.ca.us (Jef Poskanzer) (07/18/90)

In the referenced message, jindak@surfside.esd.sgi.com (Chris Schoeneman) wrote:
}GIF allows for "extension blocks" which all readers must accept.  So I
}propose the following extension:
}
}   7 6 5 4 3 2 1 0   Byte #
}  +---------------+
}  |0 0 1 0 0 0 0 1|    1        '!' - GIF extension block introducer
}  +---------------+
}  |0 1 0 1 0 0 1 0|    2        'R' - For 'aspect Ratio'
}  +---------------+
}  |0 0 0 0 0 0 1 0|    3         2  - Two bytes in block
}  +---------------+
}  |  pixel width  |    4            - First part of ratio (numerator)
}  +---------------+
}  | pixel height  |    5            - Second part of ratio (denominator)
}  +---------------+
}  |0 0 0 0 0 0 0 0|    6         0  - extension block end code
}  +---------------+
}
}Let byte four equal 'x' and byte five equal 'y'  Then x:y is the _pixel_
}aspect ratio.

I like this.  I have appended a quick patch for giftoppm.c that should
(a) make it read and ignore extension blocks, and (b) make it handle
this new aspect ratio extension block by putting out a message advising
the user to do a ppmscale.  This is the same way that ilbmtoppm handles
non-square pixels.

I haven't tested this patch beyond compiling it, but it's pretty simple.
A very similar change should work for any other GIF readers derived from
Patrick Naughton's gif2ras.

If anyone modifies a GIF writer to generate these extension blocks,
drop me a line so we can check interoperability.
---
Jef

  Jef Poskanzer  jef@well.sf.ca.us  {ucbvax, apple, hplabs}!well!jef
  "I'll tell you right out, I'm a man who likes talking to a man who
         likes to talk." -- Kaspar Gutman [The Maltese Falcon]

*** giftoppm.c.old	Tue Jul 17 15:50:09 1990
--- giftoppm.c	Tue Jul 17 16:10:11 1990
***************
*** 65,70 ****
--- 65,72 ----
  #define False (0)
  
  #define NEXTBYTE (*ptr++)
+ #define EXTENSION 0x21
+ #define EXTENSION_ASPECTRATIO 0x52
  #define IMAGESEP 0x2c
  #define INTERLACEMASK 0x40
  #define COLORMAPMASK 0x80
***************
*** 245,253 ****
  	Red[1] = Green[1] = Blue[1] = 255;
      }
    
  /* Check for image seperator */
  
!     if (NEXTBYTE != IMAGESEP)
  	pm_error( "%s is a corrupt GIF file (nosep)", inf, 0,0,0,0 );
  
  /* Now read in values from the image descriptor */
--- 247,287 ----
  	Red[1] = Green[1] = Blue[1] = 255;
      }
    
+ /* Check for extension blocks */
+ 
+     for (;;) {
+ 	ch = NEXTBYTE;
+ 	if ( ch != EXTENSION )
+ 	    break;
+ 	ch = NEXTBYTE;
+ 	if (ch == EXTENSION_ASPECTRATIO) {
+ 	    int pwid, phei;
+ 	    if (NEXTBYTE != 2)
+ 		pm_error( "%s is a corrupt GIF file (bad aspectratio 1)", inf, 0,0,0,0 );
+ 	    pwid = NEXTBYTE;
+ 	    phei = NEXTBYTE;
+ 	    if (NEXTBYTE != 0)
+ 		pm_error( "%s is a corrupt GIF file (bad aspectratio 2)", inf, 0,0,0,0 );
+ 	    if (pwid != phei)
+ 		pm_message(
+ 		    "(Warning: non-square pixels; to fix do a 'ppmscale -%cscale %g'.)\n",
+ 		    pwid > phei ? 'x' : 'y',
+ 		    pwid > phei ? (float) pwid / phei : (float) phei / pwid, 0,0,0 );
+ 	} else {
+ 	    /* Unknown type of extension block - skip past it */
+ 	    for (;;) {
+ 		ch = NEXTBYTE;
+ 		if (ch == 0)
+ 		    break;
+ 		while (--ch >= 0)
+ 		    (void) NEXTBYTE;
+ 	    }
+ 	}
+     }
+ 
  /* Check for image seperator */
  
!     if (ch != IMAGESEP)
  	pm_error( "%s is a corrupt GIF file (nosep)", inf, 0,0,0,0 );
  
  /* Now read in values from the image descriptor */