Merge lp:~jshholland/ubuntu/lucid/poppler/backport-anti-alias into lp:ubuntu/lucid/poppler

Proposed by Josh Holland
Status: Work in progress
Proposed branch: lp:~jshholland/ubuntu/lucid/poppler/backport-anti-alias
Merge into: lp:ubuntu/lucid/poppler
Diff against target: 534 lines (+522/-0)
2 files modified
debian/changelog (+7/-0)
debian/patches/backport-anti-alias.patch (+515/-0)
To merge this branch: bzr merge lp:~jshholland/ubuntu/lucid/poppler/backport-anti-alias
Reviewer Review Type Date Requested Status
James Westby (community) Needs Fixing
Sebastien Bacher Pending
Review via email: mp+22511@code.launchpad.net

Description of the change

To post a comment you must log in.
Revision history for this message
James Westby (james-w) wrote :

From the bug report:

"Josh: Your patch modifies Makefile.am without updating Makefile.in or causing the packaging to run automake. So it fails to build the new object and dies with a linker error.

After fixing that, it seems to work for me on the examples from this bug, such as ubuntu-manual-draft.pdf.

I would suggest annotating the patch to say where it came from:
https://wiki.ubuntu.com/UbuntuDevelopment/PatchTaggingGuidelines"

Thanks,

James

review: Needs Fixing
80. By Josh Holland

Tagged patch as https://wiki.ubuntu.com/UbuntuDevelopment/PatchTaggingGuidelines

Unmerged revisions

80. By Josh Holland

Tagged patch as https://wiki.ubuntu.com/UbuntuDevelopment/PatchTaggingGuidelines

79. By Josh Holland

Fixed bug number

78. By Josh Holland

