Separate core and images project.
authorscroggo@google.com <scroggo@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Fri, 31 May 2013 14:00:10 +0000 (14:00 +0000)
committerscroggo@google.com <scroggo@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Fri, 31 May 2013 14:00:10 +0000 (14:00 +0000)
SkImage calls functions on SkImageDecoder and SkImageEncoder. This
is desired behavior, and it is also desired to include SkImage as
a part of core. In order to keep core from depending on images,
update SkImageDecoder_empty.cpp to implement all of SkImageDecoder
and SkImageEncoder. This file will be built by chrome (in
https://codereview.chromium.org/15960015).

Move force_linking from SkImageDecoder.cpp to its own file. It must
be called to force linking with the image decoders if desired. Call
the function in tools that need it:
sk_image
render_pictures
render_pdfs
sk_hello
filter
bench_pictures
debugger

SkImageDecoder:
Derive from SkNoncopyable, instead of duplicating its
hiding of constructors.

skhello:
Return rather than trying to write a null SkData to the stream.

Revert "Hamfistedly removed core dependence on images"
(commit 0f05f682a90bc125323677abf3476e1027d174f5) and
"Move SkImage::encode to SkImage_Codec.cpp."
(commit 83e47a954d0bf65439f3d9c0c93213063dd70da3.)
These two commits were temporary fixes that this change
cleans up.

SkSnapshot.cpp:
Check for a NULL encoder returned by SkImageEncoder::Create.

BUG=https://code.google.com/p/skia/issues/detail?id=1275
R=djsollen@google.com, robertphillips@google.com

Review URL: https://codereview.chromium.org/15806010

git-svn-id: http://skia.googlecode.com/svn/trunk@9364 2bbb7eff-a529-9590-31e7-b0007b416f81

21 files changed:
debugger/QT/SkDebuggerGUI.cpp
gyp/core.gypi
gyp/gmslides.gypi
gyp/images.gyp
gyp/tools.gyp
include/core/SkImage.h
include/core/SkImageDecoder.h [moved from include/images/SkImageDecoder.h with 99% similarity]
include/core/SkImageEncoder.h [moved from include/images/SkImageEncoder.h with 100% similarity]
include/images/SkForceLinking.h [new file with mode: 0644]
src/animator/SkSnapshot.cpp
src/image/SkImage.cpp
src/image/SkImage_Codec.cpp
src/images/SkForceLinking.cpp [new file with mode: 0644]
src/images/SkImageDecoder.cpp
src/ports/SkImageDecoder_empty.cpp
tools/bench_pictures_main.cpp
tools/filtermain.cpp
tools/render_pdfs_main.cpp
tools/render_pictures_main.cpp
tools/skhello.cpp
tools/skimage_main.cpp

index 60ef7e9..f5f9bc6 100644 (file)
@@ -6,6 +6,7 @@
  */
 
 #include "SkDebuggerGUI.h"
+#include "SkForceLinking.h"
 #include "SkGraphics.h"
 #include "SkImageDecoder.h"
 #include <QListWidgetItem>
@@ -13,6 +14,8 @@
 #include "SkPictureRecord.h"
 #include "SkPicturePlayback.h"
 
+__SK_FORCE_IMAGE_DECODER_LINKING;
+
 #if defined(SK_BUILD_FOR_WIN32)
     #include "BenchSysTimer_windows.h"
 #elif defined(SK_BUILD_FOR_MAC)
index ab73ede..534c888 100644 (file)
         '<(skia_src_path)/image/SkDataPixelRef.cpp',
         '<(skia_src_path)/image/SkImage.cpp',
         '<(skia_src_path)/image/SkImagePriv.cpp',
-#        '<(skia_src_path)/image/SkImage_Codec.cpp',
+        '<(skia_src_path)/image/SkImage_Codec.cpp',
 #        '<(skia_src_path)/image/SkImage_Gpu.cpp',
         '<(skia_src_path)/image/SkImage_Picture.cpp',
         '<(skia_src_path)/image/SkImage_Raster.cpp',
         '<(skia_include_path)/core/SkFontHost.h',
         '<(skia_include_path)/core/SkGeometry.h',
         '<(skia_include_path)/core/SkGraphics.h',
+        '<(skia_include_path)/core/SkImageDecoder.h',
+        '<(skia_include_path)/core/SkImageEncoder.h',
         '<(skia_include_path)/core/SkImageFilter.h',
         '<(skia_include_path)/core/SkImageFilterUtils.h',
         '<(skia_include_path)/core/SkInstCnt.h',
index b37154c..ca833a5 100644 (file)
@@ -54,7 +54,6 @@
     '../gm/imagemagnifier.cpp',
     '../gm/lerpmode.cpp',
     '../gm/lighting.cpp',
-    '../src/image/SkImage_Codec.cpp',
     '../gm/image.cpp',
     '../gm/imagefiltersbase.cpp',
     '../gm/imagefiltersgraph.cpp',
index d63a594..44f944c 100644 (file)
@@ -25,8 +25,7 @@
         '../src/image/',
       ],
       'sources': [
-        '../include/images/SkImageDecoder.h',
-        '../include/images/SkImageEncoder.h',
+        '../include/images/SkForceLinking.h',
         '../include/images/SkImageRef.h',
         '../include/images/SkImageRef_GlobalPool.h',
         '../src/images/SkJpegUtility.h',
 
         '../src/images/SkBitmapRegionDecoder.cpp',
 
+        '../src/images/SkForceLinking.cpp',
         '../src/images/SkImageDecoder.cpp',
         '../src/images/SkImageDecoder_FactoryDefault.cpp',
         '../src/images/SkImageDecoder_FactoryRegistrar.cpp',
         # If decoders are added/removed to/from (all/individual)
-        # platform(s), be sure to update SkImageDecoder.cpp:force_linking
+        # platform(s), be sure to update SkForceLinking.cpp
         # so the right decoders will be forced to link.
         '../src/images/SkImageDecoder_libbmp.cpp',
         '../src/images/SkImageDecoder_libgif.cpp',
index 7e0a03b..ede028a 100644 (file)
@@ -65,7 +65,6 @@
       'type': 'executable',
       'sources': [
         '../tools/skhello.cpp',
-        '../src/image/SkImage_Codec.cpp',
       ],
       'dependencies': [
         'skia_base_libs.gyp:skia_base_libs',
index 9b7dfd1..c2ee509 100644 (file)
@@ -8,6 +8,7 @@
 #ifndef SkImage_DEFINED
 #define SkImage_DEFINED
 
+#include "SkImageEncoder.h"
 #include "SkRefCnt.h"
 #include "SkScalar.h"
 
@@ -82,15 +83,6 @@ public:
 
     void draw(SkCanvas*, SkScalar x, SkScalar y, const SkPaint*);
 
-    enum EncodeType {
-        kBMP_EncodeType,
-        kGIF_EncodeType,
-        kICO_EncodeType,
-        kJPEG_EncodeType,
-        kPNG_EncodeType,
-        kWBMP_EncodeType,
-        kWEBP_EncodeType,
-    };
     /**
      *  Encode the image's pixels and return the result as a new SkData, which
      *  the caller must manage (i.e. call unref() when they are done).
@@ -98,7 +90,8 @@ public:
      *  If the image type cannot be encoded, or the requested encoder type is
      *  not supported, this will return NULL.
      */
-    SkData* encode(EncodeType t = kPNG_EncodeType, int quality = 80) const;
+    SkData* encode(SkImageEncoder::Type t = SkImageEncoder::kPNG_Type,
+                   int quality = 80) const;
 
 protected:
     SkImage(int width, int height) :
similarity index 99%
rename from include/images/SkImageDecoder.h
rename to include/core/SkImageDecoder.h
index ba22652..5ef5690 100644 (file)
@@ -15,6 +15,7 @@
 #include "SkImage.h"
 #include "SkRect.h"
 #include "SkRefCnt.h"
+#include "SkTypes.h"
 
 class SkStream;
 
@@ -22,7 +23,7 @@ class SkStream;
 
     Base class for decoding compressed images into a SkBitmap
 */
-class SkImageDecoder {
+class SkImageDecoder : public SkNoncopyable {
 public:
     virtual ~SkImageDecoder();
 
@@ -432,10 +433,6 @@ private:
     bool                    fUsePrefTable;
     mutable bool            fShouldCancelDecode;
     bool                    fPreferQualityOverSpeed;
-
-    // illegal
-    SkImageDecoder(const SkImageDecoder&);
-    SkImageDecoder& operator=(const SkImageDecoder&);
 };
 
 /** Calling newDecoder with a stream returns a new matching imagedecoder
diff --git a/include/images/SkForceLinking.h b/include/images/SkForceLinking.h
new file mode 100644 (file)
index 0000000..39901f6
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/**
+ *  This function's sole purpose is to trick the linker into not discarding
+ *  SkImageDecoder subclasses just because we do not directly call them.
+ *  This is necessary in applications that will create image decoders from
+ *  a stream.
+ *  Call this function with an expression that evaluates to false to ensure
+ *  that the linker includes the subclasses.
+ *  Passing true will result in leaked objects.
+ */
+int SkForceLinking(bool doNotPassTrue);
+
+#define __SK_FORCE_IMAGE_DECODER_LINKING       \
+static int linking_forced = SkForceLinking(false)
index a253d8e..493ce2b 100644 (file)
@@ -41,6 +41,10 @@ bool SkSnapshot::draw(SkAnimateMaker& maker) {
     SkASSERT(type >= 0);
     SkASSERT(filename.size() > 0);
     SkImageEncoder* encoder = SkImageEncoder::Create((SkImageEncoder::Type) type);
+    if (!encoder) {
+        return false;
+    }
+    SkAutoTDelete<SkImageEncoder> ad(encoder);
 
     SkString name(filename);
     if (sequence) {
index 1169459..9c60f55 100644 (file)
@@ -5,17 +5,21 @@
  * found in the LICENSE file.
  */
 
-#include "SkImage_Base.h"
-#include "SkImagePriv.h"
 #include "SkBitmap.h"
 #include "SkCanvas.h"
+#include "SkImagePriv.h"
+#include "SkImage_Base.h"
 
 SK_DEFINE_INST_COUNT(SkImage)
 
-static SkImage_Base* asIB(SkImage* image) {
+static SkImage_Base* as_IB(SkImage* image) {
     return static_cast<SkImage_Base*>(image);
 }
 
+static const SkImage_Base* as_IB(const SkImage* image) {
+    return static_cast<const SkImage_Base*>(image);
+}
+
 uint32_t SkImage::NextUniqueID() {
     static int32_t gUniqueID;
 
@@ -29,9 +33,17 @@ uint32_t SkImage::NextUniqueID() {
 
 void SkImage::draw(SkCanvas* canvas, SkScalar x, SkScalar y,
                    const SkPaint* paint) {
-    asIB(this)->onDraw(canvas, x, y, paint);
+    as_IB(this)->onDraw(canvas, x, y, paint);
 }
 
 GrTexture* SkImage::getTexture() {
-    return asIB(this)->onGetTexture();
+    return as_IB(this)->onGetTexture();
+}
+
+SkData* SkImage::encode(SkImageEncoder::Type type, int quality) const {
+    SkBitmap bm;
+    if (as_IB(this)->getROPixels(&bm)) {
+        return SkImageEncoder::EncodeData(bm, type, quality);
+    }
+    return NULL;
 }
index 77ce037..61661de 100644 (file)
@@ -5,11 +5,11 @@
  * found in the LICENSE file.
  */
 
+#include "SkImageDecoder.h"
 #include "SkImage_Base.h"
 #include "SkBitmap.h"
 #include "SkCanvas.h"
 #include "SkData.h"
-#include "../images/SkImageDecoder.h"
 
 class SkImage_Codec : public SkImage_Base {
 public:
@@ -64,40 +64,3 @@ SkImage* SkImage::NewEncodedData(SkData* data) {
 
     return SkNEW_ARGS(SkImage_Codec, (data, bitmap.width(), bitmap.height()));
 }
-
-///////////////////////////////////////////////////////////////////////////////
-
-// FIXME: Temporarily move this here so chromium can still build until we truly
-// fix the core/images dependency issue (https://code.google.com/p/skia/issues/detail?id=1275)
-#include "SkImage.h"
-#include "../images/SkImageEncoder.h"
-
-static const SkImage_Base* asIB(const SkImage* image) {
-    return static_cast<const SkImage_Base*>(image);
-}
-
-static const struct {
-    SkImageEncoder::Type    fIE;
-    SkImage::EncodeType     fET;
-} gTable[] = {
-    { SkImageEncoder::kBMP_Type,    SkImage::kBMP_EncodeType  },
-    { SkImageEncoder::kGIF_Type,    SkImage::kGIF_EncodeType  },
-    { SkImageEncoder::kICO_Type,    SkImage::kICO_EncodeType  },
-    { SkImageEncoder::kJPEG_Type,   SkImage::kJPEG_EncodeType },
-    { SkImageEncoder::kPNG_Type,    SkImage::kPNG_EncodeType  },
-    { SkImageEncoder::kWBMP_Type,   SkImage::kWBMP_EncodeType },
-    { SkImageEncoder::kWEBP_Type,   SkImage::kWEBP_EncodeType },
-};
-
-SkData* SkImage::encode(EncodeType et, int quality) const {
-    for (size_t i = 0; i < SK_ARRAY_COUNT(gTable); ++i) {
-        if (gTable[i].fET == et) {
-            SkBitmap bm;
-            if (asIB(this)->getROPixels(&bm)) {
-                return SkImageEncoder::EncodeData(bm, gTable[i].fIE, quality);
-            }
-            break;
-        }
-    }
-    return NULL;
-}
diff --git a/src/images/SkForceLinking.cpp b/src/images/SkForceLinking.cpp
new file mode 100644 (file)
index 0000000..81dbf2e
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkForceLinking.h"
+#include "SkImageDecoder.h"
+
+// This method is required to fool the linker into not discarding the pre-main
+// initialization and registration of the decoder classes. Passing true will
+// cause memory leaks.
+int SkForceLinking(bool doNotPassTrue) {
+    if (doNotPassTrue) {
+        SkASSERT(false);
+        CreateJPEGImageDecoder();
+        CreateWEBPImageDecoder();
+        CreateBMPImageDecoder();
+        CreateICOImageDecoder();
+        CreateWBMPImageDecoder();
+#if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_WIN)
+        CreateDefaultDecoder();
+#endif
+        // Only link GIF and PNG on platforms that build them. See images.gyp
+#if !defined(SK_BUILD_FOR_MAC) && !defined(SK_BUILD_FOR_WIN) && !defined(SK_BUILD_FOR_NACL)
+        CreateGIFImageDecoder();
+#endif
+#if !defined(SK_BUILD_FOR_MAC) && !defined(SK_BUILD_FOR_WIN)
+        CreatePNGImageDecoder();
+#endif
+        return -1;
+    }
+    return 0;
+}
index 52c43c8..5c078ce 100644 (file)
@@ -450,27 +450,3 @@ bool SkImageDecoder::DecodeStream(SkStream* stream, SkBitmap* bm,
     }
     return success;
 }
-
-/**
- *  This function leaks, but that is okay because it is not intended
- *  to be called. It is only here so that the linker will include the
- *  decoders.
- *  Make sure to keep it in sync with images.gyp, so only the encoders
- *  which are created on a platform are linked.
- */
-void force_linking();
-void force_linking() {
-    SkASSERT(false);
-    CreateJPEGImageDecoder();
-    CreateWEBPImageDecoder();
-    CreateBMPImageDecoder();
-    CreateICOImageDecoder();
-    CreateWBMPImageDecoder();
-    // Only link GIF and PNG on platforms that build them. See images.gyp
-#if !defined(SK_BUILD_FOR_MAC) && !defined(SK_BUILD_FOR_WIN) && !defined(SK_BUILD_FOR_NACL)
-    CreateGIFImageDecoder();
-#endif
-#if !defined(SK_BUILD_FOR_MAC) && !defined(SK_BUILD_FOR_WIN)
-    CreatePNGImageDecoder();
-#endif
-}
index 43beb94..ccfeb27 100644 (file)
@@ -6,19 +6,23 @@
  * found in the LICENSE file.
  */
 
-
+#include "SkBitmap.h"
+#include "SkBitmapFactory.h"
+#include "SkImage.h"
 #include "SkImageDecoder.h"
 #include "SkImageEncoder.h"
 #include "SkMovie.h"
 
-class SkBitmap;
+class SkColorTable;
 class SkStream;
 
-SkImageDecoder* SkImageDecoder::Factory(SkStream* stream) {
+// Empty implementations for SkImageDecoder.
+
+SkImageDecoder* SkImageDecoder::Factory(SkStream*) {
     return NULL;
 }
 
-bool SkImageDecoder::DecodeFile(const char file[], SkBitmap*, SkBitmap::Config,
+bool SkImageDecoder::DecodeFile(const char[], SkBitmap*, SkBitmap::Config,
                                 SkImageDecoder::Mode, SkImageDecoder::Format*) {
     return false;
 }
@@ -27,27 +31,93 @@ bool SkImageDecoder::decode(SkStream*, SkBitmap*, SkBitmap::Config, Mode, bool)
     return false;
 }
 
-bool SkImageDecoder::DecodeStream(SkStream*, SkBitmap*, SkBitmap::Config, SkImageDecoder::Mode,
+bool SkImageDecoder::DecodeStream(SkStream*, SkBitmap*, SkBitmap::Config,
+                                  SkImageDecoder::Mode,
                                   SkImageDecoder::Format*) {
     return false;
 }
 
-bool SkImageDecoder::DecodeMemory(const void*, size_t, SkBitmap*, SkBitmap::Config,
-                                  SkImageDecoder::Mode, SkImageDecoder::Format*) {
+bool SkImageDecoder::DecodeMemory(const void*, size_t, SkBitmap*,
+                                  SkBitmap::Config, SkImageDecoder::Mode,
+                                  SkImageDecoder::Format*) {
+    return false;
+}
+
+bool SkImageDecoder::buildTileIndex(SkStream*, int *width, int *height) {
+    return false;
+}
+
+bool SkImageDecoder::decodeSubset(SkBitmap*, const SkIRect&, SkBitmap::Config) {
     return false;
 }
 
-SkImageDecoder* CreateJPEGImageDecoder() {
+SkImageDecoder::Format SkImageDecoder::getFormat() const {
+    return kUnknown_Format;
+}
+
+SkImageDecoder::Format SkImageDecoder::GetStreamFormat(SkStream*) {
+    return kUnknown_Format;
+}
+
+const char* SkImageDecoder::GetFormatName(Format) {
     return NULL;
 }
+
+SkImageDecoder::Peeker* SkImageDecoder::setPeeker(Peeker*) {
+    return NULL;
+}
+
+SkImageDecoder::Chooser* SkImageDecoder::setChooser(Chooser*) {
+    return NULL;
+}
+
+SkBitmap::Allocator* SkImageDecoder::setAllocator(SkBitmap::Allocator*) {
+    return NULL;
+}
+
+void SkImageDecoder::setSampleSize(int) {}
+
+bool SkImageDecoder::DecodeMemoryToTarget(const void*, size_t, SkImage::Info*,
+                                          const SkBitmapFactory::Target*) {
+    return false;
+}
+
+SkBitmap::Config SkImageDecoder::GetDeviceConfig() {
+    return SkBitmap::kNo_Config;
+}
+
+void SkImageDecoder::SetDeviceConfig(SkBitmap::Config) {}
+
+bool SkImageDecoder::cropBitmap(SkBitmap*, SkBitmap*, int, int, int, int, int,
+                    int, int) {
+    return false;
+}
+
+bool SkImageDecoder::chooseFromOneChoice(SkBitmap::Config, int, int) const {
+    return false;
+}
+
+bool SkImageDecoder::allocPixelRef(SkBitmap*, SkColorTable*) const {
+    return false;
+}
+
+SkBitmap::Config SkImageDecoder::getPrefConfig(SrcDepth, bool) const {
+    return SkBitmap::kNo_Config;
+}
+
+
 /////////////////////////////////////////////////////////////////////////
 
+// Empty implementation for SkMovie.
+
 SkMovie* SkMovie::DecodeStream(SkStream* stream) {
     return NULL;
 }
 
 /////////////////////////////////////////////////////////////////////////
 
+// Empty implementations for SkImageEncoder.
+
 SkImageEncoder* SkImageEncoder::Create(Type t) {
     return NULL;
 }
@@ -60,12 +130,25 @@ bool SkImageEncoder::EncodeStream(SkWStream*, const SkBitmap&, SkImageEncoder::T
     return false;
 }
 
+SkData* SkImageEncoder::EncodeData(const SkBitmap&, Type, int quality) {
+    return NULL;
+}
+
 bool SkImageEncoder::encodeStream(SkWStream*, const SkBitmap&, int) {
     return false;
 }
 
+SkData* SkImageEncoder::encodeData(const SkBitmap&, int) {
+    return NULL;
+}
+
+bool SkImageEncoder::encodeFile(const char file[], const SkBitmap& bm, int quality) {
+    return false;
+}
 /////////////////////////////////////////////////////////////////////////
 
+// Empty implementation for SkImages.
+
 #include "SkImages.h"
 
 void SkImages::InitializeFlattenables() {}
index b5126a6..46d97de 100644 (file)
@@ -11,6 +11,7 @@
 #include "PictureRenderingFlags.h"
 #include "SkBenchLogger.h"
 #include "SkCommandLineFlags.h"
+#include "SkForceLinking.h"
 #include "SkGraphics.h"
 #include "SkImageDecoder.h"
 #if LAZY_CACHE_STATS
@@ -23,6 +24,7 @@
 #include "SkStream.h"
 #include "picture_utils.h"
 
+__SK_FORCE_IMAGE_DECODER_LINKING;
 
 SkBenchLogger gLogger;
 
index 47b82d1..30af392 100644 (file)
@@ -7,6 +7,7 @@
 
 #include "SkDebugCanvas.h"
 #include "SkDevice.h"
+#include "SkForceLinking.h"
 #include "SkGraphics.h"
 #include "SkImageDecoder.h"
 #include "SkImageEncoder.h"
@@ -18,6 +19,8 @@
 #include "picture_utils.h"
 #include "path_utils.h"
 
+__SK_FORCE_IMAGE_DECODER_LINKING;
+
 static void usage() {
     SkDebugf("Usage: filter -i inFile [-o outFile] [--input-dir path] [--output-dir path]\n");
     SkDebugf("                        [-h|--help]\n\n");
index f2ce0a5..1821548 100644 (file)
@@ -7,6 +7,7 @@
 
 #include "SkCanvas.h"
 #include "SkDevice.h"
+#include "SkForceLinking.h"
 #include "SkGraphics.h"
 #include "SkImageDecoder.h"
 #include "SkImageEncoder.h"
@@ -17,6 +18,8 @@
 #include "PdfRenderer.h"
 #include "picture_utils.h"
 
+__SK_FORCE_IMAGE_DECODER_LINKING;
+
 #ifdef SK_USE_CDB
 #include "win_dbghelp.h"
 #endif
index 3aa027f..f06cfeb 100644 (file)
@@ -9,6 +9,7 @@
 #include "SkBitmap.h"
 #include "SkDevice.h"
 #include "SkCommandLineFlags.h"
+#include "SkForceLinking.h"
 #include "SkGraphics.h"
 #include "SkImageDecoder.h"
 #include "SkImageEncoder.h"
@@ -21,6 +22,9 @@
 #include "PictureRenderingFlags.h"
 #include "picture_utils.h"
 
+// Required to ensure that image decoders get linked correctly.
+__SK_FORCE_IMAGE_DECODER_LINKING;
+
 // Flags used by this file, alphabetically:
 DEFINE_int32(clone, 0, "Clone the picture n times before rendering.");
 DECLARE_bool(deferImageDecoding);
index 3b8ddee..668c3a9 100644 (file)
@@ -57,6 +57,9 @@ int tool_main(int argc, char** argv) {
 
     SkAutoTUnref<SkImage> image(surface->newImageSnapshot());
     SkAutoDataUnref data(image->encode());
+    if (NULL == data.get()) {
+        return -1;
+    }
     SkFILEWStream stream(path.c_str());
     return stream.write(data->data(), data->size());
 }
index 98cde50..9262958 100644 (file)
@@ -10,6 +10,7 @@
 #include "SkColorPriv.h"
 #include "SkCommandLineFlags.h"
 #include "SkData.h"
+#include "SkForceLinking.h"
 #include "SkGraphics.h"
 #include "SkImageDecoder.h"
 #include "SkImageEncoder.h"
@@ -19,6 +20,8 @@
 #include "SkTArray.h"
 #include "SkTemplates.h"
 
+__SK_FORCE_IMAGE_DECODER_LINKING;
+
 DEFINE_string(createExpectationsPath, "", "Path to write JSON expectations.");
 DEFINE_string2(readPath, r, "", "Folder(s) and files to decode images. Required.");
 DEFINE_string(readExpectationsPath, "", "Path to read JSON expectations from.");