\input texinfo @c -*-texinfo-*-
@comment $Id: dpg-view.tex,v 0.3.2.0 1992/06/11 22:36:53 dpg Alpha dpg $
@comment %**start of header
@setfilename dpg-view.info
@settitle The dpg-view Manual
@comment %**end of header

@ifinfo
This file documents dpg-view.

Copyright @copyright{} 1992 D P Gymer

Permission is granted to make and distribute verbatim copies of this
manual provided the copyright notice and this permission notice are
preserved on all copies.

@ignore
Permission is granted to process this file through Tex and print the
results, provided the printed document carries copying permission notice
identical to this one except for the removal of this paragraph (this
paragraph not being relevant to the printed manual).

@end ignore
Permission is granted to copy and distribute modified versions of this
manual under the conditions for verbatim copying, provided also that the
entire resulting derived work is distributed under the terms of a
permission notice identical to this one.

Permission is granted to copy and distribute translations of this manual
into another language, under the above conditions for modified versions,
except that this permission notice may be included in translations
approved by D P Gymer instead of in the original English.
@end ifinfo

@node Top, Introduction, (dir), (dir)
@comment  node-name,  next,  previous,  up
@ifinfo
This manual documents version 0.3.2 of dpg-view.
@end ifinfo

@menu
* Introduction::	Introduction and credits
* Invocation::		How to run dpg-view
* Viewing pictures::	What happens when dpg-view runs
* Adding features::	How to write functions to recognize and read other image types
* Things to do::	Things needing attention

 --- The Detailed Node Listing ---

Adding features to dpg-view

* Internal overview::           Overview of how dpg-view works
* Internal structures::         Structures used by dpg-view
* Utility functions::           Useful utility functions and variables
* Image readers::               Writing code to read new image types
* Display drivers::             Writing code to handle different displays
@end menu

@node Introduction, Invocation, Top, Top
@comment  node-name,  next,  previous,  up
@chapter Introduction and credits

dpg-view is a program for viewing anymaps (bitmaps, graymaps, and
pixmaps)@footnote{These names refer specifically to the image formats
used in the pbmplus package; dealing with other image types is
possible.}.  The code should be fairly portable, other than the VGA
code, which is localized to one source file.

@heading Credits

@table @asis
@item Dave Gymer (dpg@@cs.nott.ac.uk)
Original code and documentation.
@item Eric R Smith (ersmith@@uwo.ca)
mkptypes (used to generate the function prototypes in @file{proto.h}).
@item Tommy Frandsen (frandsen@@diku.dk)
The Linux VGA library used by @file{view-vga.c} to plot the images.
@item Jef Poskanzer (jef@@well.sf.ca.us)
The pbmplus package whose image type is used for the reader in
@file{read-pnm.c}@footnote{Older versions of this software (up to
version 0.2.5) used the pbmplus libraries to implement this module.
Later versions have custom written routines.}.
@item David Koblas
Much of the GIF reader, which was hacked from @file{giftoppm.c} in the
pbmplus package@footnote{The following notice covers some code in
@file{read-gif.c}:

Copyright 1990, David Koblas.

Permission to use, copy, modify, and distribute this software
and its documentation for any purpose and without fee is hereby
granted, provided that the above copyright notice appear in all
copies and that both that copyright notice and this permission
notice appear in supporting documentation.  This software is
provided "as is" without express or implied warranty.}.
@end table

@node Invocation, Viewing pictures, Introduction, Top
@comment  node-name,  next,  previous,  up
@chapter Invocation

The arguments to dpg-view consist of the name of files in which images
you wish to be display are, and options which affect how the images are
displayed.  Options are normally given in a long form; if an option
requires an argument you should use the @samp{=} character to connect
the option name to the argument.  Short forms of some options also
exist, but their use is discouraged@footnote{Such options exist
mainly to simplify the option parsing code.}.

Option names may be abbreviated to their shortest unique prefix.

@table @samp
@item -border=@var{border}
@itemx -b @var{border}
Don't use @var{border} percentage of the screen's width and height in
displaying an image; the resulting area to be used is in the center of
the screen.

@item -display=@var{device}
@item -S @var{device}
Select a different device for displaying images. This is dependant on
the display driver; with the Linux @file{view-vga.c} driver, it gives a
number from 1 to 8 which selects the VGA mode to use (the default for
that driver is 360x480x256).  This would normally be a high resolution,
multicolor mode, if available.  The display driver is at liberty ignore
or cause dpg-view to die with a fatal error if an invalid value is
given.

@item -fullscreen
Scale the image so that it uses the full size of the screen.  Any aspect
ratio information is ignored.

