Created
February 25, 2011 17:45
-
-
Save RubeRad/844176 to your computer and use it in GitHub Desktop.
Read in nrows,ncols, followed by nrows lines of ncols whitespace-separated pixel intensities. Output .tff
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#! /bin/perl | |
# txt2tff.pl | |
use Getopt::Std; | |
$opt{x} = 1; | |
getopts('x:o:', \%opt); | |
# determine the dimensions, create an empty 2D matrix | |
$_ = <>; | |
@dims = split; | |
$lines = shift @dims; | |
$samps = shift @dims; | |
foreach (1..$lines) { push @img, [(0) x $samps] } | |
@lns = (<>); | |
if ($opt{x} > 1) { | |
@lns1 = @lns; | |
@lns = (); | |
foreach (@lns1) { | |
@row1 = split; | |
@row = (); | |
foreach $i (@row1) { push @row, ($i)x$opt{x} } | |
$ln = join " ", @row; | |
for (1..$opt{x}) { push @lns, $ln } | |
} | |
$lines *= $opt{x}; | |
$samps *= $opt{x}; | |
} | |
# stuff the pixel values into the matrix (and find the brightest pixel value) | |
foreach $l (0..$lines-1) { | |
$_ = $lns[$l]; | |
@row = split; | |
foreach $s (0..$samps-1) { | |
$img[$l][$s] = shift @row; | |
$maxpx = $img[$l][$s] if $img[$l][$s] > $maxpx; | |
} | |
} | |
# Construct 174 bytes of header: 8-byte TFF header, then 2+12*12+4=150 bytes of IFD, | |
# then 4*4=16 bytes of X/YResolution (data elements too long to just include in | |
# the IFD itself). | |
# 8-byte header: 4d4d=MM=big-endian, 2a=42=TIFF code, 8=byte to start IFD | |
$tiff = pack "H16", "4d4d002a00000008"; | |
# This is the only IFD in the image. 12 entries, at 12 bytes each, | |
# which define our 8-bit greyscale image. | |
$tiff .= pack "H4", "000c"; # IFD: 12 entries | |
# Tag. | |
# | |Type | |
# | || |Count... | |
# | || || |Off/Val. | |
# | || || || | | |
$tiff .= pack "H24", "00fe00040000000100000000"; #NewSubfileType | |
$tiff .= pack "H16N", "0100000400000001", $samps; #ImageWidth | |
$tiff .= pack "H16N", "0101000400000001", $lines; #ImageLength | |
$tiff .= pack "H16nn", "0102000300000001", 8, 0; #BitsPerSample (8) | |
$tiff .= pack "H16nn", "0103000300000001", 1, 0; #Compression (none) | |
$tiff .= pack "H16nn", "0106000300000001", 1, 0; #PhotometricInterpretation | |
$tiff .= pack "H16N", "0111000400000001", 174; #StripOffset (one strip, after this header) | |
$tiff .= pack "H16N", "0116000400000001", $lines; #RowsPerStrip (all) | |
$tiff .= pack "H16N", "0117000400000001", $lines*$samps; #StripByteCounts | |
$tiff .= pack "H16N", "011A000500000001", 158; #Offset of XResolution | |
$tiff .= pack "H16N", "011B000500000001", 166; #Offset of YResolution | |
$tiff .= pack "H16nn", "0128000300000001", 1, 0; #ResolutionUnits (unitless) | |
$tiff .= pack "N", 0; #offset of next IFD (never) | |
# At this point, $tiff is 158 bytes long, which is why XResolution | |
# offset is hardcoded to 158 | |
$tiff .= pack "NN", 1, 1; #XResolution: 1:1 | |
# At this point, $tiff is 162 bytes long, which is why YResolution | |
# offset is hardcoded to 162 | |
$tiff .= pack "NN", 1, 1; #YResolution: 1:1 | |
# The Strip (of rows of pixels) | |
# At this point, $tiff is 174 bytes long, which is why StripOffset | |
# is hardcoded to 174. All that is left is to encode each pixel as one byte | |
foreach $l (0..$lines-1) { | |
foreach $s (0..$samps-1) { | |
$val = int( $img[$l][$s] / $maxpx * 255 ); # rescale to 8-bit | |
$tiff .= pack "C", $val; | |
} | |
} | |
# this dumps the whole binary file | |
if ($opt{o}) { | |
open TIF, ">$opt{o}"; | |
binmode TIF; | |
print TIF $tiff; | |
close TIF; | |
} else { | |
binmode STDOUT; | |
print $tiff; | |
} | |
=head1 txt2tff.pl | |
Convert a textual description of an image (a brick of greyscale ints) into a .tff image, | |
which can be viewed/converted as needed with other standard tools. The simplest possible | |
TFF representation is used; see http://partners.adobe.com/public/developer/en/tiff/TIFF6.pdf | |
for details. | |
=head2 txt2tff.pl Typical Usage | |
txt2tff.pl greyvals.txt > image.tff | |
=head2 txt2tff.pl Command Line | |
The text version of the image can be specified as a command-line filename argument (as above), | |
or piped through STDIN, as | |
greyscale_generator | txt2tff.pl > image.tff | |
Since the script prints binary to STDOUT, you'll probably want to redirect into a file | |
(as above). | |
=head2 txt2tff.pl Inputs | |
The text input must begin with a header line with two positive integers that determine the | |
number of lines (rows) and samples (columns), respectively. There must follow | |
that many lines in the file, each with that many numerical greyscale values per line. | |
Any missing lines/samps will be construed as 0, any extra lines/samps will be ignored. | |
The orientation of pixels in the image will be the same as in the text input, i.e. the | |
first line of pixel text will be the top row of pixels in the file, beginnings of lines | |
in the text will be at the left of the image. | |
Numbers on each line may be delimited by any amount/type of whitespace. Numbers may be noninteger; | |
they'll all get scaled and truncated to 8-bit anyways. | |
=head2 txt2tff.pl Outputs | |
A (binary) TFF file will be printed to STDOUT. The range 0...MAX of grey values | |
encountered in the text input will be rescaled to 0..255. Due to the 174 bytes of | |
header information, the .tff file will be exactly 174+nlines*nsamps bytes long. | |
=head2 txt2tff.pl Changelog | |
=over 4 | |
=item Apr 5 2006 | |
Initial submission to http://etrc/sites/perl/code/share/txt2tff/ | |
=back | |
=head2 txt2tff.pl Todo | |
Rescale minimum to 0, instead of 0-->0? | |
Auto-determine image dimensions without needing header line | |
Color? | |
Skip rescaling, build header first, and pack pixels into the binary file | |
as encountered in the input (without need for in-memory array storage) | |
Print binary as built (without need for in-memory $tiff storage) | |
=cut |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment