Push damages IM object in PerlMagick?

Post any defects you find in the released or beta versions of the ImageMagick software here. Include the ImageMagick version, OS, and any command-line required to reproduce the problem. Got a patch for a bug? Post it here.
Post Reply
BrianP007
Posts: 49
Joined: 2013-12-13T09:54:14-07:00
Authentication code: 6789

Push damages IM object in PerlMagick?

Post by BrianP007 »

Hi,
I have a program with 3 IM objects:
A) one to read single files
B) one to accumulate files read by A
c) one to take the take the appended -> stack object B and print it.

This may not be the most optimal design, but it should work.

I have an option to stack N copies of the same object in a loop. It only works if I destroy A and re-read it before pushing it onto B each time.

I have a trivial test program which:
1) clears A, B and C,
2) reads a file into A
3) pushes A onto B N times in a loop
4) appends B, stack=>'true' and places the resulting IM object in C
5) writes C to disk.

C should contain N copies of the picture. It only contains one.

The fix is to expand step 3):
push A onto B
destroy A
Reread A
repeat N times

I know that this simple operation can be done on the command line. I have many stacks, rotations, resizes, etc so need a real programming language, not just shell commands. The object is to solve the mystery of why the IM arrays appear to be misbehaving or why I am abusing them (much more likely).

Here is the log from the misbehaving run:
M:\print\2013.1210>bb.pl 3
Running C:\bin\bb.pl 3 Fri Dec 13 11:06:16 2013
IM sig = "ImageMagick 6.8.7-9 Q16 x64 2013-11-28 http://www.imagemagick.org".
Count = 3, ImageA size = 3600 x 900.
0) Stacking image to @$imageB [1], @$imageA [1].
1) Stacking image to @$imageB [2], @$imageA [1].
2) Stacking image to @$imageB [3], @$imageA [1].
Scalar @{$imageB} = 3.
ImageB[0] size = 3600 x 900.
ImageB[1] size = 3600 x 900.
ImageB[2] size = 3600 x 900.
Append stack -> TRUE. scalar @imageC = 1.
Scalar @{$imageA} = 1.
Scalar @{$imageB} = 3.
Scalar @{$imageC} = 1.
Final image stack.3.jpg X 3600, Y 900. << NOTE: Final image resolution is the same as the original. Only 1 copy. IM B array has 3.
===========================================

here is the correct behavior truncating the A object and rereading the file every time through the loop:

M:\print\2013.1210>bb.pl 3 DESTROY_AND_REREAD
Running C:\bin\bb.pl 3, DESTROY_AND_REREAD Fri Dec 13 11:13:53 2013
IM sig = "ImageMagick 6.8.7-9 Q16 x64 2013-11-28 http://www.imagemagick.org".
Count = 3, ImageA size = 3600 x 900.
0) Stacking image to @$imageB [1], @$imageA [1].
Truncating IA and re-reading.
1) Stacking image to @$imageB [2], @$imageA [1].
Truncating IA and re-reading.
2) Stacking image to @$imageB [3], @$imageA [1].
Truncating IA and re-reading.
Scalar @{$imageB} = 3.
ImageB[0] size = 3600 x 900.
ImageB[1] size = 3600 x 900.
ImageB[2] size = 3600 x 900.
Append stack -> TRUE. scalar @imageC = 1.
Scalar @{$imageA} = 1.
Scalar @{$imageB} = 3.
Scalar @{$imageC} = 1.
Final image stack.3.jpg X 3600, Y 2700. << NOTE: Y dimension is N times the original, 3 copies, not one.

The only difference in the code path is:
  • print("Truncating IA and re-reading.\n");
    @$imagea = ();
    $err = $imagea->Read("$file"); # Read the Fully Qualified Path.
    warn $err if $err;
Another weirdness is that any even number makes 2 copies. Any odd number makes only 1.
Activestate Perl, latest, IM latest:
>perl -v
This is perl 5, version 16, subversion 3 (v5.16.3) built for MSWin32-x64-multi-t...

Here is the full program:

Code: Select all

#!/usr/local/bin/perl -w

use Image::Magick;
use Time::HiRes qw(gettimeofday tv_interval );

$stime = [gettimeofday];  # Current start time to microseconds. 
printf("Running $0 %s %s\n", join(", ", @ARGV), scalar localtime());
$| = 1;

&im_array();  # ImageManick array append problem!

printf("Elapsed time = %4.3f seconds.\n", tv_interval($stime, [gettimeofday]));



sub im_array()  {
	my $imagea = Image::Magick->new;
	my $imageb = Image::Magick->new;
	my $imagec = Image::Magick->new;
	$sig = $imagea->Get('version');
	print("IM sig = \"$sig\".\n");
	@$imagea = @$imageb = @$imagec = ();  # Truncate image arrays.
	my $file = "4/bs-2012.0824-p2c.3x12.jpg";
	my $count = 2;
	$reread = 0;
	my $ii = 0;
	$count  = $ARGV[0]  if $ARGV[0];
	$reread = $ARGV[1]  if $ARGV[1];
	my $ofn = "stack.$count.jpg";

	$err = $imagea->Read("$file");  # Read the Fully Qualified Path.
	warn $err  if $err;
	($xres, $yres) = $imagea->Get('columns', 'Rows');
	print("Count = $count, ImageA size = $xres x $yres.\n");

	for($ii = 0; $ii < $count; $ii++)  {
		push(@$imageb, @$imagea);  # Push current image onto image array.
		printf("$ii) Stacking image to \@\$imageB [%d], \@\$imageA [%d].\n", 
			scalar @$imageb, scalar @$imagea);
		next  unless $reread;
		print("Truncating IA and re-reading.\n");
		@$imagea = ();
		$err = $imagea->Read("$file");  # Read the Fully Qualified Path.
		warn $err  if $err;
	}
	printf("Scalar \@{\$imageB} = %d.\n", scalar @$imageb);
	for($ii = 0; $ii < $count; $ii++)  {
		($xres, $yres) = $imageb->[$ii]->Get('columns', 'Rows');
		print("ImageB[$ii] size = $xres x $yres.\n");
	}
	$imagec = $imageb->Append(stack=>'true');  # Stack TOP to BOTtom.
	printf("Append stack -> TRUE. scalar \@imageC = %d.\n", scalar @$imagec);
	printf("Scalar \@{\$imageA} = %d.\n", scalar @$imagea);
	printf("Scalar \@{\$imageB} = %d.\n", scalar @$imageb);
	printf("Scalar \@{\$imageC} = %d.\n", scalar @$imagec);

	($xres, $yres) = $imagec->Get('columns', 'Rows');
	$err = $imagec->Write("$ofn");
	printf("Final image $ofn X $xres, Y $yres.\n");
}
Post Reply