From: Tony Cook Date: Tue, 24 Nov 2009 08:02:16 +0000 (+0000) Subject: - use scanline oriented operations to flip images instead of pixel X-Git-Tag: Imager-0.72~10 X-Git-Url: http://git.imager.perl.org/imager.git/commitdiff_plain/e41cfe8fad4ecd916d92abf3d8d92685c064dcde - use scanline oriented operations to flip images instead of pixel operations https://rt.cpan.org/Ticket/Display.html?id=39278 - use double/sample operations to flip large sample images instead of 8-bit sample operations. https://rt.cpan.org/Ticket/Display.html?id=39280 --- diff --git a/Changes b/Changes index ae33a08a..c9bdfbe1 100644 --- a/Changes +++ b/Changes @@ -1,5 +1,18 @@ Imager release history. Older releases can be found in Changes.old +Imager 0.72 - unreleased +=========== + +Bug fixes: + + - use scanline oriented operations to flip images instead of pixel + operations + https://rt.cpan.org/Ticket/Display.html?id=39278 + + - use double/sample operations to flip large sample images instead of + 8-bit sample operations. + https://rt.cpan.org/Ticket/Display.html?id=39280 + Imager 0.71 - 16 Nov 2009 =========== diff --git a/Imager.xs b/Imager.xs index 539836a3..f6733ed6 100644 --- a/Imager.xs +++ b/Imager.xs @@ -1868,7 +1868,10 @@ i_img_diff(im1,im2) Imager::ImgRaw im1 Imager::ImgRaw im2 - +double +i_img_diffd(im1,im2) + Imager::ImgRaw im1 + Imager::ImgRaw im2 undef_int i_init_fonts(t1log=0) diff --git a/MANIFEST b/MANIFEST index eda895fc..b0f0077c 100644 --- a/MANIFEST +++ b/MANIFEST @@ -105,6 +105,7 @@ feat.h fills.c Generic fills filterlist.perl filters.im +flip.im font.c fontfiles/ExistenceTest.afm please edit ExistenceTest.sfd in CVS fontfiles/ExistenceTest.pfb to change these files, edited and diff --git a/Makefile.PL b/Makefile.PL index 327c2a99..0b71b807 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -168,7 +168,7 @@ my @objs = qw(Imager.o draw.o polygon.o image.o io.o iolayer.o regmach.o trans2.o quant.o error.o convert.o map.o tags.o palimg.o maskimg.o img16.o rotate.o bmp.o tga.o color.o fills.o imgdouble.o limits.o hlines.o - imext.o scale.o rubthru.o render.o paste.o compose.o); + imext.o scale.o rubthru.o render.o paste.o compose.o flip.o); my %opts=( 'NAME' => 'Imager', diff --git a/flip.im b/flip.im new file mode 100644 index 00000000..c3df8f7f --- /dev/null +++ b/flip.im @@ -0,0 +1,192 @@ +#include "imager.h" + +static void flip_h(i_img *im); +static void flip_v(i_img *im); +static void flip_hv(i_img *im); + +#define XAXIS 0 +#define YAXIS 1 +#define XYAXIS 2 + +/* +=item i_flipxy(im, axis) + +Flips the image inplace around the axis specified. +Returns 0 if parameters are invalid. + + im - Image pointer + axis - 0 = x, 1 = y, 2 = both + +=cut +*/ + +undef_int +i_flipxy(i_img *im, int direction) { + i_clear_error(); + + mm_log((1, "i_flipxy(im %p, direction %d)\n", im, direction )); + + if (!im) + return 0; + + switch (direction) { + case XAXIS: /* Horizontal flip */ + flip_h(im); + break; + + case YAXIS: /* Vertical flip */ + flip_v(im); + break; + + case XYAXIS: /* Horizontal and Vertical flip */ + flip_hv(im); + break; + + default: + mm_log((1, "i_flipxy: direction is invalid\n" )); + i_push_errorf(0, "direction %d invalid", direction); + return 0; + + } + return 1; +} + +static void +flip_row_pal(i_palidx *row, i_img_dim width) { + i_palidx tmp; + i_palidx *leftp = row; + i_palidx *rightp = row + width - 1; + + while (leftp < rightp) { + tmp = *leftp; + *leftp = *rightp; + *rightp = tmp; + ++leftp; + --rightp; + } +} + +#code + +static void +IM_SUFFIX(flip_row)(IM_COLOR *row, i_img_dim width) { + IM_COLOR tmp; + IM_COLOR *leftp = row; + IM_COLOR *rightp = row + width - 1; + + while (leftp < rightp) { + tmp = *leftp; + *leftp = *rightp; + *rightp = tmp; + ++leftp; + --rightp; + } +} + +#/code + +static void +flip_h(i_img *im) { + int y; + if (im->type == i_palette_type) { + i_palidx *line = mymalloc(im->xsize * sizeof(i_palidx)); + for (y = 0; y < im->ysize; ++y) { + i_gpal(im, 0, im->xsize, y, line); + flip_row_pal(line, im->xsize); + i_ppal(im, 0, im->xsize, y, line); + } + myfree(line); + } + else { +#code im->bits == i_8_bits + IM_COLOR *line = mymalloc(im->xsize * sizeof(IM_COLOR)); + for (y = 0; y < im->ysize; ++y) { + IM_GLIN(im, 0, im->xsize, y, line); + IM_SUFFIX(flip_row)(line, im->xsize); + IM_PLIN(im, 0, im->xsize, y, line); + } + myfree(line); +#/code + } +} + +static void +flip_v(i_img *im) { + int topy = 0; + int boty = im->ysize - 1; + if (im->type == i_palette_type) { + i_palidx *top_line = mymalloc(im->xsize * sizeof(i_palidx)); + i_palidx *bot_line = mymalloc(im->xsize * sizeof(i_palidx)); + while (topy < boty) { + i_gpal(im, 0, im->xsize, topy, top_line); + i_gpal(im, 0, im->xsize, boty, bot_line); + i_ppal(im, 0, im->xsize, topy, bot_line); + i_ppal(im, 0, im->xsize, boty, top_line); + ++topy; + --boty; + } + myfree(bot_line); + myfree(top_line); + } + else { +#code im->bits == i_8_bits + IM_COLOR *top_line = mymalloc(im->xsize * sizeof(IM_COLOR)); + IM_COLOR *bot_line = mymalloc(im->xsize * sizeof(IM_COLOR)); + while (topy < boty) { + IM_GLIN(im, 0, im->xsize, topy, top_line); + IM_GLIN(im, 0, im->xsize, boty, bot_line); + IM_PLIN(im, 0, im->xsize, topy, bot_line); + IM_PLIN(im, 0, im->xsize, boty, top_line); + ++topy; + --boty; + } + myfree(top_line); + myfree(bot_line); +#/code + } +} + +static void +flip_hv(i_img *im) { + int topy = 0; + int boty = im->ysize - 1; + if (im->type == i_palette_type) { + i_palidx *top_line = mymalloc(im->xsize * sizeof(i_palidx)); + i_palidx *bot_line = mymalloc(im->xsize * sizeof(i_palidx)); + while (topy < boty) { + i_gpal(im, 0, im->xsize, topy, top_line); + i_gpal(im, 0, im->xsize, boty, bot_line); + flip_row_pal(top_line, im->xsize); + flip_row_pal(bot_line, im->xsize); + i_ppal(im, 0, im->xsize, topy, bot_line); + i_ppal(im, 0, im->xsize, boty, top_line); + ++topy; + --boty; + } + myfree(bot_line); + myfree(top_line); + } + else { +#code im->bits == i_8_bits + IM_COLOR *top_line = mymalloc(im->xsize * sizeof(IM_COLOR)); + IM_COLOR *bot_line = mymalloc(im->xsize * sizeof(IM_COLOR)); + while (topy < boty) { + IM_GLIN(im, 0, im->xsize, topy, top_line); + IM_GLIN(im, 0, im->xsize, boty, bot_line); + IM_SUFFIX(flip_row)(top_line, im->xsize); + IM_SUFFIX(flip_row)(bot_line, im->xsize); + IM_PLIN(im, 0, im->xsize, topy, bot_line); + IM_PLIN(im, 0, im->xsize, boty, top_line); + ++topy; + --boty; + } + if (topy == boty) { + IM_GLIN(im, 0, im->xsize, topy, top_line); + IM_SUFFIX(flip_row)(top_line, im->xsize); + IM_PLIN(im, 0, im->xsize, topy, top_line); + } + myfree(top_line); + myfree(bot_line); +#/code + } +} diff --git a/image.c b/image.c index e6d5345d..55c0864b 100644 --- a/image.c +++ b/image.c @@ -709,114 +709,6 @@ i_copy(i_img *src) { } -/* -=item i_flipxy(im, axis) - -Flips the image inplace around the axis specified. -Returns 0 if parameters are invalid. - - im - Image pointer - axis - 0 = x, 1 = y, 2 = both - -=cut -*/ - -undef_int -i_flipxy(i_img *im, int direction) { - int x, x2, y, y2, xm, ym; - int xs = im->xsize; - int ys = im->ysize; - - mm_log((1, "i_flipxy(im %p, direction %d)\n", im, direction )); - - if (!im) return 0; - - switch (direction) { - case XAXIS: /* Horizontal flip */ - xm = xs/2; - ym = ys; - for(y=0; yxsizexsize)?im1->xsize:im2->xsize; + yb=(im1->ysizeysize)?im1->ysize:im2->ysize; + chb=(im1->channelschannels)?im1->channels:im2->channels; + + mm_log((1,"i_img_diff: xb=%d xy=%d chb=%d\n",xb,yb,chb)); + + tdiff=0; + for(y=0;ynew; @@ -304,6 +305,22 @@ sub is_image_similar($$$$) { . $right->getchannels); return; } + + return 1; +} + +sub is_image_similar($$$$) { + my ($left, $right, $limit, $comment) = @_; + + { + local $Test::Builder::Level = $Test::Builder::Level + 1; + + _low_image_diff_check($left, $right, $comment) + or return; + } + + my $builder = Test::Builder->new; + my $diff = Imager::i_img_diff($left->{IMG}, $right->{IMG}); if ($diff > $limit) { $builder->ok(0, $comment); @@ -338,6 +355,42 @@ sub is_image($$$) { return is_image_similar($left, $right, 0, $comment); } +sub is_imaged($$$) { + my ($left, $right, $comment) = @_; + + { + local $Test::Builder::Level = $Test::Builder::Level + 1; + + _low_image_diff_check($left, $right, $comment) + or return; + } + + my $builder = Test::Builder->new; + + my $diff = Imager::i_img_diffd($left->{IMG}, $right->{IMG}); + if ($diff > 0) { + $builder->ok(0, $comment); + $builder->diag("image data difference: $diff"); + + # find the first mismatch + PIXELS: + for my $y (0 .. $left->getheight()-1) { + for my $x (0.. $left->getwidth()-1) { + my @lsamples = $left->getsamples(x => $x, y => $y, width => 1); + my @rsamples = $right->getsamples(x => $x, y => $y, width => 1); + if ("@lsamples" ne "@rsamples") { + $builder->diag("first mismatch at ($x, $y) - @lsamples vs @rsamples"); + last PIXELS; + } + } + } + + return; + } + + return $builder->ok(1, $comment); +} + sub image_bounds_checks { my $im = shift; @@ -554,6 +607,11 @@ each pixel. The color comparison is done at 8-bits per pixel. The color representation such as direct vs paletted, bits per sample are not checked. Equivalent to is_image_similar($im1, $im2, 0, $comment). +=item is_imaged($im, $im2, $comment) + +Tests if the two images have the same content at the double/sample +level. + =item is_image_similar($im1, $im2, $maxdiff, $comment) Tests if the 2 images have similar content. Both images must be diff --git a/t/t64copyflip.t b/t/t64copyflip.t index bc9a65d0..87149842 100644 --- a/t/t64copyflip.t +++ b/t/t64copyflip.t @@ -1,8 +1,8 @@ #!perl -w use strict; -use Test::More tests => 65; +use Test::More tests => 69; use Imager; -use Imager::Test qw(is_color3); +use Imager::Test qw(is_color3 is_image is_imaged test_image_double); #$Imager::DEBUG=1; @@ -17,27 +17,32 @@ ok($nimg, "copy returned something"); # test if ->copy() works my $diff = Imager::i_img_diff($img->{IMG}, $nimg->{IMG}); -is($diff, 0, "copy matches source"); - +is_image($img, $nimg, "copy matches source"); # test if ->flip(dir=>'h')->flip(dir=>'h') doesn't alter the image - $nimg->flip(dir=>"h")->flip(dir=>"h"); -$diff = Imager::i_img_diff($img->{IMG}, $nimg->{IMG}); -is($diff, 0, "double horiz flipped matches original"); +is_image($nimg, $img, "double horiz flipped matches original"); # test if ->flip(dir=>'v')->flip(dir=>'v') doesn't alter the image - $nimg->flip(dir=>"v")->flip(dir=>"v"); -$diff = Imager::i_img_diff($img->{IMG}, $nimg->{IMG}); -is($diff, 0, "double vertically flipped image matches original"); +is_image($nimg, $img, "double vertically flipped image matches original"); # test if ->flip(dir=>'h')->flip(dir=>'v') is same as ->flip(dir=>'hv') - $nimg->flip(dir=>"v")->flip(dir=>"h")->flip(dir=>"hv");; -$diff = Imager::i_img_diff($img->{IMG}, $nimg->{IMG}); -is($diff, 0, "check flip with hv matches flip v then flip h"); +is_image($img, $nimg, "check flip with hv matches flip v then flip h"); + +{ + my $imsrc = test_image_double; + my $imcp = $imsrc->copy; + is_imaged($imsrc, $imcp, "copy double image"); + $imcp->flip(dir=>"v")->flip(dir=>"v"); + is_imaged($imsrc, $imcp, "flip v twice"); + $imcp->flip(dir=>"h")->flip(dir=>"h"); + is_imaged($imsrc, $imcp, "flip h twice"); + $imcp->flip(dir=>"h")->flip(dir=>"v")->flip(dir=>"hv"); + is_imaged($imsrc, $imcp, "flip h,v,hv twice"); +} rot_test($img, 90, 4); rot_test($img, 180, 2);