@item -invert
Invert the colors in an image.  This is most useful with bitmaps; it may
occaisionally be useful with graymaps, but is rarely any use with
pixmaps (where the affect is to produce an image somewhat like a
photographic negative).  Note that the inversion is done before any
dithering or palette compression.

@item -physical-ratio=@var{width}x@var{height}
@item -p @var{width}x@var{height}
Pretend the screen has a physical size ratio of
@var{width}:@var{height}.  The default is 13:10@footnote{This is a good
approximation for my Mitac SVGA monitor.}. This useful when dealing
with images whose ratio is not 1:1 (that is, whose pixels are not
square).

@item -unscaled
Do not scale the image; instead, match one pixel in the image to one
pixel on the screen.  Any image which is taller or wider than the screen
(in terms of pixels) is rejected.  Any aspect ratio information is
ignored.

@item -version
@itemx -v
Print the version number of this copy of dpg-view and exit.  The number
is in the form @samp{@var{version}.@var{release}.@var{update}}.
@end table

@node Viewing pictures, Adding features, Invocation, Top
@comment  node-name,  next,  previous,  up
@chapter What happens when dpg-view runs

Each picture is read in and then displayed.  If at any point during this
process you hit the interrupt key, the processing of that image is
abandoned and dpg-view moves immediately on to the next image.  Hitting
the quit key will abandons the run altogether.  Otherwise, dpg-view
pauses at the end of each picture to wait for a (non-interrupt)
keypress.

@node Adding features, Things to do, Viewing pictures, Top
@comment  node-name,  next,  previous,  up
@chapter Adding features to dpg-view

@menu
* Internal overview::           Overview of how dpg-view works
* Internal structures::         Structures used by dpg-view
* Utility functions::           Useful utility functions and variables
* Image readers::               Writing code to read new image types
* Display drivers::             Writing code to handle different displays
@end menu

@node Internal overview, Internal structures,  , Adding features
@comment  node-name,  next,  previous,  up
@section Overview of how dpg-view works

dpg-view works by opening each listed file in turn, and handing the file
descriptor to a set of functions, each of which is designed to recognize
a particular type of image.  @xref{Image readers}, which gives a
detailed description of what such a function should do.

If one of these functions thinks it knows how to read the file, it
attempts to do so, and returns a code to its caller to say whether or
not it succeed (failure to read and definite lack of rocognition are
treated identically).  If a function manages to read the image, no more
functions are called.  The image is read into a special structure which
gives its width and height, a color palette@footnote{This is more often
called a `colormap', but I like the artistic ring of `palette', which is
what they always seemed to be called on the Atari ST.} (a list of the
colors which make up the pixels of the image), and the image itself, in
the form of an index into the palette for each pixel, thus specifying
what color each pixel is@footnote{This is in contrast to the way in
which some image file formats, such as portable pixmaps, are stored,
where each pixel has its own red, green, and blue values.}.
@xref{Internal structures}, which descibes this structure, and the
structures which it is itself made up of.

The image is then passed to a function which attempts to reduce the
palette size (the number of colors it contains) to a number which the
dsiplay device can show (this may not be necessary if the display can
show many colors), scales the image, and may also dither the image in
order to improve its appearance (especially if the display cannot show
many colors)@footnote{This doesn't actually work yet.  @xref{Things to
do}.}.

The dither code calls a function in the display driver to set the actual
display's color registers to the colors given in the (possibly reduced)
color palette, and then another function to plot each pixel of the
(possibly dithered), scaled image.  @xref{Display drivers}, where these
functions are described.

@node Internal structures, Utility functions, Internal overview, Adding features
@comment  node-name,  next,  previous,  up
@section Structures used by dpg-view

@deftp {Data type} rgbval
This is an integer variable type, with a value ranging from @code{0} to
@code{MAXRGBVAL} (which is defined in @file{view.h}), which holds the
red, green, or blue intensity of a color component.
@end deftp

@deftp {Data type} COLOR
An integer type with a value from @code{0} to @code{MAXCOLOR} (again,
defined in @file{view.h}), which is used to indicate which color out of
a list of colors a given pixel is.
@end deftp

@deftp {Data type} {struct color} red green blue
@code{red}, @code{green}, and @code{blue} are of type @code{rgbval}, and
together give the color of a set of pixels.
@end deftp

@deftp {Data type} PALETTE color number count next
@code{color} is of type @code{struct color} and gives the color of all
pixels which have a value of the @code{COLOR} given by @code{number}.
@code{count} is an @code{int} which is used to record the number of
times a color occurs in a given image.  @code{next} is a pointer to a
@code{PALETTE}, and points to the next color in the list, or is a null
pointer in the last entry.

