[comp.lang.postscript] compressed images

jcm@nori.Philips.Com (John Martin) (07/20/89)

The PostScript "image" operator works as follows:

<width> <height> <bits/sample> <matrix> <proc> image

The simplest case uses {currentfile picstr readhexstring pop} as the
procedure to provide the image data, followed by the image represented
as hexadecimal strings.

Has anyone implemented a PostScript run length decoder procedure that
will allow run length compressed files to be sent to the printer?
Assume that the compression is done by a C program in advance.

I realize that the file transmission time will be more than offset by
the decompression time, but am willing to trade off time for file
size.

I have made several attempts at getting this to work, but have run
into problems because of limited stack size, and inconsistent
treatment of whitespace characters by "read", "readhexstring", and
"readline".

I would appreciate any suggestions. Thanks very much.

	John Martin
	Philips Labs
	jcm@philabs.philips.com
	tel 914-945-6406
	fax 914-945-6552

hascall@atanasoff.cs.iastate.edu (John Hascall) (07/21/89)

In article <59760> jcm@nori.Philips.Com (John Martin) writes:
>The PostScript "image" operator works as follows: ...
 
>Has anyone implemented a PostScript run length decoder procedure that
>will allow run length compressed files to be sent to the printer?
>Assume that the compression is done by a C program in advance.

   Yes (here is an excerpt of output from such a program).
This may or may not be a "good" way to do this as this was one
of my first attempts at PostScript.

%!-Adobe-1.0                     
%%Title: p1                        
%%Creator: VAXstation MOVIE.BYU 6.2
18 108 translate    
 0.6667 0.6667 scale
/c 0 def /d 1 string def
/IB {/pix exch def save pix 1 8 [pix 0 0 1 0 0]} def 
/RL {c 0 eq {
       /c currentfile d readhexstring pop 0 get def
       currentfile d readhexstring pop pop
    } if
    /c c 1 sub def d
} def
/IE {translate pix 1 scale image restore} def
/NP {newpath} def /SK {stroke} def
/MT {moveto} def /LT {lineto} def 
/SC {setrgbcolor} def             
%%EndProlog
%%Page: 0 1
 33 IB {RL} 389 627 IE  
01151F0F010E            
 80 IB {RL} 357 626 IE  
010F010E0E1431150F0F    
106 IB {RL} 347 625 IE  
090F2115221B0F150F0F    
123 IB {RL} 337 624 IE  
090F09154E1B15150114050E

 
>I realize that the file transmission time will be more than offset by
>the decompression time, but am willing to trade off time for file
>size.

    I found that it was faster to send uncompressed data, than to
send compressed data (at least at 19.2 Kbaud which is what we run).


John Hascall
ISU Comp Center
Ames IA

rokicki@polya.Stanford.EDU (Tomas G. Rokicki) (07/21/89)

jcm@nori.Philips.Com (John Martin) writes:
> Has anyone implemented a PostScript run length decoder procedure that
> will allow run length compressed files to be sent to the printer?
> Assume that the compression is done by a C program in advance.

Sure, this is easy, and for most printers that run over 9600 buad
serial lines, it's actually faster.  You use a simple run-length scheme.
The loop to decode looks like

	grab a byte
	if it's > 128
		repeat the next byte (n-128) times
	else
		grab the next n bytes literally

It's sometimes smart to not attempt full compression; ie, only compress
into run-length if the run count is four or greater, or some such, to
help avoid some interpreter overhead with all the really small chunks.

