diff options
author | Jesse Luehrs <doy@tozt.net> | 2014-10-07 13:29:26 -0400 |
---|---|---|
committer | Jesse Luehrs <doy@tozt.net> | 2014-10-07 13:29:26 -0400 |
commit | 35a0bc2f82802800bdb0769882d667d59313f141 (patch) | |
tree | 7e861ca1c3f9a23366adc3dbfd1b881c813bbccf | |
parent | 3151013be7b78d79f5c0db3d5e7b95b2714dc88f (diff) | |
download | image-pnm-35a0bc2f82802800bdb0769882d667d59313f141.tar.gz image-pnm-35a0bc2f82802800bdb0769882d667d59313f141.zip |
initial sketch
-rw-r--r-- | lib/Image/PNM.pm | 139 | ||||
-rw-r--r-- | t/P3.t | 23 | ||||
-rw-r--r-- | t/data/P3.pnm | 196 |
3 files changed, 358 insertions, 0 deletions
diff --git a/lib/Image/PNM.pm b/lib/Image/PNM.pm index e69de29..31d4c93 100644 --- a/lib/Image/PNM.pm +++ b/lib/Image/PNM.pm @@ -0,0 +1,139 @@ +package Image::PNM; +use strict; +use warnings; + +sub new { + my $class = shift; + my ($data) = @_; + + my $self = bless {}, $class; + + if (ref $data) { + $self->_parse_string($data); + } + elsif ($data) { + $self->_parse_file($data); + } + else { + $self->{w} = 1; + $self->{h} = 1; + $self->{max} = 1; + $self->{pixels} = [[0]]; + } + + return $self; +} + +sub as_string { + my $self = shift; + my ($format) = @_; + + my $method = "_as_string_$format"; + die "Unknown format $format" + unless $self->can($method); + + return $self->$method; +} + +sub _as_string_P3 { + my $self = shift; + + my $data = <<HEADER; +P3 +$self->{w} $self->{h} +$self->{max} +HEADER + + for my $row (@{ $self->{pixels} }) { + $data .= join(' ', map { join(' ', @$_) } @$row) . "\n"; + } + + return $data; +} + +sub _parse_string { + my $self = shift; + my ($string) = @_; + + return $self->_parse_pnm(sub { + my ($line, $rest) = split /\n/, $string, 2; + return unless length($line) || length($rest); + $string = $rest; + return "$line\n"; + }); +} + +sub _parse_file { + my $self = shift; + my ($filename) = @_; + + open my $fh, '<', $filename + or die "Couldn't open $filename for reading: $!"; + + return $self->_parse_pnm(sub { scalar <$fh> }); +} + +sub _parse_pnm { + my $self = shift; + my ($next_line) = @_; + + my $next_line_nocomments = sub { + my $line; + while (!length($line)) { + $line = $next_line->(); + return unless defined($line); + $line =~ s/#.*//s; + } + return $line; + }; + + chomp(my $format = $next_line_nocomments->()); + chomp(my $dimensions = $next_line_nocomments->()); + + my ($w, $h) = $dimensions =~ /^([0-9]+)\s+([0-9]+)$/; + die "Invalid dimensions: $dimensions" + unless $w && $h; + $self->{w} = $w; + $self->{h} = $h; + + my $method = "_parse_pnm_$format"; + die "Don't know how to parse PNM files of format $format" + unless $self->can($method); + return $self->$method($next_line_nocomments); +} + +sub _parse_pnm_P3 { + my $self = shift; + my ($next_line) = @_; + + chomp (my $max = $next_line->()); + die "Invalid max color value: $max" + unless $max =~ /^[0-9]+$/ && $max > 0; + $self->{max} = $max; + + my @words; + my $next_word = sub { + if (!@words) { + chomp(my $line = $next_line->()); + @words = split ' ', $line; + } + my $word = shift @words; + die "Invalid color: $word" unless $word =~ /^[0-9]+$/; + return $word; + }; + + $self->{pixels} = []; + for my $i (1..$self->{w}) { + my $row = []; + for my $j (1..$self->{h}) { + push @$row, [ + $next_word->(), + $next_word->(), + $next_word->(), + ]; + } + push @{ $self->{pixels} }, $row; + } +} + +1; @@ -0,0 +1,23 @@ +#!/usr/bin/env perl +use strict; +use warnings; +use Test::More; + +use Image::PNM; + +my $image = Image::PNM->new('t/data/P3.pnm'); +is($image->as_string('P3'), <<IMAGE); +P3 +8 8 +255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 255 255 255 0 84 255 0 84 255 255 255 255 255 255 255 255 255 255 +255 255 255 255 255 255 0 0 0 255 255 255 255 255 255 0 0 0 255 255 255 255 255 255 +255 255 255 0 0 0 255 255 255 255 255 255 255 255 255 255 255 255 0 0 0 255 255 255 +255 255 255 0 0 0 255 0 0 255 0 0 255 0 0 255 0 0 0 0 0 255 255 255 +255 255 255 0 0 0 255 255 255 255 255 255 255 255 255 255 255 255 0 0 0 255 255 255 +255 255 255 0 0 0 255 255 255 255 255 255 255 255 255 255 255 255 0 0 0 255 255 255 +255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 +IMAGE + +done_testing; diff --git a/t/data/P3.pnm b/t/data/P3.pnm new file mode 100644 index 0000000..df64d54 --- /dev/null +++ b/t/data/P3.pnm @@ -0,0 +1,196 @@ +P3 +# CREATOR: GIMP PNM Filter Version 1.1 +8 8 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +84 +255 +0 +84 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +255 +255 +255 +255 +255 +255 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +255 +255 +255 +255 +255 +255 +0 +0 +0 +255 +0 +0 +255 +0 +0 +255 +0 +0 +255 +0 +0 +0 +0 +0 +255 +255 +255 +255 +255 +255 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +255 +255 +255 +255 +255 +255 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +0 +0 +0 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 +255 |