Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(345)

Side by Side Diff: src/pdf/SkPngPredictors.cpp

Issue 1686313005: SkPDF: Implement Paeth predictor for images. (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: 2016-02-25 (Thursday) 14:57:16 EST Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/pdf/SkPngPredictors.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Copyright 2016 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "SkPngPredictors.h"
9 #include "SkTypes.h"
10
11 // SkPngPredictors: Implement PNG-style prediction filters on a
12 // scanline-by-scanline basis for SkPDF.
13
14 // See <https://www.w3.org/TR/PNG/#9Filters> for reference.
15 // Where used, a,b,c,x have the same meaning as in the standard.
16
17 // "The approach that has by now become standard is known as the
18 // minimum sum of absolute differences heuristic and was first
19 // proposed by Lee Daniel Crocker in February 1995. In this
20 // approach, the filtered bytes are treated as signed [bytes]. The
21 // absolute value of each is then summed, and the filter type that
22 // produces the smallest sum is chosen."
23
24 static int8_t weight(uint8_t x) {
25 return SkTAbs(reinterpret_cast<int8_t&>(x));
26 }
27
28 // Type:0; Name:None; Filt(x) = Orig(x)
29 // BPP == bytes-per-pixel
30 // track: iff true, do not write into out; instead calculate "cost" of out.
31 template<int BPP, bool track>
32 static int none(int width, const uint8_t* prev,
33 const uint8_t* scanline, uint8_t* out) {
34 int64_t w = 0;
35 (void)prev;
36 static_assert(BPP > 0, "");
37 if (track) {
38 const uint8_t* end = &scanline[BPP * width];
39 while (scanline != end) {
40 w += weight(*scanline++);
41 }
42 } else {
43 if (out != scanline) {
44 memcpy(out, scanline, width * BPP);
45 }
46 }
47 return SkToInt(w);
48 }
49
50 // Type:1; Name:Sub; Filt(x) = Orig(x) - Orig(a)
51 template<int BPP, bool track>
52 static int sub(int width, const uint8_t* prev,
53 const uint8_t* scanline, uint8_t* out) {
54 static_assert(BPP > 0, "");
55 (void)prev; // not used
56 int64_t w = 0; // Use int64: SkToInt will catch overflow in worst case.
57 uint8_t a[BPP]{}; // a = left
58 const uint8_t* end = &scanline[BPP * width];
59 while (scanline != end) {
60 for (int i = 0; i < BPP; ++i) {
61 uint8_t x = *scanline++;
62 uint8_t v = x - a[i];
63 if (track) { w += weight(v); } else { *out++ = v; }
64 a[i] = x;
65 }
66 }
67 return SkToInt(w);
68 }
69 // Type:2; Name:Up; Filt(x) = Orig(x) - Orig(b)
70 template<int BPP, bool track>
71 static int up(int width, const uint8_t* prev,
72 const uint8_t* scanline, uint8_t* out) {
73 if (prev) {
74 int64_t w = 0;
75 const uint8_t* end = &scanline[BPP * width];
76 while (scanline != end) {
77 for (int i = 0; i < BPP; ++i) {
78 uint8_t v = *scanline++ - *prev++;
79 if (track) { w += weight(v); } else { *out++ = v; }
80 }
81 }
82 return SkToInt(w);
83 } else {
84 return none<BPP, track>(width, prev, scanline, out);
85 }
86 }
87
88 // Type:3; Name:Average; Filt(x) = Orig(x) - floor((Orig(a) + Orig(b)) / 2)
89 template<int BPP, bool track>
90 static int average(int width, const uint8_t* prev,
91 const uint8_t* scanline, uint8_t* out) {
92 static_assert(BPP > 0, "");
93 int64_t w = 0;
94 const uint8_t* end = &scanline[BPP * width];
95 if (prev) {
96 uint8_t a[BPP]{}; // a = left, b = above
97 while (scanline != end) {
98 for (int i = 0; i < BPP; ++i) {
99 uint8_t x = *scanline++;
100 uint8_t v = x - SkToU8(((int)a[i] + (int)(*prev++)) / 2);
101 if (track) { w += weight(v); } else { *out++ = v; }
102 a[i] = x;
103 }
104 }
105 } else {
106 uint8_t a[BPP]{};
107 while (scanline != end) {
108 for (int i = 0; i < BPP; ++i) {
109 uint8_t x = *scanline++;
110 uint8_t v = x - a[i] / 2; // average with zero.
111 if (track) { w += weight(v); } else { *out++ = v; }
112 a[i] = x;
113 }
114 }
115 }
116 return SkToInt(w);
117 }
118
119 // Type:4; Name: Paeth;
120 // Filt(x) = Orig(x) - PaethPredictor(Orig(a), Orig(b), Orig(c))
121 template<int BPP, bool track>
122 static int paeth(int width, const uint8_t* prev, const uint8_t* scanline, uint8_ t* out) {
123 static_assert(BPP > 0, "");
124 // a = left, b = above, c = upper left
125 if (!prev) {
126 return sub<BPP, track>(width, prev, scanline, out);
127 }
128 int64_t w = 0;
129 uint8_t a[BPP]{}, c[BPP]{};
130 const uint8_t* end = &scanline[BPP * width];
131 while (scanline != end) {
132 for (int i = 0; i < BPP; ++i) {
133 uint8_t b = *prev++;
134 uint8_t x = *scanline++;
135 int pa = SkTAbs<int>(b - c[i]);
136 int pb = SkTAbs<int>(a[i] - c[i]);
137 int pc = SkTAbs<int>((b - c[i]) + (a[i] - c[i]));
138 uint8_t pred = a[i];
139 if (pb < pa) { pred = b; pa = pb; }
140 if (pc < pa) { pred = c[i]; }
141 uint8_t v = x - pred;
142 if (track) { w += weight(v); } else { *out++ = v; }
143 a[i] = x;
144 c[i] = b;
145 }
146 }
147 return SkToInt(w);
148 }
149
150 // prev == out is okay.
151 // prev can be null.
152 // Return the type that is used.
153 template<int BPP>
154 uint8_t png_encode(int width,
155 const uint8_t* prev,
156 const uint8_t* scanline,
157 uint8_t* out) {
158 int scores[5];
159 scores[0] = none<BPP, true>(width, prev, scanline, nullptr);
160 scores[1] = sub<BPP, true>(width, prev, scanline, nullptr);
161 scores[2] = up<BPP, true>(width, prev, scanline, nullptr);
162 scores[3] = average<BPP, true>(width, prev, scanline, nullptr);
163 scores[4] = paeth<BPP, true>(width, prev, scanline, nullptr);
164 uint8_t best = 0;
165 int best_score = scores[0];
166 for (uint8_t i = 1; i < SK_ARRAY_COUNT(scores); ++i) {
167 if (scores[i] < best_score) {
168 best = i;
169 best_score = scores[i];
170 }
171 }
172 // 9087 === 0
173 // 2346 === 1
174 // 6698 === 2
175 // 12747 === 3
176 // 6216 === 4
177 // SkDebugf("=== %d\n", best);
178 switch (best) {
179 case 0:
180 (void)none<BPP, false>(width, prev, scanline, out);
181 return best;
182 case 1:
183 (void)sub<BPP, false>(width, prev, scanline, out);
184 return best;
185 case 2:
186 (void)up<BPP, false>(width, prev, scanline, out);
187 return best;
188 case 3:
189 (void)average<BPP, false>(width, prev, scanline, out);
190 return best;
191 case 4:
192 (void)paeth<BPP, false>(width, prev, scanline, out);
193 return best;
194 }
195 SkASSERT(false);
196 return 0;
197 }
198
199 uint8_t SkPngEncode3(int width, const uint8_t* prev,
200 const uint8_t* scanline, uint8_t* out) {
201 return png_encode<3>(width, prev, scanline, out);
202 }
203
204 uint8_t SkPngEncode1(int width, const uint8_t* prev,
205 const uint8_t* scanline, uint8_t* out) {
206 return png_encode<1>(width, prev, scanline, out);
207 }
208
209 uint8_t SkPaethEncode3(int width, const uint8_t* prev,
210 const uint8_t* scanline, uint8_t* out) {
211 (void)paeth<3, false>(width, prev, scanline, out);
212 return 4;
213 }
214
215 uint8_t SkPaethEncode1(int width, const uint8_t* prev,
216 const uint8_t* scanline, uint8_t* out) {
217 (void)paeth<1, false>(width, prev, scanline, out);
218 return 4;
219 }
OLDNEW
« no previous file with comments | « src/pdf/SkPngPredictors.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698