Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Display external TIFF file

1,100 views
Skip to first unread message

aspr...@hotmail.com

unread,
May 2, 2007, 9:32:02 PM5/2/07
to
I've found and implemented the following code to display external JPEG
files and it works well:

300 300 translate
100 100 scale
/DeviceRGB setcolorspace
% myfile.jpg is a 100 x 100 jpeg
/infile (c:\\temp\\myfile.jpg) (r) file def
/Data {infile /DCTDecode filter} def
<<
/ImageType 1
/Width 100
/Height 100
/ImageMatrix [100 0 0 -100 0 100]
/DataSource Data
/BitsPerComponent 8
/Decode [0 1 0 1 0 1]
>>
image
showpage

But when I execute the same code with a TIFF file, substituting /
RunLengthDecode for the encoding, all I get is a one pixel high line.

I suspect I'm not using the correct filter or have made some other
mistake in one of the many portions of the image matrix but after
several days, I have been unable to determine how to make it work.

If anyone knows where I've made my mistake, please let me know.

Thank you

Alan

Ken Sharp

unread,
May 3, 2007, 3:12:02 AM5/3/07
to
In article <1178155922.9...@c35g2000hsg.googlegroups.com>,
aspr...@hotmail.com says...


> But when I execute the same code with a TIFF file, substituting /
> RunLengthDecode for the encoding, all I get is a one pixel high line.

TIFF files are not (or need not) be RunLength Encoded. They can also use
CCITT, LZW and later versions can use Flate.

They also have a complex structure (unlike JPEG files) and, again unlike
JPEG files, PostScript does not understand the TIFF file format.


> I suspect I'm not using the correct filter or have made some other
> mistake in one of the many portions of the image matrix but after
> several days, I have been unable to determine how to make it work.
>
> If anyone knows where I've made my mistake, please let me know.

I'm afraid its rather more complicated than that. As PostScript is a
programming language its perfectly possible to write a program to read a
TIFF file, either from disk if your interpreter supports that or in-
line. Note that unless the TIFF file is small enough to hold in memory,
or is a single contiguous strip, it may well not be possible to process
some TIFF files.

Here's a program which works for some TIFF files. This only works with
files on disk. No warranty, express or implied....

To use this, :

%%
%% TiffPrint reads and prints a TIFF file.
%% Syntax: x y xscale yscale filename TiffRead
%%

So download as a job by appending a command to read a file, or install
as a ProcSet, or outside the server loop to make permanent.

----------------------------------------------------------------

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%
%%
%%
%% Ken's amazing Tiff reader in PostScript.
%%
%%
%%
%% Do not modify this file, under pain of pain.
%%
%%
%%
%% Created: 31/10/2002
%%
%%
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%


/TiffDict 100 dict def

/TIFFdebug false def

TiffDict begin

%%
%% GetByte reads a single byte from the file.
%% Syntax: GetByte
%% Returns: int and true, or false
%%
/GetByte{
TiffDict begin
RawFile read
end
}bind def

%%
%% GetTiffByte just points straight to GetByte
%%
/GetTiffByte{
GetByte
}bind def

%%
%% GetTiffASCII just points straight to GetByte
%%
/GetTiffASCII{
GetByte
}bind def

%%
%% GetTiffShort reads 2 bytes as a short from the file, and munges
according
%% to the data format, Motorola or Intel
%% Syntax: GetTiffShort
%% Returns: int and true, or false
%%
/GetTiffShort{
TiffDict begin
GetByte {
/b0 exch def
GetByte{
/b1 exch def
Format 73 eq{
b1 256 mul b0 add
}{
b0 256 mul b1 add
}ifelse
true
}{
false
}ifelse
}{
false
}ifelse
end
}bind def

