1 /* -*- Mode: c; c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t; -*- */
3 * Copyright © 2009 Mozilla Corporation
5 * Permission to use, copy, modify, distribute, and sell this software and its
6 * documentation for any purpose is hereby granted without fee, provided that
7 * the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation, and that the name of Mozilla Corporation not be used in
10 * advertising or publicity pertaining to distribution of the software without
11 * specific, written prior permission. Mozilla Corporation makes no
12 * representations about the suitability of this software for any purpose. It
13 * is provided "as is" without express or implied warranty.
15 * MOZILLA CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT
17 * SHALL MOZILLA CORPORATION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
19 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
23 * Author: Jeff Muizelaar, Mozilla Corp.
26 //========================================================================
28 // Modified under the Poppler project - http://poppler.freedesktop.org
30 // All changes made under the Poppler project to this file are licensed
31 // under GPL version 2 or later
33 // Copyright (C) 2012 Hib Eris <hib@hiberis.nl>
34 // Copyright (C) 2012 Adrian Johnson <ajohnson@redneon.com>
36 // To see a description of the changes please see the Changelog file that
37 // came with your tarball or type make ChangeLog if you are building from git
39 //========================================================================
42 /* This implements a box filter that supports non-integer box sizes */
54 #include "goo/gtypes_p.h"
55 #include "CairoRescaleBox.h"
58 /* we work in fixed point where 1. == 1 << 24 */
59 #define FIXED_SHIFT 24
62 static void downsample_row_box_filter (
64 uint32_t *src
, uint32_t *dest
,
65 int coverage
[], int pixel_coverage
)
67 /* we need an array of the pixel contribution of each destination pixel on the boundaries.
68 * we invert the value to get the value on the other size of the box */
71 value = a * contribution * 1/box_size
72 value += a * 1/box_size
73 value += a * 1/box_size
74 value += a * 1/box_size
75 value += a * (1 - contribution) * 1/box_size
76 a * (1/box_size - contribution * 1/box_size)
81 value = a * contribtion_a * 1/box_size + b * contribution_b * 1/box_size
82 contribution_b = (1 - contribution_a)
83 = (1 - contribution_a_next)
86 /* box size = ceil(src_width/dest_width) */
90 /* XXX: it might be possible to do this directly instead of iteratively, however
91 * the iterative solution is simple */
94 int box
= 1 << FIXED_SHIFT
;
95 int start_coverage
= coverage
[x
];
96 box
-= start_coverage
;
98 while (box
>= pixel_coverage
)
101 box
-= pixel_coverage
;
106 while (x
< start
+ width
)
112 int box
= 1 << FIXED_SHIFT
;
113 int start_coverage
= coverage
[x
];
115 a
= ((*src
>> 24) & 0xff) * start_coverage
;
116 r
= ((*src
>> 16) & 0xff) * start_coverage
;
117 g
= ((*src
>> 8) & 0xff) * start_coverage
;
118 b
= ((*src
>> 0) & 0xff) * start_coverage
;
121 box
-= start_coverage
;
123 while (box
>= pixel_coverage
)
125 a
+= ((*src
>> 24) & 0xff) * pixel_coverage
;
126 r
+= ((*src
>> 16) & 0xff) * pixel_coverage
;
127 g
+= ((*src
>> 8) & 0xff) * pixel_coverage
;
128 b
+= ((*src
>> 0) & 0xff) * pixel_coverage
;
131 box
-= pixel_coverage
;
134 /* multiply by whatever is leftover
135 * this ensures that we don't bias down.
136 * i.e. start_coverage + n*pixel_coverage + box == 1 << 24 */
139 a
+= ((*src
>> 24) & 0xff) * box
;
140 r
+= ((*src
>> 16) & 0xff) * box
;
141 g
+= ((*src
>> 8) & 0xff) * box
;
142 b
+= ((*src
>> 0) & 0xff) * box
;
150 *dest
= (a
<< 24) | (r
<< 16) | (g
<< 8) | b
;
155 static void downsample_columns_box_filter (
159 uint32_t *src
, uint32_t *dest
)
167 uint32_t *column_src
= src
;
168 int box
= 1 << FIXED_SHIFT
;
170 a
= ((*column_src
>> 24) & 0xff) * start_coverage
;
171 r
= ((*column_src
>> 16) & 0xff) * start_coverage
;
172 g
= ((*column_src
>> 8) & 0xff) * start_coverage
;
173 b
= ((*column_src
>> 0) & 0xff) * start_coverage
;
174 column_src
+= stride
;
175 box
-= start_coverage
;
177 while (box
>= pixel_coverage
)
179 a
+= ((*column_src
>> 24) & 0xff) * pixel_coverage
;
180 r
+= ((*column_src
>> 16) & 0xff) * pixel_coverage
;
181 g
+= ((*column_src
>> 8) & 0xff) * pixel_coverage
;
182 b
+= ((*column_src
>> 0) & 0xff) * pixel_coverage
;
183 column_src
+= stride
;
184 box
-= pixel_coverage
;
188 a
+= ((*column_src
>> 24) & 0xff) * box
;
189 r
+= ((*column_src
>> 16) & 0xff) * box
;
190 g
+= ((*column_src
>> 8) & 0xff) * box
;
191 b
+= ((*column_src
>> 0) & 0xff) * box
;
199 *dest
= (a
<< 24) | (r
<< 16) | (g
<< 8) | b
;
205 static int compute_coverage (int coverage
[], int src_length
, int dest_length
)
208 /* num = src_length/dest_length
209 total = sum(pixel) / num
211 pixel * 1/num == pixel * dest_length / src_length
213 /* the average contribution of each source pixel */
214 int ratio
= ((1 << 24)*(long long int)dest_length
)/src_length
;
215 /* because ((1 << 24)*(long long int)dest_length) won't always be divisible by src_length
216 * we'll need someplace to put the other bits.
218 * We want to ensure a + n*ratio < 1<<24
223 double scale
= (double)src_length
/dest_length
;
225 /* for each destination pixel compute the coverage of the left most pixel included in the box */
226 /* I have a proof of this, which this margin is too narrow to contain */
227 for (i
=0; i
<dest_length
; i
++)
229 float left_side
= i
*scale
;
230 float right_side
= (i
+1)*scale
;
231 float right_fract
= right_side
- floor (right_side
);
232 float left_fract
= ceil (left_side
) - left_side
;
234 /* find out how many source pixels will be used to fill the box */
235 int count
= floor (right_side
) - ceil (left_side
);
236 /* what's the maximum value this expression can become?
237 floor((i+1)*scale) - ceil(i*scale)
239 (i+1)*scale - i*scale == scale
241 since floor((i+1)*scale) <= (i+1)*scale
242 and ceil(i*scale) >= i*scale
244 floor((i+1)*scale) - ceil(i*scale) <= scale
246 further since: floor((i+1)*scale) - ceil(i*scale) is an integer
249 floor((i+1)*scale) - ceil(i*scale) <= floor(scale)
252 if (left_fract
== 0.)
255 /* compute how much the right-most pixel contributes */
256 overage
= ratio
*(right_fract
);
258 /* the remainder is the the amount that the left-most pixel
260 coverage
[i
] = (1<<24) - (count
* ratio
+ overage
);
267 GBool
CairoRescaleBox::downScaleImage(unsigned orig_width
, unsigned orig_height
,
268 signed scaled_width
, signed scaled_height
,
269 unsigned short int start_column
, unsigned short int start_row
,
270 unsigned short int width
, unsigned short int height
,
271 cairo_surface_t
*dest_surface
) {
272 int pixel_coverage_x
, pixel_coverage_y
;
276 int *x_coverage
= NULL
;
277 int *y_coverage
= NULL
;
278 uint32_t *temp_buf
= NULL
;
279 GBool retval
= gFalse
;
283 dest
= (unsigned int *)cairo_image_surface_get_data (dest_surface
);
284 dst_stride
= cairo_image_surface_get_stride (dest_surface
);
286 scanline
= (uint32_t*)gmallocn3 (orig_width
, 1, sizeof(int));
288 x_coverage
= (int *)gmallocn3 (orig_width
, 1, sizeof(int));
289 y_coverage
= (int *)gmallocn3 (orig_height
, 1, sizeof(int));
291 /* we need to allocate enough room for ceil(src_height/dest_height)+1
295 src_height/dest_height = 2.8
297 |-------------| 2.8 pixels
298 |----|----|----|----| 4 pixels
299 need to sample 3 pixels
301 |-------------| 2.8 pixels
302 |----|----|----|----| 4 pixels
303 need to sample 4 pixels
306 temp_buf
= (uint32_t *)gmallocn3 ((orig_height
+ scaled_height
-1)/scaled_height
+1, scaled_width
, sizeof(uint32_t));
308 if (!x_coverage
|| !y_coverage
|| !scanline
|| !temp_buf
)
311 pixel_coverage_x
= compute_coverage (x_coverage
, orig_width
, scaled_width
);
312 pixel_coverage_y
= compute_coverage (y_coverage
, orig_height
, scaled_height
);
314 assert (width
+ start_column
<= scaled_width
);
318 /* skip the rows at the beginning */
319 for (dest_y
= 0; dest_y
< start_row
; dest_y
++)
321 int box
= 1 << FIXED_SHIFT
;
322 int start_coverage_y
= y_coverage
[dest_y
];
323 box
-= start_coverage_y
;
325 while (box
>= pixel_coverage_y
)
327 box
-= pixel_coverage_y
;
332 for (; dest_y
< start_row
+ height
; dest_y
++)
335 int box
= 1 << FIXED_SHIFT
;
336 int start_coverage_y
= y_coverage
[dest_y
];
338 getRow(src_y
, scanline
);
339 downsample_row_box_filter (start_column
, width
, scanline
, temp_buf
+ width
* columns
, x_coverage
, pixel_coverage_x
);
342 box
-= start_coverage_y
;
344 while (box
>= pixel_coverage_y
)
346 getRow(src_y
, scanline
);
347 downsample_row_box_filter (start_column
, width
, scanline
, temp_buf
+ width
* columns
, x_coverage
, pixel_coverage_x
);
350 box
-= pixel_coverage_y
;
353 /* downsample any leftovers */
356 getRow(src_y
, scanline
);
357 downsample_row_box_filter (start_column
, width
, scanline
, temp_buf
+ width
* columns
, x_coverage
, pixel_coverage_x
);
361 /* now scale the rows we just downsampled in the y direction */
362 downsample_columns_box_filter (width
, start_coverage_y
, pixel_coverage_y
, temp_buf
, dest
);
363 dest
+= dst_stride
/ 4;
365 // assert(width*columns <= ((orig_height + scaled_height-1)/scaled_height+1) * width);
367 // assert (src_y<=orig_height);