I'll post code as soon as I go home and get some.  Another idea that
works much better for some pictures (and is faster for some as well)
is to just send the first raster row, and then compute and send
`differences'; these differences can be a right shift, a left shift,
etc.  This is especially fast for line-art type rasters or structured
drawings.

Now if we can only encourage Adobe to give us a readlempelzivstream
instead of readhexstring . . .

> I have made several attempts at getting this to work, but have run
> into problems because of limited stack size, and inconsistent
> treatment of whitespace characters by "read", "readhexstring", and
> "readline".

Use readhexstring exclusively; that's all you need.

-tom

leech@Apple.COM (Jonathan Patrick Leech) (07/21/89)

In article <1231@atanasoff.cs.iastate.edu> hascall@atanasoff.cs.iastate.edu.UUCP (John Hascall) writes:
>In article <59760> jcm@nori.Philips.Com (John Martin) writes:
<re run-length encoded images>
>>I realize that the file transmission time will be more than offset by
>>the decompression time, but am willing to trade off time for file
>>size.
>    I found that it was faster to send uncompressed data, than to
>send compressed data (at least at 19.2 Kbaud which is what we run).

    I have implemented run-length decoding of a binary stream
(Mac PackBits format, actually :-), rendering the entire image with
one operator as opposed to the multiple invocations of image in your
approach.  The images are much smaller, but decoding takes several
times longer than just dumping the raw bits (~4 minutes/full page
image encoded, ~1.5 minutes/full page in straight binary).  This is
over Appletalk, much faster than a 19.2K line, so you might show a net
increase in speed.  You probably couldn't use binary on a serial line,
though, so there goes half your bandwidth.

    I've been tweaking my decoding procedure for a while, but haven't
gotten the speed up enough to show net gain.  This is why I was asking
about faster PostScript controllers recently; however, it doesn't seem
that Hyperscript running on a Qume goes any faster than Adobe
PostScript on an NTX, in this particular (unusual) application.

    I can't post the code, so don't ask.  It isn't hard to write,
though - I started learning PostScript two months ago.
--
    Jon Leech (leech@apple.com)
    Apple Integrated Systems
    __@/

rokicki@polya.Stanford.EDU (Tomas G. Rokicki) (07/21/89)

> Has anyone implemented a PostScript run length decoder procedure that
> will allow run length compressed files to be sent to the printer?
> Assume that the compression is done by a C program in advance.

Here's my entry.  Comments have been added to the normal output of
the program.

% random definitions for width, height, etc.
/W  378 def /H  230 def /BS 1 def /PW 0.99 def /ST 128 string def
% a single-byte string for grabbing byte by byte
/T 1 string def
% n S -
% This subroutine grabs the next `n' bytes from the stream and
% returns them literally.  Does it by grabbing a subinterval of
% the appropriate length, and then readhexstring.
/S { %def
   ST exch 0 exch getinterval
   currentfile exch readhexstring pop
} bind def
% n S -
% This subroutine does a run-code; it grabs the next byte and
% repeats it n-128 times.
% First it grabs the next byte and stuffs it into all 128
% positions of the string.  (This has been shown to be faster
% than the `for' loop method.)  It then grabs the appropriate
% subinterval of that string.
/R { %def
   128 sub
   currentfile T readhexstring pop 0 get
   dup ST exch 0 exch put
   dup ST exch 1 exch put
   dup ST exch 2 exch put
   dup ST exch 3 exch put pop ST
   dup dup  4 exch 0  4 getinterval putinterval
   dup dup  8 exch 0  8 getinterval putinterval
   dup dup 16 exch 0 16 getinterval putinterval
   dup dup 32 exch 0 32 getinterval putinterval
   dup dup 64 exch 0 64 getinterval putinterval
   exch 0 exch getinterval
} bind def
% This is the general subroutine.  We repeatedly get a byte,
% compare it with 128, and call the appropriate routine.
/G { %def
   currentfile T readhexstring pop 0 get
   dup 128 lt { S } { R } ifelse
} bind def
% Of course, image calls the above routine as many times as
% appropriate.
/DP { %def
  W H BS [W 0 0 H neg 0 H]
  { G }
  image grestore
} bind def
%%EndProlog
gsave
DP
% And now, the data . . .
AFFF01C091FF01EF9DFF01C091FF01E09DFF01C091FF02EF1F9CFF01C08CFF01BF84FF02EFE39C
FF04C0E0F87F89FF017F84FF03EFFC3F9BFF04C0F2733F88FF01FE85FF03EFFFC79BFF04C0F332
3F88FF01FD85FF03EFFFF89BFF04C0F3303F88FF01FB85FF04EFFFFF0F9AFF04C0F3313F88FF01
...