%%
%% GetTiffLong reads 4 bytes as a long from the file, and munges
according
%% to the data format, Motorola or Intel
%% Syntax: GetTiffLong
%% Returns: int and true, or false
%%
/GetTiffLong{
TiffDict begin
GetByte {
/b0 exch def
GetByte{
/b1 exch def
GetByte{
/b2 exch def
GetByte{
/b3 exch def
Format 73 eq{
b3 16777216 mul b2 65536 mul
add b1 256 mul add b0 add
}{
b0 16777216 mul b1 65536 mul
add b2 256 mul add b3 add
}ifelse
true
}{
}ifelse
}{
false
}ifelse
}{
false
}ifelse
}{
false
}ifelse
end
} bind def

%%
%% GetTiffRational reads two LONGs, the first is the numerator, the
seond
%% the denominator of a fraction.
%% Syntax: GetTiffRational
%% Returns: float and true, or false
%%
/GetTiffRational{
GetTiffLong{
GetTiffLong{
div
true
}{
pop
(Unable to read denominator of Rational)==
false
}ifelse
}{
(Unable to read numerator of Rational)==
false
}ifelse
}bind def

%%
%% GetTiffSByte reads a signed byte from the file
%% Syntax: GetTiffSByte
%% Returns: int and true, or false
%%
/GetTiffSByte{
GetTiffByte{
dup 128 ge{
128 sub -1 mul
}if
true
}{
(Error reading byte) ==
false
}
}bind def

%%
%% GetTiffSShort reads a signed short from the file
%% Syntax: GetTiffSShort
%% Returns: int and true, or false
%%
/GetTiffSShort{
GetTiffShort{
dup 32768 ge{
32768 sub -1 mul
}if
true
}{
(Error reading short) ==
false
}ifelse
}bind def

%%
%% GetTiffSLong reads a signed short from the file
%% Syntax: GetTiffSLong
%% Returns: int and true, or false
%%
/GetTiffSLong{
GetTiffSLong{
dup 2147483648 ge{
2147483648 sub -1 mul
}if
true
}{
(Error reading long) ==
false
}ifelse
}bind def

%%
%% GetTiffSRational reads two LONGs, the first is the numerator, the
seond
%% the denominator of a fraction.
%% Syntax: GetTiffSRational
%% Returns: float and true, or false
%%
/GetTiffSRational{
GetTiffSLong{
GetTiffSLong{
div
true
}{
pop
(Unable to read denominator of Rational)==
false
}ifelse
}{
(Unable to read numerator of Rational)==
false
}ifelse
}bind def

/UnHandledType{
(Unknown TIff data type)==
false
}bind def

/TypeReader [/UnHandledType load 1 /GetTiffByte load 1 /GetTiffASCII
load 1 /GetTiffShort load 2 /GetTiffLong load 4
/GetTiffRational load 8 /GetTiffSByte load 1
/UnHandledType load 1 /GetTiffSShort load 2
/GetTiffSLong load 4 /GetTiffSRational load 8
/UnHandledType load 4 /UnHandledType load 4] def

/TagHandler [254 /NewSubFileType
255 /SubFileType
256 /ImageWidth
257 /ImageLength
258 /BitsPerSample
259 /Compression
262 /PhotometricInterpretation
263 /Thresholding
264 /CellWidth
265 /CellLength
266 /FillOrder
269 /DocumentName
270 /ImageDescription
271 /Make
272 /Model
273 /StripOffsets
274 /Orientation
277 /SamplesPerPixel
278 /RowsPerStrip
279 /StripByteCounts
280 /MinSampleValue
281 /MaxSampleValue
282 /XResolution
283 /YResolution
284 /PlanarConfiguration
285 /PageName
286 /XPosition
287 /YPosition
288 /FreeOffsets
289 /FreeByteCounts
290 /GrayResponseUnit
291 /GrayResponseCurve
292 /Group3Options
293 /Group4Options
296 /ResolutionUnit
297 /PageNumber
301 /TransferFunction
305 /Software
306 /DateTime
315 /Artist
316 /HostComputer
317 /Predictor
318 /WhitePoint
319 /PrimaryChromaticities
320 /ColorMap
321 /HalftoneHints
322 /TileWidth
323 /TileHeight
324 /TileOffsets
325 /TileByteCounts
332 /InkSet
333 /InkNames
336 /DotRange
337 /TargetPrinter
338 /ExtraSamples
339 /SampleFormat
340 /SMinSampleValue
341 /SMaxSampleValue
512 /JPEGProc
513 /JPEGInterchangeFormat
514 /JPEGInterchangeFormatLength
515 /JPEGRestartInterval
517 /JPEGLosslessPredictors
518 /JPEGPointTransforms
519 /JPEGQTables
520 /JPEGDCTTables
521 /JPEGACTables
529 /YCbCrCoefficients
530 /YCbCrSubSampling
531 /YCbCrPositioning
532 /ReferenceBlackWhite
] def

