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

Proposed by Josh Holland on 2010-03-31
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) 2010-03-31 Needs Fixing on 2010-03-31
Sebastien Bacher 2010-03-31 Pending
Review via email: mp+22511@code.launchpad.net

Description of the change

To post a comment you must log in.
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 on 2010-03-31

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

Unmerged revisions

80. By Josh Holland on 2010-03-31

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

79. By Josh Holland on 2010-03-30

Fixed bug number

78. By Josh Holland on 2010-03-30

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

Subscribers

People subscribed via source and target branches

to all changes: