summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Luehrs <doy@tozt.net>2014-10-07 13:29:26 -0400
committerJesse Luehrs <doy@tozt.net>2014-10-07 13:29:26 -0400
commit35a0bc2f82802800bdb0769882d667d59313f141 (patch)
tree7e861ca1c3f9a23366adc3dbfd1b881c813bbccf
parent3151013be7b78d79f5c0db3d5e7b95b2714dc88f (diff)
downloadimage-pnm-35a0bc2f82802800bdb0769882d667d59313f141.tar.gz
image-pnm-35a0bc2f82802800bdb0769882d667d59313f141.zip
initial sketch
-rw-r--r--lib/Image/PNM.pm139
-rw-r--r--t/P3.t23
-rw-r--r--t/data/P3.pnm196
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;
diff --git a/t/P3.t b/t/P3.t
new file mode 100644
index 0000000..5712ace
--- /dev/null
+++ b/t/P3.t
@@ -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