%%
%% TiffStore stores a tag, and an array of data in a new dictionary in
TiffDict
%% Syntax: Type Length Offset Tag TiffStore
%% Return: none
%%
/TiffStore{
TiffDict begin

TiffDict /ParamsDict known not {
/ParamsDict 100 dict def
}if

ParamsDict begin
/LastTag exch def
/LastOffset exch def
/LastLength exch def
/LastType exch def

%% First we need to figure out the size of the data. If its 4 byts
or less
%% then Offset is the *actual* data, otherwise its a pointer...
LastType TypeReader length gt{
(Unknown Tiff data type ) print LastType ==
false
}{
TypeReader LastType 2 mul 1 add get %% Get the
field size from the table
LastLength mul 4 le { %%
See if field size * count <= 4
/LastArray 1 array def %%
If it is, define a single entry array
LastArray 0 LastOffset put %% and
store the offset as a value
true
}{
/LastArray LastLength array def %%
otherwise, define a big array to hold the data
/SavePos RawFile fileposition def %% save the
current file position
RawFile LastOffset setfileposition %% move to the
stored data
true
0 1 LastLength 1 sub{
TypeReader LastType 2 mul get exec {
LastArray 3 1 roll put
}{
pop
(error reading data for this tag) ==
pop % true exit code
false % say we failed
exit
}ifelse
} for
RawFile SavePos setfileposition
}ifelse
}ifelse

false 0 1 TagHandler length {
2 mul dup TagHandler exch get LastTag eq{
1 add TagHandler exch get

dup 255 string cvs print ( ) print 0 1 LastArray
length 1 sub {LastArray exch get 255 string cvs print ( ) print} for
(\n) print

LastArray def
pop
true
exit
}
{
pop
}ifelse
}for

not{
(Unhandled tag ) print LastTag ==
false
}{
true
}ifelse

and %% the boolean from the data retrieval and the
boolean from the tag handling

end %% ParamsDict
end %%TiffDict
}bind def

%%
%% ReadIFD reads a TIFF IFD from the file, and stores it in the Tiff
dictionary
%% Syntax: offset ReadIFD
%% Return: true if succesful false if not
%%
/ReadIFD{
TiffDict begin
%% First, move the file to the position specified by the offset
RawFile exch setfileposition
%% Now read the number of Directory entries in this IFD
GetTiffShort {
true exch %% marker for succesful read
%% Now read each directory entry in turn
{
%% Read the tag
GetTiffShort{
/Tag exch def
GetTiffShort{
/Type exch def
GetTiffLong{
/Length exch def
GetTiffLong{
/Offset exch def
Type Length Offset Tag
TiffStore not{
pop %% the true
(Problem storing
tag data) ==
false exit
}if
}{
pop %% the true
(Error reading Directory
Value offset) ==
false
exit
}ifelse
}{
pop %% the true
(Error reading Directory
Length) ==
false
exit
}ifelse
}{
pop %% the true
(Error reading Directory type) ==
false
exit
}ifelse
}{
pop %% the true
(Error reading Directory tag) ==
false
exit
}ifelse
}repeat
}{
(error reading number of IFD entries) ==
false
}ifelse
end
}bind def