Add backport-anti-alias.patch: Fix anti aliasing (fixed in upstream git)
(LP: #248335)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'debian/changelog'
--- debian/changelog 2010-03-19 13:51:55 +0000
+++ debian/changelog 2010-03-31 09:29:27 +0000
@@ -1,3 +1,10 @@
1poppler (0.12.4-0ubuntu3) lucid; urgency=low
2
3 * Add backport-anti-alias.patch: Fix anti aliasing (fixed in upstream git)
4 (LP: #248355)
5
6 -- Josh Holland <jrh@joshh.co.uk> Tue, 30 Mar 2010 23:35:59 +0100
7
1poppler (0.12.4-0ubuntu2) lucid; urgency=low8poppler (0.12.4-0ubuntu2) lucid; urgency=low
29
3 * Add psname-escape-backslash.patch: Don't use '\' character in PostScript10 * Add psname-escape-backslash.patch: Don't use '\' character in PostScript
411
=== added file 'debian/patches/backport-anti-alias.patch'
--- debian/patches/backport-anti-alias.patch 1970-01-01 00:00:00 +0000
+++ debian/patches/backport-anti-alias.patch 2010-03-31 09:29:27 +0000
@@ -0,0 +1,515 @@
1From: Carlos Garcia Campos <carlosgc@gnome.org>
2Subject: Anti-alias graphics in PDF documents
3Origin: upstream, http://bugs.freedesktop.org/attachment.cgi?id=32750
4Bug: http://bugs.freedesktop.org/show_bug.cgi?id=5589
5Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/poppler/+bug/248355
6diff -Nur -x '*.orig' -x '*~' poppler/poppler/CairoOutputDev.cc poppler.new/poppler/CairoOutputDev.cc
7--- poppler/poppler/CairoOutputDev.cc 2010-03-30 23:08:49.306054000 +0100
8+++ poppler.new/poppler/CairoOutputDev.cc 2010-03-30 23:22:56.511527017 +0100
9@@ -58,6 +58,7 @@
10 #include <splash/SplashBitmap.h>
11 #include "CairoOutputDev.h"
12 #include "CairoFontEngine.h"
13+#include "CairoRescaleBox.h"
14 //------------------------------------------------------------------------
15
16 // #define LOG_CAIRO
17@@ -1291,6 +1292,82 @@
18 clearSoftMask(state);
19 }
20
21+cairo_surface_t *CairoOutputDev::downscaleSurface(cairo_surface_t *orig_surface) {
22+ cairo_surface_t *dest_surface;
23+ unsigned char *dest_buffer;
24+ int dest_stride;
25+ unsigned char *orig_buffer;
26+ int orig_width, orig_height;
27+ int orig_stride;
28+ GBool res;
29+
30+ if (printing)
31+ return NULL;
32+
33+ cairo_matrix_t matrix;
34+ cairo_get_matrix(cairo, &matrix);
35+
36+ /* this whole computation should be factored out */
37+ double xScale = matrix.xx;
38+ double yScale = matrix.yy;
39+ int tx, tx2, ty, ty2; /* the integer co-oridinates of the resulting image */
40+ int scaledHeight;
41+ int scaledWidth;
42+ if (xScale >= 0) {
43+ tx = splashRound(matrix.x0 - 0.01);
44+ tx2 = splashRound(matrix.x0 + xScale + 0.01) - 1;
45+ } else {
46+ tx = splashRound(matrix.x0 + 0.01) - 1;
47+ tx2 = splashRound(matrix.x0 + xScale - 0.01);
48+ }
49+ scaledWidth = abs(tx2 - tx) + 1;
50+ //scaledWidth = splashRound(fabs(xScale));
51+ if (scaledWidth == 0) {
52+ // technically, this should draw nothing, but it generally seems
53+ // better to draw a one-pixel-wide stripe rather than throwing it
54+ // away
55+ scaledWidth = 1;
56+ }
57+ if (yScale >= 0) {
58+ ty = splashFloor(matrix.y0 + 0.01);
59+ ty2 = splashCeil(matrix.y0 + yScale - 0.01);
60+ } else {
61+ ty = splashCeil(matrix.y0 - 0.01);
62+ ty2 = splashFloor(matrix.y0 + yScale + 0.01);
63+ }
64+ scaledHeight = abs(ty2 - ty);
65+ if (scaledHeight == 0) {
66+ scaledHeight = 1;
67+ }
68+
69+ orig_width = cairo_image_surface_get_width (orig_surface);
70+ orig_height = cairo_image_surface_get_height (orig_surface);
71+ if (scaledWidth >= orig_width || scaledHeight >= orig_height)
72+ return NULL;
73+
74+ dest_surface = cairo_surface_create_similar (orig_surface,
75+ cairo_surface_get_content (orig_surface),
76+ scaledWidth, scaledHeight);
77+ dest_buffer = cairo_image_surface_get_data (dest_surface);
78+ dest_stride = cairo_image_surface_get_stride (dest_surface);
79+
80+ orig_buffer = cairo_image_surface_get_data (orig_surface);
81+ orig_stride = cairo_image_surface_get_stride (orig_surface);
82+
83+ res = downscale_box_filter((uint32_t *)orig_buffer,
84+ orig_stride, orig_width, orig_height,
85+ scaledWidth, scaledHeight, 0, 0,
86+ scaledWidth, scaledHeight,
87+ (uint32_t *)dest_buffer, dest_stride);
88+ if (!res) {
89+ cairo_surface_destroy (dest_surface);
90+ return NULL;
91+ }
92+
93+ return dest_surface;
94+
95+}
96+
97 void CairoOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
98 int width, int height, GBool invert,
99 GBool interpolate, GBool inlineImg) {
100@@ -2043,6 +2120,18 @@
101 }
102 gfree(lookup);
103
104+ cairo_surface_t *scaled_surface;
105+
106+ scaled_surface = downscaleSurface (image);
107+ if (scaled_surface) {
108+ if (cairo_surface_status (scaled_surface))
109+ goto cleanup;
110+ cairo_surface_destroy (image);
111+ image = scaled_surface;
112+ width = cairo_image_surface_get_width (image);
113+ height = cairo_image_surface_get_height (image);
114+ }
115+
116 cairo_surface_mark_dirty (image);
117 pattern = cairo_pattern_create_for_surface (image);
118 cairo_surface_destroy (image);
119diff -Nur -x '*.orig' -x '*~' poppler/poppler/CairoOutputDev.h poppler.new/poppler/CairoOutputDev.h
120--- poppler/poppler/CairoOutputDev.h 2010-03-30 23:08:49.306054000 +0100
121+++ poppler.new/poppler/CairoOutputDev.h 2010-03-30 23:22:56.531526906 +0100
122@@ -268,6 +268,7 @@
123
124 protected:
125 void doPath(cairo_t *cairo, GfxState *state, GfxPath *path);
126+ cairo_surface_t *downscaleSurface(cairo_surface_t *orig_surface);
127
128 GfxRGB fill_color, stroke_color;
129 cairo_pattern_t *fill_pattern, *stroke_pattern;
130diff -Nur -x '*.orig' -x '*~' poppler/poppler/CairoRescaleBox.cc poppler.new/poppler/CairoRescaleBox.cc
131--- poppler/poppler/CairoRescaleBox.cc 1970-01-01 01:00:00.000000000 +0100
132+++ poppler.new/poppler/CairoRescaleBox.cc 2010-03-30 23:22:56.559527323 +0100
133@@ -0,0 +1,352 @@
134+/* -*- Mode: c; c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t; -*- */
135+/*
136+ * Copyright © 2009 Mozilla Corporation
137+ *
138+ * Permission to use, copy, modify, distribute, and sell this software and its
139+ * documentation for any purpose is hereby granted without fee, provided that
140+ * the above copyright notice appear in all copies and that both that
141+ * copyright notice and this permission notice appear in supporting
142+ * documentation, and that the name of Mozilla Corporation not be used in
143+ * advertising or publicity pertaining to distribution of the software without
144+ * specific, written prior permission. Mozilla Corporation makes no
145+ * representations about the suitability of this software for any purpose. It
146+ * is provided "as is" without express or implied warranty.
147+ *
148+ * MOZILLA CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
149+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT
150+ * SHALL MOZILLA CORPORATION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
151+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
152+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
153+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
154+ * OF THIS SOFTWARE.
155+ *
156+ * Author: Jeff Muizelaar, Mozilla Corp.
157+ */
158+
159+/* This implements a box filter that supports non-integer box sizes */
160+
161+#ifdef HAVE_CONFIG_H
162+#include <config.h>
163+#endif
164+
165+#include <stdint.h>
166+#include <stdio.h>
167+#include <assert.h>
168+#include <stdlib.h>
169+#include <math.h>
170+#include "goo/gmem.h"
171+#include "CairoRescaleBox.h"
172+
173+typedef unsigned short int uint16_t;
174+typedef unsigned int uint32_t;
175+
176+/* we work in fixed point where 1. == 1 << 24 */
177+#define FIXED_SHIFT 24
178+
179+static void downsample_row_box_filter (
180+ int start, int width,
181+ uint32_t *src, uint32_t *dest,
182+ int coverage[], int pixel_coverage)
183+{
184+ /* we need an array of the pixel contribution of each destination pixel on the boundaries.
185+ * we invert the value to get the value on the other size of the box */
186+ /*
187+
188+ value = a * contribution * 1/box_size
189+ value += a * 1/box_size
190+ value += a * 1/box_size
191+ value += a * 1/box_size
192+ value += a * (1 - contribution) * 1/box_size
193+ a * (1/box_size - contribution * 1/box_size)
194+
195+ box size is constant
196+
197+
198+ value = a * contribtion_a * 1/box_size + b * contribution_b * 1/box_size
199+ contribution_b = (1 - contribution_a)
200+ = (1 - contribution_a_next)
201+ */
202+
203+ /* box size = ceil(src_width/dest_width) */
204+ int x = 0;
205+
206+ /* skip to start */
207+ /* XXX: it might be possible to do this directly instead of iteratively, however
208+ * the iterative solution is simple */
209+ while (x < start)
210+ {
211+ int box = 1 << FIXED_SHIFT;
212+ int start_coverage = coverage[x];
213+ box -= start_coverage;
214+ src++;
215+ while (box >= pixel_coverage)
216+ {
217+ src++;
218+ box -= pixel_coverage;
219+ }
220+ x++;
221+ }
222+
223+ while (x < start + width)
224+ {
225+ uint32_t a = 0;
226+ uint32_t r = 0;
227+ uint32_t g = 0;
228+ uint32_t b = 0;
229+ int box = 1 << FIXED_SHIFT;
230+ int start_coverage = coverage[x];
231+
232+ a = ((*src >> 24) & 0xff) * start_coverage;
233+ r = ((*src >> 16) & 0xff) * start_coverage;
234+ g = ((*src >> 8) & 0xff) * start_coverage;
235+ b = ((*src >> 0) & 0xff) * start_coverage;
236+ src++;
237+ x++;
238+ box -= start_coverage;
239+
240+ while (box >= pixel_coverage)
241+ {
242+ a += ((*src >> 24) & 0xff) * pixel_coverage;
243+ r += ((*src >> 16) & 0xff) * pixel_coverage;
244+ g += ((*src >> 8) & 0xff) * pixel_coverage;
245+ b += ((*src >> 0) & 0xff) * pixel_coverage;
246+ src++;
247+
248+ box -= pixel_coverage;
249+ }
250+
251+ /* multiply by whatever is leftover
252+ * this ensures that we don't bias down.
253+ * i.e. start_coverage + n*pixel_coverage + box == 1 << 24 */
254+ if (box > 0)
255+ {
256+ a += ((*src >> 24) & 0xff) * box;
257+ r += ((*src >> 16) & 0xff) * box;
258+ g += ((*src >> 8) & 0xff) * box;
259+ b += ((*src >> 0) & 0xff) * box;
260+ }
261+
262+ a >>= FIXED_SHIFT;
263+ r >>= FIXED_SHIFT;
264+ g >>= FIXED_SHIFT;
265+ b >>= FIXED_SHIFT;
266+
267+ *dest = (a << 24) | (r << 16) | (g << 8) | b;
268+ dest++;
269+ }
270+}
271+
272+static void downsample_columns_box_filter (
273+ int n,
274+ int start_coverage,
275+ int pixel_coverage,
276+ uint32_t *src, uint32_t *dest)
277+{
278+ int stride = n;
279+ while (n--) {
280+ uint32_t a = 0;
281+ uint32_t r = 0;
282+ uint32_t g = 0;
283+ uint32_t b = 0;
284+ uint32_t *column_src = src;
285+ int box = 1 << FIXED_SHIFT;
286+
287+ a = ((*column_src >> 24) & 0xff) * start_coverage;
288+ r = ((*column_src >> 16) & 0xff) * start_coverage;
289+ g = ((*column_src >> 8) & 0xff) * start_coverage;
290+ b = ((*column_src >> 0) & 0xff) * start_coverage;
291+ column_src += stride;
292+ box -= start_coverage;
293+
294+ while (box >= pixel_coverage)
295+ {
296+ a += ((*column_src >> 24) & 0xff) * pixel_coverage;
297+ r += ((*column_src >> 16) & 0xff) * pixel_coverage;
298+ g += ((*column_src >> 8) & 0xff) * pixel_coverage;
299+ b += ((*column_src >> 0) & 0xff) * pixel_coverage;
300+ column_src += stride;
301+ box -= pixel_coverage;
302+ }
303+
304+ if (box > 0) {
305+ a += ((*column_src >> 24) & 0xff) * box;
306+ r += ((*column_src >> 16) & 0xff) * box;
307+ g += ((*column_src >> 8) & 0xff) * box;
308+ b += ((*column_src >> 0) & 0xff) * box;
309+ }
310+
311+ a >>= FIXED_SHIFT;
312+ r >>= FIXED_SHIFT;
313+ g >>= FIXED_SHIFT;
314+ b >>= FIXED_SHIFT;
315+
316+ *dest = (a << 24) | (r << 16) | (g << 8) | b;
317+ dest++;
318+ src++;
319+ }
320+}
321+
322+static int compute_coverage (int coverage[], int src_length, int dest_length)
323+{
324+ int i;
325+ /* num = src_length/dest_length
326+ total = sum(pixel) / num
327+
328+ pixel * 1/num == pixel * dest_length / src_length
329+ */
330+ /* the average contribution of each source pixel */
331+ int ratio = ((1 << 24)*(long long int)dest_length)/src_length;
332+ /* because ((1 << 24)*(long long int)dest_length) won't always be divisible by src_length
333+ * we'll need someplace to put the other bits.
334+ *
335+ * We want to ensure a + n*ratio < 1<<24
336+ *
337+ * 1<<24
338+ * */
339+
340+ double scale = (double)src_length/dest_length;
341+
342+ /* for each destination pixel compute the coverage of the left most pixel included in the box */
343+ /* I have a proof of this, which this margin is too narrow to contain */
344+ for (i=0; i<dest_length; i++)
345+ {
346+ float left_side = i*scale;
347+ float right_side = (i+1)*scale;
348+ float right_fract = right_side - floor (right_side);
349+ float left_fract = ceil (left_side) - left_side;
350+ int overage;
351+ /* find out how many source pixels will be used to fill the box */
352+ int count = floor (right_side) - ceil (left_side);
353+ /* what's the maximum value this expression can become?
354+ floor((i+1)*scale) - ceil(i*scale)
355+
356+ (i+1)*scale - i*scale == scale
357+
358+ since floor((i+1)*scale) <= (i+1)*scale
359+ and ceil(i*scale) >= i*scale
360+
361+ floor((i+1)*scale) - ceil(i*scale) <= scale
362+
363+ further since: floor((i+1)*scale) - ceil(i*scale) is an integer
364+
365+ therefore:
366+ floor((i+1)*scale) - ceil(i*scale) <= floor(scale)
367+ */
368+
369+ if (left_fract == 0.)
370+ count--;
371+
372+ /* compute how much the right-most pixel contributes */
373+ overage = ratio*(right_fract);
374+
375+ /* the remainder is the the amount that the left-most pixel
376+ * contributes */
377+ coverage[i] = (1<<24) - (count * ratio + overage);
378+ }
379+
380+ return ratio;
381+}
382+
383+GBool downscale_box_filter(uint32_t *orig, int orig_stride, unsigned orig_width, unsigned orig_height,
384+ signed scaled_width, signed scaled_height,
385+ uint16_t start_column, uint16_t start_row,
386+ uint16_t width, uint16_t height,
387+ uint32_t *dest, int dst_stride)
388+{
389+ int pixel_coverage_x, pixel_coverage_y;
390+ int dest_y;
391+ int src_y = 0;
392+ uint32_t *scanline = orig;
393+ int *x_coverage = NULL;
394+ int *y_coverage = NULL;
395+ uint32_t *temp_buf = NULL;
396+ GBool retval = gFalse;
397+
398+ x_coverage = (int *)gmallocn3 (orig_width, 1, sizeof(int));
399+ y_coverage = (int *)gmallocn3 (orig_height, 1, sizeof(int));
400+
401+ /* we need to allocate enough room for ceil(src_height/dest_height)+1
402+ Example:
403+ src_height = 140
404+ dest_height = 50
405+ src_height/dest_height = 2.8
406+
407+ |-------------| 2.8 pixels
408+ |----|----|----|----| 4 pixels
409+ need to sample 3 pixels
410+
411+ |-------------| 2.8 pixels
412+ |----|----|----|----| 4 pixels
413+ need to sample 4 pixels
414+ */
415+
416+ temp_buf = (uint32_t *)gmallocn3 ((orig_height + scaled_height-1)/scaled_height+1, scaled_width, sizeof(uint32_t));
417+
418+ if (!x_coverage || !y_coverage || !scanline || !temp_buf)
419+ goto cleanup;
420+
421+ pixel_coverage_x = compute_coverage (x_coverage, orig_width, scaled_width);
422+ pixel_coverage_y = compute_coverage (y_coverage, orig_height, scaled_height);
423+
424+ assert (width + start_column <= scaled_width);
425+
426+ /* skip the rows at the beginning */
427+ for (dest_y = 0; dest_y < start_row; dest_y++)
428+ {
429+ int box = 1 << FIXED_SHIFT;
430+ int start_coverage_y = y_coverage[dest_y];
431+ box -= start_coverage_y;
432+ src_y++;
433+ while (box >= pixel_coverage_y)
434+ {
435+ box -= pixel_coverage_y;
436+ src_y++;
437+ }
438+ }
439+
440+ for (; dest_y < start_row + height; dest_y++)
441+ {
442+ int columns = 0;
443+ int box = 1 << FIXED_SHIFT;
444+ int start_coverage_y = y_coverage[dest_y];
445+
446+ scanline = orig + src_y * orig_stride / 4;
447+ downsample_row_box_filter (start_column, width, scanline, temp_buf + width * columns, x_coverage, pixel_coverage_x);
448+ columns++;
449+ src_y++;
450+ box -= start_coverage_y;
451+
452+ while (box >= pixel_coverage_y)
453+ {
454+ scanline = orig + src_y * orig_stride / 4;
455+ downsample_row_box_filter (start_column, width, scanline, temp_buf + width * columns, x_coverage, pixel_coverage_x);
456+ columns++;
457+ src_y++;
458+ box -= pixel_coverage_y;
459+ }
460+
461+ /* downsample any leftovers */
462+ if (box > 0)
463+ {
464+ scanline = orig + src_y * orig_stride / 4;
465+ downsample_row_box_filter (start_column, width, scanline, temp_buf + width * columns, x_coverage, pixel_coverage_x);
466+ columns++;
467+ }
468+
469+ /* now scale the rows we just downsampled in the y direction */
470+ downsample_columns_box_filter (width, start_coverage_y, pixel_coverage_y, temp_buf, dest);
471+ dest += dst_stride / 4;
472+
473+// assert(width*columns <= ((orig_height + scaled_height-1)/scaled_height+1) * width);
474+ }
475+// assert (src_y<=orig_height);
476+
477+ retval = gTrue;
478+
479+cleanup:
480+ free (x_coverage);
481+ free (y_coverage);
482+ free (temp_buf);
483+
484+ return gTrue;
485+}
486diff -Nur -x '*.orig' -x '*~' poppler/poppler/CairoRescaleBox.h poppler.new/poppler/CairoRescaleBox.h
487--- poppler/poppler/CairoRescaleBox.h 1970-01-01 01:00:00.000000000 +0100
488+++ poppler.new/poppler/CairoRescaleBox.h 2010-03-30 23:22:56.559527323 +0100
489@@ -0,0 +1,12 @@
490+#ifndef CAIRO_RESCALE_BOX_H
491+#define CAIRO_RESCALE_BOX_H
492+
493+#include "goo/gtypes.h"
494+
495+GBool downscale_box_filter(unsigned int *orig, int orig_stride, unsigned orig_width, unsigned orig_height,
496+ signed scaled_width, signed scaled_height,
497+ unsigned short int start_column, unsigned short int start_row,
498+ unsigned short int width, unsigned short int height,
499+ unsigned int *dest, int dst_stride);
500+
501+#endif /* CAIRO_RESCALE_BOX_H */
502diff -Nur -x '*.orig' -x '*~' poppler/poppler/Makefile.am poppler.new/poppler/Makefile.am
503--- poppler/poppler/Makefile.am 2010-03-30 23:08:49.306054000 +0100
504+++ poppler.new/poppler/Makefile.am 2010-03-30 23:22:56.559527323 +0100
505@@ -47,7 +47,9 @@
506 CairoFontEngine.cc \
507 CairoFontEngine.h \
508 CairoOutputDev.cc \
509- CairoOutputDev.h
510+ CairoOutputDev.h \
511+ CairoRescaleBox.cc \
512+ CairoRescaleBox.h
513
514 endif
515

Subscribers

People subscribed via source and target branches

to all changes: