Acme-Steganography-Image-Png
view release on metacpan or search on metacpan
use vars qw($VERSION @ISA);
use Imager;
require Class::Accessor;
use Carp;
@ISA = qw(Class::Accessor);
$VERSION = '0.06';
my @keys = qw(offset data section x y datum_length done filename_generator
suffix);
# What arguments can we accept to the constructor.
# Am I reinventing the wheel here?
my %keys;
@keys{@keys} = ();
sub _keys {
return \%keys;
}
Acme::Steganography::Image::Png->mk_accessors(@keys);
# This will get refactored out at some point to support other formats.
sub generate_header {
my ($self) = shift;
my $section = $self->section;
my $header = pack 'w', $section;
if (!$section) {
$header .= pack 'w', length ${$self->data};
}
$header;
}
sub default_filename_generator {
my $state = shift;
$state ||= 0;
my $new_state = $state+1;
# really unimaginative filenames by default
$datum .= substr ${$self->data()}, $offset, $grab;
$self->offset($offset + $grab);
if (length $datum < $datum_length) {
# Need to pad it. NUL is so uninspiring.
$datum .= "N" x ($datum_length - length $datum);
$self->done(1);
} elsif (length ${$self->data()} == $self->offset) {
warn length $datum;
}
$self->section($self->section + 1);
$self->make_image($datum);
}
sub new {
my $class = shift;
croak "Use a classname, not a reference for " . __PACKAGE__ . "::new"
if ref $class;
my $self = bless {}, $class;
my %args = @_;
$self;
}
sub type {
'png';
}
sub write_images {
my $self = shift;
$self->section(0);
$self->offset(0);
$self->datum_length($self->calculate_datum_length());
my $type = $self->type;
my $filename_generator
= $self->filename_generator || \&default_filename_generator;
my @filenames;
my ($filename, $state);
while (!$self->done()) {
my $class = shift;
# This is intentionally a "sparse" array to avoid some "interesting" DOS
# possibilities.
my $length;
my %got;
foreach my $file (@_) {
my $img = new Imager;
$img->open(file => $file) or carp "Can't read '$file': " . $img->errstr;
my $payload = $class->extract_payload($img);
my $datum;
my $section;
($section, $datum) = unpack "wa*", $payload;
if ($section == 0) {
# Oops. Strip off the length.
($length, $datum) = unpack "wa*", $datum;
}
$got{$section} = $datum;
}
carp "Did not find first section in files @_" unless defined $length;
my $data = join '', map {$got{$_}} sort {$a <=> $b} keys %got;
substr ($data, $length) = '';
$data;
}
1;
__END__
my @filenames = $writer->write_images("Camouflage.jpg");
# Returns a list of the filenames it wrote to
# Then read them back.
my $reread =
Acme::Steganography::Image::Png::RGB::556->read_files(@files);
=head1 DESCRIPTION
Acme::Steganography::Image::Png is extremely ineffective at hiding your
secrets inside Png images.
There are 4 implementations
=over 4
=item Acme::Steganography::Image::Png::FlashingNeonSignGrey
Blatantly stuffs your data into greyscale PNG files with absolutely no attempt
to hide it.
Acme::Steganography::Image::Png version 0.06
============================================
Acme::Steganography::Image::Png is extremely ineffective at hiding your
secrets inside Png images.
If you want real steganography, you're in the wrong place.
INSTALLATION
To install this module type the following:
perl Makefile.PL
make
make test
( run in 2.180 seconds using v1.01-cache-2.11-cpan-5837b0d9d2c )