Each entry in the list should be unique in the value of both
@code{color} and @code{number}.  @code{count} may be @code{0}, in which
case the color is simply discarded; the values of @code{number} may or
may not form a sequence starting at 0, but it is recommended that they
do.  No significane is placed on the order of the entries.
@end deftp

@deftp {Data type} MAP width height image palette
@code{image} is a pointer to an array of @code{COLOR *}s, one for each
row of the image (hence they a numbered from @code{0} to the value of
@code{height}).  Each of these is in turn a pointer to an array of
@code{COLOR}s having the number of elements given by @code{width}, which
holds the color index of each pixel (as given in a @code{PALETTE}
entry).  The @code{palette} member points to the first entry in that
image's color palette@footnote{It is not meaningful for this to be null,
since each pixel must have a corresponding palette entry, and thus an
empty palette implies an image with no colors, which cannot have any
pixels.}.
@end deftp

@node Utility functions, Image readers, Internal structures, Adding features
@comment  node-name,  next,  previous,  up
@section Useful utility functions and variables

@deftypevr {Global flag} int rc
This holds the value which will be returned via the @code{exit} function
if the program terminates normally.  By default this is set to @code{0},
but can be set to some other value (normally @code{1}) if an error is
detected which is important but does not justify aborting execution.
Note that this value may be overidden if the program is terminated
abnormally after the value is set.
@end deftypevr

@deftypevr {Global flag} int last_sig
This is set to the number of the last non-fatal signal received
(normally @code{SIGINT}), or @code{0}.  Functions which are likely to be
time-consuming should periodically check for a value other than @code{0}
here, and return as if they had finished normally (but without having
actually completed the task).  For example, an image reader might check
this at the start of every row (assuming pixels are read in row-by-row),
and return as if the image had been read succesfully if a signal has
been caught.

Note that @code{last_sig} is reset between each image, so that an
interrupt during the processing of one image will cause dpg-view to move
on to the next immediately.
@end deftypevr

@deftypefn {Macro} int COLOREQ (struct color @var{c1}, struct color @var{c2})
Compares two variables of type @code{struct color} and returns 1 if the
@code{red}, @code{green}, and @code{blue} color components of each are
equal.
@end deftypefn

@deftypefn {Function} void status_bar (int @var{done}, int @var{total})
Indicate that the @var{done}th part of a task of @var{total} parts is
complete.  This is normally called by image reading functions to let the
user know that things are progressing.  Note that only the segment given
is plotted, not the entire bar.
@end deftypefn

@deftypefn {Function} void view_message (const char *@var{why}, const char *@var{where}, ...)
Display an error or informational message on @code{stderr}.
@var{where}, and any additional arguments, describe the source of the
error or the object which information is being given about, and takes
the form of a @code{printf}-style format string and arguments.
@var{why} describes the error or information itself, and is simply an
unformatted string.  If @var{why} is a null pointer, then @code{errno}
and @code{strerror} are used to determine the message.
@end deftypefn

@deftypefn {Function} PALETTE *alloc_palette (void)
Returns a pointer to a freshly allocated @code{PALETTE}.  If allocation
fails, dpg-view will abort with an error message.  None of the members
of the @code{PALETTE} structure are set.
@end deftypefn

@deftypefn {Function} PALETTE *alloc_map (void)
Returns a pointer to a freshly allocated @code{MAP}, with its
@code{width} and @code{height} members undefined, and the @code{image}
and @code{palette} pointers set to null.  If allocation fails, dpg-view
will abort with an error message.
@end deftypefn

@deftypefn {Function} void alloc_image (MAP *@var{map}, int @var{width}, int @var{height})
Allocate a new image of @var{height} rows and @var{width} columns, and
set the @code{image}, @code{width}, and @code{height} members of
@var{map} to @var{width} and @var{height}, respectively.
@end deftypefn

Prototypes for these are given in the file @file{view.h}.

@node Image readers, Display drivers, Utility functions, Adding features
@comment  node-name,  next,  previous,  up
@section Writing code to read new image types

(See @file{read-pnm.c} for an example.)

Basically, you create a file called @file{read-@var{foo}.c}, where
@var{foo} indicates the type of file.  Add this to the @file{Makefile}
(both the source name in the prototypeable source list, and the object
file name in the dpg-view object module list).  It should contain only
one externally visible identifier, which should be
@code{maybe_read_@var{foo}}.  Add this identifier to the list of
functions in the file @file{read.c}.

