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

Unified 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/pdf/SkPngPredictors.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/pdf/SkPngPredictors.cpp
diff --git a/src/pdf/SkPngPredictors.cpp b/src/pdf/SkPngPredictors.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..adc49698aaf593f5edc681d17fc182e4f6fe9e5e
--- /dev/null
+++ b/src/pdf/SkPngPredictors.cpp
@@ -0,0 +1,219 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkPngPredictors.h"
+#include "SkTypes.h"
+
+// SkPngPredictors: Implement PNG-style prediction filters on a
+// scanline-by-scanline basis for SkPDF.
+
+// See <https://www.w3.org/TR/PNG/#9Filters> for reference.
+// Where used, a,b,c,x have the same meaning as in the standard.
+
+// "The approach that has by now become standard is known as the
+// minimum sum of absolute differences heuristic and was first
+// proposed by Lee Daniel Crocker in February 1995. In this
+// approach, the filtered bytes are treated as signed [bytes]. The
+// absolute value of each is then summed, and the filter type that
+// produces the smallest sum is chosen."
+
+static int8_t weight(uint8_t x) {
+ return SkTAbs(reinterpret_cast<int8_t&>(x));
+}
+
+// Type:0; Name:None; Filt(x) = Orig(x)
+// BPP == bytes-per-pixel
+// track: iff true, do not write into out; instead calculate "cost" of out.
+template<int BPP, bool track>
+static int none(int width, const uint8_t* prev,
+ const uint8_t* scanline, uint8_t* out) {
+ int64_t w = 0;
+ (void)prev;
+ static_assert(BPP > 0, "");
+ if (track) {
+ const uint8_t* end = &scanline[BPP * width];
+ while (scanline != end) {
+ w += weight(*scanline++);
+ }
+ } else {
+ if (out != scanline) {
+ memcpy(out, scanline, width * BPP);
+ }
+ }
+ return SkToInt(w);
+}
+
+// Type:1; Name:Sub; Filt(x) = Orig(x) - Orig(a)
+template<int BPP, bool track>
+static int sub(int width, const uint8_t* prev,
+ const uint8_t* scanline, uint8_t* out) {
+ static_assert(BPP > 0, "");
+ (void)prev; // not used
+ int64_t w = 0; // Use int64: SkToInt will catch overflow in worst case.
+ uint8_t a[BPP]{}; // a = left
+ const uint8_t* end = &scanline[BPP * width];
+ while (scanline != end) {
+ for (int i = 0; i < BPP; ++i) {
+ uint8_t x = *scanline++;
+ uint8_t v = x - a[i];
+ if (track) { w += weight(v); } else { *out++ = v; }
+ a[i] = x;
+ }
+ }
+ return SkToInt(w);
+}
+// Type:2; Name:Up; Filt(x) = Orig(x) - Orig(b)
+template<int BPP, bool track>
+static int up(int width, const uint8_t* prev,
+ const uint8_t* scanline, uint8_t* out) {
+ if (prev) {
+ int64_t w = 0;
+ const uint8_t* end = &scanline[BPP * width];
+ while (scanline != end) {
+ for (int i = 0; i < BPP; ++i) {
+ uint8_t v = *scanline++ - *prev++;
+ if (track) { w += weight(v); } else { *out++ = v; }
+ }
+ }
+ return SkToInt(w);
+ } else {
+ return none<BPP, track>(width, prev, scanline, out);
+ }
+}
+
+// Type:3; Name:Average; Filt(x) = Orig(x) - floor((Orig(a) + Orig(b)) / 2)
+template<int BPP, bool track>
+static int average(int width, const uint8_t* prev,
+ const uint8_t* scanline, uint8_t* out) {
+ static_assert(BPP > 0, "");
+ int64_t w = 0;
+ const uint8_t* end = &scanline[BPP * width];
+ if (prev) {
+ uint8_t a[BPP]{}; // a = left, b = above
+ while (scanline != end) {
+ for (int i = 0; i < BPP; ++i) {
+ uint8_t x = *scanline++;
+ uint8_t v = x - SkToU8(((int)a[i] + (int)(*prev++)) / 2);
+ if (track) { w += weight(v); } else { *out++ = v; }
+ a[i] = x;
+ }
+ }
+ } else {
+ uint8_t a[BPP]{};
+ while (scanline != end) {
+ for (int i = 0; i < BPP; ++i) {
+ uint8_t x = *scanline++;
+ uint8_t v = x - a[i] / 2; // average with zero.
+ if (track) { w += weight(v); } else { *out++ = v; }
+ a[i] = x;
+ }
+ }
+ }
+ return SkToInt(w);
+}
+
+// Type:4; Name: Paeth;
+// Filt(x) = Orig(x) - PaethPredictor(Orig(a), Orig(b), Orig(c))
+template<int BPP, bool track>
+static int paeth(int width, const uint8_t* prev, const uint8_t* scanline, uint8_t* out) {
+ static_assert(BPP > 0, "");
+ // a = left, b = above, c = upper left
+ if (!prev) {
+ return sub<BPP, track>(width, prev, scanline, out);
+ }
+ int64_t w = 0;
+ uint8_t a[BPP]{}, c[BPP]{};
+ const uint8_t* end = &scanline[BPP * width];
+ while (scanline != end) {
+ for (int i = 0; i < BPP; ++i) {
+ uint8_t b = *prev++;
+ uint8_t x = *scanline++;
+ int pa = SkTAbs<int>(b - c[i]);
+ int pb = SkTAbs<int>(a[i] - c[i]);
+ int pc = SkTAbs<int>((b - c[i]) + (a[i] - c[i]));
+ uint8_t pred = a[i];
+ if (pb < pa) { pred = b; pa = pb; }
+ if (pc < pa) { pred = c[i]; }
+ uint8_t v = x - pred;
+ if (track) { w += weight(v); } else { *out++ = v; }
+ a[i] = x;
+ c[i] = b;
+ }
+ }
+ return SkToInt(w);
+}
+
+// prev == out is okay.
+// prev can be null.
+// Return the type that is used.
+template<int BPP>
+uint8_t png_encode(int width,
+ const uint8_t* prev,
+ const uint8_t* scanline,
+ uint8_t* out) {
+ int scores[5];
+ scores[0] = none<BPP, true>(width, prev, scanline, nullptr);
+ scores[1] = sub<BPP, true>(width, prev, scanline, nullptr);
+ scores[2] = up<BPP, true>(width, prev, scanline, nullptr);
+ scores[3] = average<BPP, true>(width, prev, scanline, nullptr);
+ scores[4] = paeth<BPP, true>(width, prev, scanline, nullptr);
+ uint8_t best = 0;
+ int best_score = scores[0];
+ for (uint8_t i = 1; i < SK_ARRAY_COUNT(scores); ++i) {
+ if (scores[i] < best_score) {
+ best = i;
+ best_score = scores[i];
+ }
+ }
+ // 9087 === 0
+ // 2346 === 1
+ // 6698 === 2
+ // 12747 === 3
+ // 6216 === 4
+ // SkDebugf("=== %d\n", best);
+ switch (best) {
+ case 0:
+ (void)none<BPP, false>(width, prev, scanline, out);
+ return best;
+ case 1:
+ (void)sub<BPP, false>(width, prev, scanline, out);
+ return best;
+ case 2:
+ (void)up<BPP, false>(width, prev, scanline, out);
+ return best;
+ case 3:
+ (void)average<BPP, false>(width, prev, scanline, out);
+ return best;
+ case 4:
+ (void)paeth<BPP, false>(width, prev, scanline, out);
+ return best;
+ }
+ SkASSERT(false);
+ return 0;
+}
+
+uint8_t SkPngEncode3(int width, const uint8_t* prev,
+ const uint8_t* scanline, uint8_t* out) {
+ return png_encode<3>(width, prev, scanline, out);
+}
+
+uint8_t SkPngEncode1(int width, const uint8_t* prev,
+ const uint8_t* scanline, uint8_t* out) {
+ return png_encode<1>(width, prev, scanline, out);
+}
+
+uint8_t SkPaethEncode3(int width, const uint8_t* prev,
+ const uint8_t* scanline, uint8_t* out) {
+ (void)paeth<3, false>(width, prev, scanline, out);
+ return 4;
+}
+
+uint8_t SkPaethEncode1(int width, const uint8_t* prev,
+ const uint8_t* scanline, uint8_t* out) {
+ (void)paeth<1, false>(width, prev, scanline, out);
+ return 4;
+}
« 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