|
4 | 4 | * - from join.c
|
5 | 5 | * 6/9/21
|
6 | 6 | * - minmise inputs once we've used them
|
| 7 | + * 29/12/22 |
| 8 | + * - much faster with large arrays |
7 | 9 | */
|
8 | 10 |
|
9 | 11 | /*
|
@@ -80,43 +82,67 @@ static int
|
80 | 82 | vips_arrayjoin_gen( VipsRegion *or, void *seq,
|
81 | 83 | void *a, void *b, gboolean *stop )
|
82 | 84 | {
|
83 |
| - VipsRegion **ir = (VipsRegion **) seq; |
| 85 | + VipsImage **in = (VipsImage **) a; |
84 | 86 | VipsArrayjoin *join = (VipsArrayjoin *) b;
|
85 | 87 | VipsConversion *conversion = VIPS_CONVERSION( join );
|
86 | 88 | VipsRect *r = &or->valid;
|
87 |
| - |
88 | 89 | int n;
|
89 |
| - VipsImage **in; |
| 90 | + |
| 91 | + /* Find the left/top/width/height of the cells this region touches. |
| 92 | + */ |
| 93 | + int cell_width = join->hspacing + join->shim; |
| 94 | + int cell_height = join->vspacing + join->shim; |
| 95 | + int left = r->left / cell_width; |
| 96 | + int top = r->top / cell_height; |
| 97 | + int width = (VIPS_ROUND_UP( VIPS_RECT_RIGHT( r ), cell_width ) - |
| 98 | + VIPS_ROUND_DOWN( r->left, cell_width )) / cell_width; |
| 99 | + int height = (VIPS_ROUND_UP( VIPS_RECT_BOTTOM( r ), cell_height ) - |
| 100 | + VIPS_ROUND_DOWN( r->top, cell_height )) / cell_height; |
| 101 | + |
90 | 102 | int i;
|
91 |
| - gboolean just_one; |
| 103 | + VipsRegion *reg; |
92 | 104 |
|
93 |
| - in = vips_array_image_get( join->in, &n ); |
| 105 | + /* Size of image array. |
| 106 | + */ |
| 107 | + vips_array_image_get( join->in, &n ); |
94 | 108 |
|
95 |
| - /* Does this rect fit completely within one of our inputs? |
| 109 | + /* Does this rect fit completely within one of our inputs? We can just |
| 110 | + * forward the request. |
96 | 111 | */
|
97 |
| - just_one = FALSE; |
98 |
| - for( i = 0; i < n; i++ ) |
99 |
| - if( vips_rect_includesrect( &join->rects[i], r ) ) { |
100 |
| - just_one = TRUE; |
101 |
| - break; |
| 112 | + if( width == 1 && height == 1 ) { |
| 113 | + i = VIPS_MIN( n - 1, left + top * join->across ); |
| 114 | + |
| 115 | + reg = vips_region_new( in[i] ); |
| 116 | + |
| 117 | + if( vips__insert_just_one( or, reg, |
| 118 | + join->rects[i].left, join->rects[i].top ) ) { |
| 119 | + g_object_unref( reg ); |
| 120 | + return( -1 ); |
102 | 121 | }
|
103 | 122 |
|
104 |
| - if( just_one ) { |
105 |
| - /* Just needs one input, we can forward the request to that |
106 |
| - * region. |
107 |
| - */ |
108 |
| - if( vips__insert_just_one( or, ir[i], |
109 |
| - join->rects[i].left, join->rects[i].top ) ) |
110 |
| - return( -1 ); |
| 123 | + g_object_unref( reg ); |
111 | 124 | }
|
112 | 125 | else {
|
113 | 126 | /* Output requires more than one input. Paste all touching
|
114 | 127 | * inputs into the output.
|
115 | 128 | */
|
116 |
| - for( i = 0; i < n; i++ ) |
117 |
| - if( vips__insert_paste_region( or, ir[i], |
118 |
| - &join->rects[i] ) ) |
119 |
| - return( -1 ); |
| 129 | + int x, y; |
| 130 | + |
| 131 | + for( y = 0; y < height; y++ ) |
| 132 | + for( x = 0; x < width; x++ ) { |
| 133 | + i = VIPS_MIN( n - 1, |
| 134 | + x + left + (y + top) * join->across ); |
| 135 | + |
| 136 | + reg = vips_region_new( in[i] ); |
| 137 | + |
| 138 | + if( vips__insert_paste_region( or, reg, |
| 139 | + &join->rects[i] ) ) { |
| 140 | + g_object_unref( reg ); |
| 141 | + return( -1 ); |
| 142 | + } |
| 143 | + |
| 144 | + g_object_unref( reg ); |
| 145 | + } |
120 | 146 | }
|
121 | 147 |
|
122 | 148 | if( vips_image_is_sequential( conversion->out ) )
|
@@ -320,9 +346,12 @@ vips_arrayjoin_build( VipsObject *object )
|
320 | 346 | conversion->out->Xsize = output_width;
|
321 | 347 | conversion->out->Ysize = output_height;
|
322 | 348 |
|
| 349 | + /* DOn't use start_many -- the set of input images can be huge (many |
| 350 | + * 10s of 1000s) and we don't want to have 20,000 regions active. It's |
| 351 | + * much quicker to make them on demand. |
| 352 | + */ |
323 | 353 | if( vips_image_generate( conversion->out,
|
324 |
| - vips_start_many, vips_arrayjoin_gen, vips_stop_many, |
325 |
| - size, join ) ) |
| 354 | + NULL, vips_arrayjoin_gen, NULL, size, join ) ) |
326 | 355 | return( -1 );
|
327 | 356 |
|
328 | 357 | return( 0 );
|
|
0 commit comments