%%
%% ReadHeader reads the tags from a TIFF file, and stores them.
%% Syntax: ReadHeader
%% Return: true for success, false for error
%%
/ReadHeader{
TiffDict begin

%% First, let's read the 2 byte format header
RawFile read {
dup 73 eq{
pop
RawFile read{
73 eq{
(Tiff file is Intel format)==
/Format 73 def
true
}{
(First two bytes of file do not
match!) ==
false
}ifelse
}{
(Failed to read second byte of file)==
false
}ifelse
}{
77 eq{
RawFile read {
77 eq{
(Tiff file is Motorola format)
==
/Format 77 def
true
}{
(First two bytes of file do not
match!) ==
false
}ifelse
}{
(Failed to read second byte of file)==
false
}ifelse
}{
(First byte of file neither 'I' nor 'M') ==
false
}ifelse
}ifelse
}{
(failed to read any data from file!) ==
false
}
ifelse

{
%% OK, we found an apparent header, now lets check the
version
RawFile read {
42 eq {
RawFile read {
pop
/IFDIndex 0 def
%% Looks like it may even be a TIFF
file :-)
%% Now we need to get the offset of
the 'next' IFD
%% and then read all the IFDs
{
GetTiffLong
{
dup /NextIFD exch def
dup 0 eq{pop true exit}
if
ReadIFD not {(Unable to
read IFD ) print IFDIndex == false exit}if
}{
(Unable to read offset
to IFD ) print IFDIndex ==
false %% return value
}ifelse
/IFDIndex 1 IFDIndex add def
}loop
}{
(unable to read version number, byte
2) ==
false
}ifelse
}{
(version number not 42) ==
false
}ifelse
}
{
(unable to read version number) ==
false
}ifelse
}{
false %% return value
}ifelse
end %% TiffDict
} bind def

%%
%% MoveToStrip moves the underlying file to the offset of the 'next'
strip
%% It also instantiates the filter (if required) to decode the
compressed
%% data.
%% Syntax: int MoveToStrip
%% Returns: Boolean
%%
/MoveToStrip{
TiffDict begin
ParamsDict begin
/CurrentStrip exch def
StripOffsets CurrentStrip get RawFile exch setfileposition
Compression 0 get 0 eq{
(Invalid compression scheme ) print Compression==
false
}{
Compression 0 get 1 eq{
%% No compression
/FilterFile RawFile def
}{
Compression 0 get 2 eq{
%% Old-fashioned CCITT Group 3 (pure 1d
encoding)
/FilterFile RawFile
<<
/Columns ImageWidth 0 get
/Rows ImageLength 0 get
/K 0
/BlackIs1 true
/EndOfBlock false
>> /CCITTFaxDecode filter def
}{
Compression 0 get 3 eq{
%% New CCITT Group 3 (specify
encoding)
/FilterFile RawFile
<<
/Columns ImageWidth 0 get
/Rows ImageLength 0 get
ParamsDict /Group3Options known
{
Group3Options 0 get 1
and {
/K 1
}{
/K 0
}ifelse
Group3Options 0 get 2
and {
/Uncompressed true
}if
Group3Options 0 get 4
and{
/EncodedByteAlign
true
}if
}{
/K 0
}ifelse
/BlackIs1 true
/EndOfBlock false
>> /CCITTFaxDecode filter def
}{
Compression 0 get 4 eq{
%% CCITT Group 4
/FilterFile RawFile
<<
/Columns ImageWidth 0
get
/Rows ImageLength 0 get
/K -1
ParamsDict
/Group4Options known{
Group4Options 0
get 2 and {

/Uncompressed true
}if
}if
/BlackIs1 true
/EndOfBlock false
>> /CCITTFaxDecode filter def
}{
Compression 0 get 5 eq{
TiffDict /Predictor
known{
Predictor 0 get 2
eq{
/FilterFile
RawFile
<<

/Columns ImageWidth 0 get

/Predictor 2

/Colours SamplesPerPixel 0 get

/BitsPerComponent BitsPerPixel 0 get 255 and
>>
/LZWDecode filter def
}{
/FilterFile
RawFile /LZWDecode filter def
}ifelse
}{
/FilterFile
RawFile /LZWDecode filter def
}ifelse
}{
Compression 0 get 6 eq{
(Unsupported
compression scheme 'JPEG') ==
}{
Compression 0 get
32773 eq{
%% Packbits
/FilterFile
RawFile /RunLengthDecode filter def
}{

(Unrecognised compression scheme ) print Compression 0 get ==
false
}ifelse
}ifelse
}ifelse
}ifelse
}ifelse
}ifelse
}ifelse
}ifelse
end
end
}bind def

