@@ -536,15 +536,15 @@ vips_reducev_gen( VipsRegion *out_region, void *vseq,
536
536
s.left = r->left ;
537
537
s.top = r->top * reducev->vshrink ;
538
538
s.width = r->width ;
539
- s.height = r->height * reducev->vshrink + reducev->n_point
540
- + reducev->voffset ;
539
+ s.height = r->height * reducev->vshrink + reducev->n_point -
540
+ reducev->voffset ;
541
541
if ( vips_region_prepare ( ir, &s ) )
542
542
return ( -1 );
543
543
544
544
VIPS_GATE_START ( " vips_reducev_gen: work" );
545
545
546
- double Y = (r->top + 0.5 ) * reducev->vshrink - 0.5
547
- + reducev->voffset ;
546
+ double Y = (r->top + 0.5 ) * reducev->vshrink - 0.5 -
547
+ reducev->voffset ;
548
548
549
549
for ( int y = 0 ; y < r->height ; y++ ) {
550
550
VipsPel *q =
@@ -651,8 +651,8 @@ vips_reducev_vector_gen( VipsRegion *out_region, void *vseq,
651
651
s.left = r->left ;
652
652
s.top = r->top * reducev->vshrink ;
653
653
s.width = r->width ;
654
- s.height = r->height * reducev->vshrink + reducev->n_point
655
- + reducev->voffset ;
654
+ s.height = r->height * reducev->vshrink + reducev->n_point -
655
+ reducev->voffset ;
656
656
if ( vips_region_prepare ( ir, &s ) )
657
657
return ( -1 );
658
658
@@ -667,8 +667,8 @@ vips_reducev_vector_gen( VipsRegion *out_region, void *vseq,
667
667
668
668
VIPS_GATE_START ( " vips_reducev_vector_gen: work" );
669
669
670
- double Y = (r->top + 0.5 ) * reducev->vshrink - 0.5
671
- + reducev->voffset ;
670
+ double Y = (r->top + 0.5 ) * reducev->vshrink - 0.5 -
671
+ reducev->voffset ;
672
672
673
673
for ( int y = 0 ; y < r->height ; y++ ) {
674
674
VipsPel *q =
@@ -732,41 +732,7 @@ vips_reducev_raw( VipsReducev *reducev, VipsImage *in, VipsImage **out )
732
732
733
733
VipsGenerateFn generate;
734
734
735
- /* Build masks.
736
- */
737
- for ( int y = 0 ; y < VIPS_TRANSFORM_SCALE; y++ ) {
738
- reducev->matrixf [y] =
739
- VIPS_ARRAY ( NULL , reducev->n_point , double );
740
- if ( !reducev->matrixf [y] )
741
- return ( -1 );
742
-
743
- vips_reduce_make_mask ( reducev->matrixf [y],
744
- reducev->kernel , reducev->vshrink ,
745
- (float ) y / VIPS_TRANSFORM_SCALE );
746
-
747
- #ifdef DEBUG
748
- printf ( " %6.2g" , (double ) y / VIPS_TRANSFORM_SCALE );
749
- for ( int i = 0 ; i < reducev->n_point ; i++ )
750
- printf ( " , %6.2g" , reducev->matrixf [y][i] );
751
- printf ( " \n " );
752
- #endif /* DEBUG*/
753
- }
754
-
755
- /* uchar and ushort need an int version of the masks.
756
- */
757
- if ( VIPS_IMAGE_SIZEOF_ELEMENT ( in ) <= 2 )
758
- for ( int y = 0 ; y < VIPS_TRANSFORM_SCALE; y++ ) {
759
- reducev->matrixi [y] =
760
- VIPS_ARRAY ( NULL , reducev->n_point , int );
761
- if ( !reducev->matrixi [y] )
762
- return ( -1 );
763
-
764
- vips_vector_to_fixed_point (
765
- reducev->matrixf [y], reducev->matrixi [y],
766
- reducev->n_point , VIPS_INTERPOLATE_SCALE );
767
- }
768
-
769
- /* And we need an 2.6 version if we will use the vector path.
735
+ /* We need an 2.6 version if we will use the vector path.
770
736
*/
771
737
if ( in->BandFmt == VIPS_FORMAT_UCHAR &&
772
738
vips_vector_isenabled () )
@@ -836,7 +802,7 @@ vips_reducev_build( VipsObject *object )
836
802
VipsImage **t = (VipsImage **) vips_object_local_array ( object, 4 );
837
803
838
804
VipsImage *in;
839
- double top ;
805
+ double height, extra_pixels ;
840
806
841
807
if ( VIPS_OBJECT_CLASS ( vips_reducev_parent_class )->build ( object ) )
842
808
return ( -1 );
@@ -861,21 +827,63 @@ vips_reducev_build( VipsObject *object )
861
827
return ( -1 );
862
828
}
863
829
830
+ /* Output size. We need to always round to nearest, so round(), not
831
+ * rint().
832
+ */
833
+ height = VIPS_ROUND_UINT (
834
+ (double ) resample->in ->Ysize / reducev->vshrink );
835
+
836
+ /* How many pixels we are inventing in the input, -ve for
837
+ * discarding.
838
+ */
839
+ extra_pixels =
840
+ height * reducev->vshrink - resample->in ->Ysize ;
841
+
842
+ /* If we are rounding down, we are not using some input
843
+ * pixels. We need to move the origin *inside* the input image
844
+ * by half that distance so that we discard pixels equally
845
+ * from left and right.
846
+ */
847
+ reducev->voffset = (1 + extra_pixels) / 2.0 ;
848
+
849
+ /* Build the tables of pre-computed coefficients.
850
+ */
851
+ for ( int y = 0 ; y < VIPS_TRANSFORM_SCALE; y++ ) {
852
+ reducev->matrixf [y] =
853
+ VIPS_ARRAY ( NULL , reducev->n_point , double );
854
+ reducev->matrixi [y] =
855
+ VIPS_ARRAY ( NULL , reducev->n_point , int );
856
+ if ( !reducev->matrixf [y] ||
857
+ !reducev->matrixi [y] )
858
+ return ( -1 );
859
+
860
+ vips_reduce_make_mask ( reducev->matrixf [y],
861
+ reducev->kernel , reducev->vshrink ,
862
+ (float ) y / VIPS_TRANSFORM_SCALE );
863
+
864
+ for ( int i = 0 ; i < reducev->n_point ; i++ )
865
+ reducev->matrixi [y][i] = reducev->matrixf [y][i] *
866
+ VIPS_INTERPOLATE_SCALE;
867
+
868
+ #ifdef DEBUG
869
+ printf ( " vips_reducev_raw: mask %d\n " , y );
870
+ for ( int i = 0 ; i < reducev->n_point ; i++ )
871
+ printf ( " %d " , reducev->matrixi [y][i] );
872
+ printf ( " \n " );
873
+ #endif /* DEBUG*/
874
+ }
875
+
864
876
/* Unpack for processing.
865
877
*/
866
878
if ( vips_image_decode ( in, &t[0 ] ) )
867
879
return ( -1 );
868
880
in = t[0 ];
869
881
870
- top = reducev->n_point / 2.0 - 1 ;
871
- reducev->voffset -= modf ( top, &top );
872
- printf ( " voffset: %f\n " , reducev->voffset );
873
-
874
882
/* Add new pixels around the input so we can interpolate at the edges.
875
883
*/
876
884
if ( vips_embed ( in, &t[1 ],
877
- 0 , top ,
878
- in->Xsize , in->Ysize + reducev->n_point + reducev-> voffset ,
885
+ 0 , reducev-> n_point / 2 - 1 ,
886
+ in->Xsize , in->Ysize + reducev->n_point ,
879
887
" extend" , VIPS_EXTEND_COPY,
880
888
(void *) NULL ) )
881
889
return ( -1 );
@@ -946,13 +954,6 @@ vips_reducev_class_init( VipsReducevClass *reducev_class )
946
954
G_STRUCT_OFFSET ( VipsReducev, kernel ),
947
955
VIPS_TYPE_KERNEL, VIPS_KERNEL_LANCZOS3 );
948
956
949
- VIPS_ARG_DOUBLE ( reducev_class, " voffset" , 5 ,
950
- _ ( " Offset" ),
951
- _ ( " Vertical displacement" ),
952
- VIPS_ARGUMENT_OPTIONAL_INPUT,
953
- G_STRUCT_OFFSET ( VipsReducev, voffset ),
954
- -10000000 , 10000000 , 0 );
955
-
956
957
/* Old name.
957
958
*/
958
959
VIPS_ARG_DOUBLE ( reducev_class, " yshrink" , 3 ,
@@ -977,7 +978,6 @@ static void
977
978
vips_reducev_init ( VipsReducev *reducev )
978
979
{
979
980
reducev->kernel = VIPS_KERNEL_LANCZOS3;
980
- reducev->voffset = 0.0 ;
981
981
}
982
982
983
983
/* See reduce.c for the doc comment.
0 commit comments