aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gyp/tools.gyp21
-rw-r--r--tools/imgblur.cpp83
-rw-r--r--tools/sk_tool_utils.cpp94
-rw-r--r--tools/sk_tool_utils.h5
4 files changed, 201 insertions, 2 deletions
diff --git a/gyp/tools.gyp b/gyp/tools.gyp
index accdd61681..8685570347 100644
--- a/gyp/tools.gyp
+++ b/gyp/tools.gyp
@@ -24,9 +24,11 @@
'filter',
'flatten',
'gpuveto',
+ 'imgblur',
+ 'imgconv',
+ 'imgslice',
'lua_app',
'lua_pictures',
- 'imgconv',
'pinspect',
'render_pdfs',
'render_pictures',
@@ -36,7 +38,6 @@
'skpdiff',
'skpinfo',
'skpmaker',
- 'imgslice',
'test_image_decoder',
'test_public_includes',
'whitelist_typefaces',
@@ -313,6 +314,22 @@
],
},
{
+ 'target_name': 'imgblur',
+ 'type': 'executable',
+ 'sources': [
+ '../tools/imgblur.cpp',
+ ],
+ 'include_dirs': [
+ '../include/core',
+ ],
+ 'dependencies': [
+ 'flags.gyp:flags',
+ 'flags.gyp:flags_common',
+ 'skia_lib.gyp:skia_lib',
+ 'tools.gyp:sk_tool_utils',
+ ],
+ },
+ {
'target_name': 'imgslice',
'type': 'executable',
'sources': [
diff --git a/tools/imgblur.cpp b/tools/imgblur.cpp
new file mode 100644
index 0000000000..5ee8b12370
--- /dev/null
+++ b/tools/imgblur.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkCommandLineFlags.h"
+#include "SkCommonFlags.h"
+#include "SkImageDecoder.h"
+#include "SkStream.h"
+#include "SkTypes.h"
+
+#include "sk_tool_utils.h"
+
+DEFINE_string(in, "input.png", "Input image");
+DEFINE_string(out, "blurred.png", "Output image");
+DEFINE_double(sigma, 1, "Sigma to be used for blur (> 0.0f)");
+
+
+// This tool just performs a blur on an input image
+// Return codes:
+static const int kSuccess = 0;
+static const int kError = 1;
+
+int tool_main(int argc, char** argv);
+int tool_main(int argc, char** argv) {
+ SkCommandLineFlags::SetUsage("Brute force blur of an image.");
+ SkCommandLineFlags::Parse(argc, argv);
+
+ if (FLAGS_sigma <= 0) {
+ if (!FLAGS_quiet) {
+ SkDebugf("Sigma must be greater than zero (it is %f).\n", FLAGS_sigma);
+ }
+ return kError;
+ }
+
+ SkFILEStream inputStream(FLAGS_in[0]);
+ if (!inputStream.isValid()) {
+ if (!FLAGS_quiet) {
+ SkDebugf("Couldn't open file: %s\n", FLAGS_in[0]);
+ }
+ return kError;
+ }
+
+ SkAutoTDelete<SkImageDecoder> codec(SkImageDecoder::Factory(&inputStream));
+ if (!codec) {
+ if (!FLAGS_quiet) {
+ SkDebugf("Couldn't create codec for: %s.\n", FLAGS_in[0]);
+ }
+ return kError;
+ }
+
+ SkBitmap src;
+
+ inputStream.rewind();
+ SkImageDecoder::Result res = codec->decode(&inputStream, &src,
+ kN32_SkColorType,
+ SkImageDecoder::kDecodePixels_Mode);
+ if (SkImageDecoder::kSuccess != res) {
+ if (!FLAGS_quiet) {
+ SkDebugf("Couldn't decode image: %s.\n", FLAGS_in[0]);
+ }
+ return kError;
+ }
+
+ SkBitmap dst = sk_tool_utils::slow_blur(src, (float) FLAGS_sigma);
+
+ if (!SkImageEncoder::EncodeFile(FLAGS_out[0], dst, SkImageEncoder::kPNG_Type, 100)) {
+ if (!FLAGS_quiet) {
+ SkDebugf("Couldn't write to file: %s\n", FLAGS_out[0]);
+ }
+ return kError;
+ }
+
+ return kSuccess;
+}
+
+#if !defined SK_BUILD_FOR_IOS
+int main(int argc, char * const argv[]) {
+ return tool_main(argc, (char**) argv);
+}
+#endif
diff --git a/tools/sk_tool_utils.cpp b/tools/sk_tool_utils.cpp
index 710c204271..9a667b4a45 100644
--- a/tools/sk_tool_utils.cpp
+++ b/tools/sk_tool_utils.cpp
@@ -349,4 +349,98 @@ void make_big_path(SkPath& path) {
#include "BigPathBench.inc"
}
+static float gaussian2d_value(int x, int y, float sigma) {
+ // don't bother with the scale term since we're just going to normalize the
+ // kernel anyways
+ float temp = exp(-(x*x + y*y)/(2*sigma*sigma));
+ return temp;
+}
+
+static float* create_2d_kernel(float sigma, int* filterSize) {
+ // We will actually take 2*halfFilterSize+1 samples (i.e., our filter kernel
+ // sizes are always odd)
+ int halfFilterSize = SkScalarCeilToInt(6*sigma)/2;
+ int wh = *filterSize = 2*halfFilterSize + 1;
+
+ float* temp = new float[wh*wh];
+
+ float filterTot = 0.0f;
+ for (int yOff = 0; yOff < wh; ++yOff) {
+ for (int xOff = 0; xOff < wh; ++xOff) {
+ temp[yOff*wh+xOff] = gaussian2d_value(xOff-halfFilterSize, yOff-halfFilterSize, sigma);
+
+ filterTot += temp[yOff*wh+xOff];
+ }
+ }
+
+ // normalize the kernel
+ for (int yOff = 0; yOff < wh; ++yOff) {
+ for (int xOff = 0; xOff < wh; ++xOff) {
+ temp[yOff*wh+xOff] /= filterTot;
+ }
+ }
+
+ return temp;
+}
+
+static SkPMColor blur_pixel(const SkBitmap& bm, int x, int y, float* kernel, int wh) {
+ SkASSERT(wh & 0x1);
+
+ int halfFilterSize = (wh-1)/2;
+
+ float r = 0.0f, g = 0.0f, b = 0.0f;
+ for (int yOff = 0; yOff < wh; ++yOff) {
+ int ySamp = y + yOff - halfFilterSize;
+
+ if (ySamp < 0) {
+ ySamp = 0;
+ } else if (ySamp > bm.height()-1) {
+ ySamp = bm.height()-1;
+ }
+
+ for (int xOff = 0; xOff < wh; ++xOff) {
+ int xSamp = x + xOff - halfFilterSize;
+
+ if (xSamp < 0) {
+ xSamp = 0;
+ } else if (xSamp > bm.width()-1) {
+ xSamp = bm.width()-1;
+ }
+
+ float filter = kernel[yOff*wh + xOff];
+
+ SkPMColor c = *bm.getAddr32(xSamp, ySamp);
+
+ r += SkGetPackedR32(c) * filter;
+ g += SkGetPackedG32(c) * filter;
+ b += SkGetPackedB32(c) * filter;
+ }
+ }
+
+ U8CPU r8, g8, b8;
+
+ r8 = (U8CPU) (r+0.5f);
+ g8 = (U8CPU) (g+0.5f);
+ b8 = (U8CPU) (b+0.5f);
+
+ return SkPackARGB32(255, r8, g8, b8);
+}
+
+SkBitmap slow_blur(const SkBitmap& src, float sigma) {
+ SkBitmap dst;
+
+ dst.allocN32Pixels(src.width(), src.height(), true);
+
+ int wh;
+ SkAutoTDeleteArray<float> kernel(create_2d_kernel(sigma, &wh));
+
+ for (int y = 0; y < src.height(); ++y) {
+ for (int x = 0; x < src.width(); ++x) {
+ *dst.getAddr32(x, y) = blur_pixel(src, x, y, kernel.get(), wh);
+ }
+ }
+
+ return dst;
+}
+
} // namespace sk_tool_utils
diff --git a/tools/sk_tool_utils.h b/tools/sk_tool_utils.h
index e0ad1df3ec..052bade6a7 100644
--- a/tools/sk_tool_utils.h
+++ b/tools/sk_tool_utils.h
@@ -135,6 +135,11 @@ namespace sk_tool_utils {
void create_tetra_normal_map(SkBitmap* bm, const SkIRect& dst);
void make_big_path(SkPath& path);
+
+ // Return a blurred version of 'src'. This doesn't use a separable filter
+ // so it is slow!
+ SkBitmap slow_blur(const SkBitmap& src, float sigma);
+
} // namespace sk_tool_utils
#endif // sk_tool_utils_DEFINED