%%
%% TiffDataRead is the routine which extracts data from the TIFF file
and
%% passes it to the PostScript 'image' operator. DO not call this
directly...
%%
/TiffDataRead{
TiffDict begin
ParamsDict begin
/DataString ImageWidth 0 get string def
NextRow RowsPerStrip 0 get ge{
CurrentStrip 1 add MoveToStrip
}if

FilterFile DataString readstring pop

end
}bind def

end %%TiffDict

%%
%% TiffPrint reads and prints a TIFF file.
%% Syntax: x y xscale yscale filename TiffRead
%%
/TiffPrint{
gsave
TiffDict begin
/TIFFFileName exch def
/TIFFYScale exch def
/TIFFXScale exch def
/TIFFYPos exch def
/TIFFXPos exch def

/RawFile TIFFFileName (r) file def

ReadHeader{
TIFFdebug
{
(Tiff dictionary) == flush
ParamsDict
{exch 256 string cvs print ( ) print 256 string cvs
==}
forall
}
if
ParamsDict /BitsPerSample known not
ParamsDict /BitsPerSample [1] put
ParamsDict /SamplesPerPixel known not
ParamsDict /SamplesPerPixel [1] put
%% check required keys
ParamsDict /ImageWidth known
ParamsDict /ImageLength known and
ParamsDict /Compression known and
ParamsDict /RowsPerStrip known and
ParamsDict /StripOffsets known and
ParamsDict /StripByteCounts known and
ParamsDict /PhotometricInterpretation known and
{
/ImageDict 7 dict def
ParamsDict /PhotometricInterpretation get 0 get
dup 0 eq{
pop
/DeviceGray setcolorspace
ImageDict /BitsPerComponent 1 put
ParamsDict /BitsPerSample get 0 get 1 eq{
ImageDict /Decode [1 0] put}{
ImageDict /Decode [0 1] put
}ifelse
}{
dup 1 eq{
pop
/DeviceGray setcolorspace
ImageDict /BitsPerComponent 1 put
ParamsDict /BitsPerSample get 0 get 1
eq{
ImageDict /Decode [0 1] put
}{
ImageDict /Decode [1 0] put
}ifelse
}{
dup 2 eq{
%%FIXME, need to check BitsPerSample, theoretically they could be
different, and we can't support that
pop
/DeviceRGB setcolorspace
ImageDict /BitsPerComponent 8
put
ImageDict /Decode [0 1 0 1 0 1]
put
}{
dup 3 eq{
%%FIXME, need to convert ColorMap to /Indexed colour space
pop
/Indexed [/DeviceRGB ]
setcolorspace
ImageDict
/BitsPerComponent 8 put
ImageDict /Decode [0 1]
put
}{
dup 4 eq{
pop
(This code does
not handle transparency masks) ==
}{
(Unknown
PhotometricInterpretation type) print ==
}ifelse
}ifelse
}ifelse
}ifelse
}ifelse

ParamsDict begin
/NextRow 0 def
0 MoveToStrip
ImageDict begin
/ImageType 1 def
/Width ParamsDict /ImageWidth get 0 get def
/Height ParamsDict /ImageLength get 0 get def

%%FIXME, if the TIFF file isn't a top-down file,then we should take that
into account here
/ImageMatrix [TIFFXScale 0 0 TIFFYScale -1 mul
TIFFXPos TIFFYPos ParamsDict /ImageLength get 0 get add ] def

/DataSource /TiffDataRead load def
end
end
ImageDict dup == image
}{
(Missing required TIFF tag in header) ==
}ifelse
}{
(error reading Tiff header) ==
}ifelse
TiffDict /ParamsDict undef
end %% TiffDict
grestore
} bind def