@deftypefn {Function} int maybe_read_@var{foo} (FILE *@var{fp}, const char *@var{file}, MAP *@var{map})
@var{fp} is a stream which is opened and is positioned at the start of
the image (normally the beginning of the file).  The load routine may
read and seek on this stream at will, without repositioning the file
pointer on exit.

@var{file} is the name of the file for error message; you should not
normally print messages unless you are absolutely sure that you have
correctly identified the file type.

@var{map} is a pointer to a map, with an empty palette, and no valid
image.  If you read an image, you must fill the palette, and allocate
(using @code{alloc_image}) and fill the image.

The function should return 0 if it recognizes the image and has
succesfully loaded it, or 1 othewise.
@end deftypefn

On entry to the function, the @code{image} and @code{palette} members of
the @code{MAP} structure are initialized as null pointers.

On exit from the function, the structure members should be set like
this:

@table @code
@item width
@itemx height
These are normally set by @code{alloc_image}, and should not be altered
by modules after an image has been allocated.
@item image
If the function returns 0, this must be set to point to an image
(normally allocated with @code{alloc_image}).  Otherwise, it need not be
set.
@item palette
This should be a pointer to the first element in a linked list of colors
(each element normally being allocated with @code{alloc_palette}.
@end table

During reading, it is useful to use the @code{status_bar} function to
let the user know how the read is progressing, since large images may
take some time to read.  (If the image format is guarenteed to be small,
such as the uncompressed X-Face, this may be ignored.)

@node Display drivers,  , Image readers, Adding features
@comment  node-name,  next,  previous,  up
@section Writing code to handle different displays

(See @file{view-vga.c} for an example.)

The file should be called @file{view-@var{foo}.c}, where @var{foo}
describes the display device.  Add the source file name to the Makefile
in the prototypeable source list.  The appropriate object filename
should replace the default display driver in the program target's list.

It should provide the following functions.  No other identifiers should
be externally visible.

@deftypefn {Function} int readkey (void)
Read a keypress.  Echoing and line buffering should be disabled.  Return
the key pressed, or EOF.
@end deftypefn

@deftypefn {Function} void plot_pixel (int @var{x}, int @var{y}, COLOR @var{c})
Plot a pixel of color @var{c} at row @var{y} of column @var{x}.
@end deftypefn

@deftypefn {Function} int init_display (int *@var{width}, int *@var{height}, int *@var{num_colors})
Initialize the display, and set the integers pointed to by @var{width},
@var{height}, and @var{num_colors} to apropriate values.  The function
should return 0 if succesful, non-zero otherwise.  If the terminal
parameters are altered, care should be taken to leave the interrupt and
quit keys (if available) active.

The variable @code{screen_dev}, which is of type @code{const char *},
points to the display device given in the options to dpg-view, or 0 if
none was.  The display driver may use this value to select a particular
display mode (in which case none is given, a sensible default should be
chosen), or it may simply ignore it (for instance, if only one display
mode is available).
@end deftypefn

@deftypefn {Function} int set_colors (PALETTE *@var{pal})
Set the display's color registers to those given in the list whose first
entry is pointed to by @var{pal}.  The @code{number} field gives the
register number, and the @code{color} structure gives the red, green,
and blue component values, from 0 to @code{MAXRGBVAL}.  The number of
colors will never exceed the maximum number indicated by
@code{init_display}.
@end deftypefn

@deftypefn {Function} void tidy_display (void)
Return the display to the state it was in before init_display was
called.
@end deftypefn

@node Things to do,  , Adding features, Top
@comment  node-name,  next,  previous,  up
@chapter Things to do

Add dithering and palette compression capabilities.  The current
@code{dither()} function merely scales the image; it doesn't compress
the palette or dither the image.

Pass the name of the image file to all the functions that deal with it
and might give an error, so that we can tell the user which image(s)
failed to diplay properly and why.  (This is just because of my quickly
written image reading code.)

Check arguments more carefully.

Read other common formats, such as PCX.  @xref{Image readers}

Re-write the GIF reader to recognize extension blocks, and to stop being
dependant on someone else's code (not that it _really_ matters, I'd just
be happier about it if it were under the GPL).

Re-write the uncompressed X-Face reader to be able to uncompress the
images, maybe even pull them out of mail and news messages.

More speed might be gained if, after we display and image, we just flush
the input buffer, and only wait for a key once the next image is loaded
and ready for display.  This may or may not cause unwanted trouble with
SIGINTs and the status bar.  More thought required, I think.

Option to force color images to grayscale.  This would save us using
ppmtopm on very colorful images.  This might also be the best way to
deal with images with more gray levels than we actually distinguish or
can display, and saves us mucking around with unnecessary dithering.

The ability to display images larger than the screen in a scrollable
window.
@bye