Aandi Inston

unread,
May 3, 2007, 3:38:17 AM5/3/07
to
aspr...@hotmail.com wrote:

>I've found and implemented the following code to display external JPEG
>files and it works well:

This works (mostly) because the JPEG file format is, by coincidence,
exactly the same as the format required by the DCTDecode filter.


>
>But when I execute the same code with a TIFF file, substituting /
>RunLengthDecode for the encoding, all I get is a one pixel high line.

A TIFF file contains tags, pointers, and pixel data, in tiles or
stripes, uncompressed or compressed with LZW, Run length, ZIP or JPEG.
There is certainly no filter in PostScript for this or any other file
format except JPEG.

I have heard of an exercise in reading TIFF files with PostScript, but
it would have been thousands of lines of code, parsing a byte at a
time.
----------------------------------------
Aandi Inston
Please support usenet! Post replies and follow-ups, don't e-mail them.

Aandi Inston

unread,
May 3, 2007, 5:01:37 AM5/3/07
to
qu...@dial.pipex.con (Aandi Inston) wrote:

>I have heard of an exercise in reading TIFF files with PostScript, but
>it would have been thousands of lines of code, parsing a byte at a
>time.

I'm impressed - only hundreds!

Ken Sharp

unread,
May 3, 2007, 9:28:24 AM5/3/07
to
In article <4639a4e3....@read.news.uk.uu.net>,
qu...@dial.pipex.con says...

> qu...@dial.pipex.con (Aandi Inston) wrote:
>
> >I have heard of an exercise in reading TIFF files with PostScript, but
> >it would have been thousands of lines of code, parsing a byte at a
> >time.
>
> I'm impressed - only hundreds!

Thanks for the kind comment, but it isn't an exhaustive treatment :-)

Note the 'fixme's, also it only handles files, no attempt to haandle in-
line TIFF (maybe use ReusableStreams ?).

I'm sure there are other problems, it was an intellectual exercise some
time back, not coomercial-grade code....


Ken

Helge Blischke

unread,
May 3, 2007, 10:09:03 AM5/3/07
to

In 1997, I initially wrote a set of PostScript procedures to handle all
of baseline TIFF (meanwhile including a couple of extensions) and,
for use with discless level 2 interpreters, a PostScript program that
"serializes" a TIFF file to a sequentially digestible stream.

If there is interest, I could publish this stuff under the GPL on
our web site. Let me know.

Helge

--
Helge Blischke
Softwareentwicklung

H.Bli...@acm.org

tku...@ettera.com

unread,
Mar 25, 2013, 9:53:04 PM3/25/13
to
Hi Ken,

Could you please describe how to use this TiffRead to convert tif image to pdf? Is that possible?

Thanks in advance!

ken

unread,
Mar 26, 2013, 3:50:05 AM3/26/13
to
In article <2cb8018e-f281-4af0...@googlegroups.com>,
tku...@ettera.com says...


> Could you please describe how to use this TiffRead to convert tif image to pdf? Is that possible?

TiffPrint doesn't care what its printing to, so just set up your
Distiller-like application appropriately. If you are using Ghostscript
you need the switch -sDEVICE=pdfwrite and -sOutputFile=<filename.pdf>


Ken
0 new messages