Getting in-band assets to render with the viewer renderer.
diff --git a/include/rive/assets/file_asset.hpp b/include/rive/assets/file_asset.hpp
index 5826e3a..dcc91e5 100644
--- a/include/rive/assets/file_asset.hpp
+++ b/include/rive/assets/file_asset.hpp
@@ -7,7 +7,7 @@
 	class FileAsset : public FileAssetBase
 	{
 	public:
-		virtual void decode(const uint8_t* bytes) = 0;
+		virtual void decode(const uint8_t* bytes, std::size_t size) = 0;
 		StatusCode import(ImportStack& importStack) override;
 	};
 } // namespace rive
diff --git a/include/rive/assets/file_asset_contents.hpp b/include/rive/assets/file_asset_contents.hpp
index d035621..5b3e961 100644
--- a/include/rive/assets/file_asset_contents.hpp
+++ b/include/rive/assets/file_asset_contents.hpp
@@ -1,12 +1,13 @@
 #ifndef _RIVE_FILE_ASSET_CONTENTS_HPP_
 #define _RIVE_FILE_ASSET_CONTENTS_HPP_
 #include "rive/generated/assets/file_asset_contents_base.hpp"
-#include <stdio.h>
+
 namespace rive
 {
 	class FileAssetContents : public FileAssetContentsBase
 	{
 	public:
+		StatusCode import(ImportStack& importStack) override;
 	};
 } // namespace rive
 
diff --git a/include/rive/assets/image_asset.hpp b/include/rive/assets/image_asset.hpp
index 152ff58..30777ce 100644
--- a/include/rive/assets/image_asset.hpp
+++ b/include/rive/assets/image_asset.hpp
@@ -14,7 +14,7 @@
 		ImageAsset();
 		~ImageAsset();
 
-		void decode(const uint8_t* bytes) override;
+		void decode(const uint8_t* bytes, std::size_t size) override;
 		RenderImage* renderImage() const { return m_RenderImage; }
 	};
 } // namespace rive
diff --git a/include/rive/importers/file_asset_importer.hpp b/include/rive/importers/file_asset_importer.hpp
new file mode 100644
index 0000000..57626c3
--- /dev/null
+++ b/include/rive/importers/file_asset_importer.hpp
@@ -0,0 +1,23 @@
+#ifndef _RIVE_FILE_ASSET_IMPORTER_HPP_
+#define _RIVE_FILE_ASSET_IMPORTER_HPP_
+
+#include "rive/importers/import_stack.hpp"
+#include <unordered_map>
+#include <vector>
+
+namespace rive
+{
+	class FileAsset;
+	class FileAssetContents;
+	class FileAssetImporter : public ImportStackObject
+	{
+	private:
+		FileAsset* m_FileAsset;
+
+	public:
+		FileAssetImporter(FileAsset* fileAsset);
+		void loadContents(const FileAssetContents& contents);
+		StatusCode resolve() override;
+	};
+} // namespace rive
+#endif
diff --git a/include/rive/renderer.hpp b/include/rive/renderer.hpp
index de385b8..3b4bce5 100644
--- a/include/rive/renderer.hpp
+++ b/include/rive/renderer.hpp
@@ -47,7 +47,7 @@
 
 	public:
 		virtual ~RenderImage() {}
-		virtual bool decode(const uint8_t* bytes) = 0;
+		virtual bool decode(const uint8_t* bytes, std::size_t size) = 0;
 		int width() const { return m_Width; }
 		int height() const { return m_Height; }
 	};
diff --git a/include/rive/shapes/image.hpp b/include/rive/shapes/image.hpp
index d36fcbd..190d261 100644
--- a/include/rive/shapes/image.hpp
+++ b/include/rive/shapes/image.hpp
@@ -15,6 +15,7 @@
 		void draw(Renderer* renderer) override;
 		StatusCode import(ImportStack& importStack) override;
 		void assets(const std::vector<FileAsset*>& assets) override;
+		Core* clone() const override;
 	};
 } // namespace rive
 
diff --git a/skia/dependencies/make_glfw.sh b/skia/dependencies/make_glfw.sh
index 71c7a9c..62620a7 100755
--- a/skia/dependencies/make_glfw.sh
+++ b/skia/dependencies/make_glfw.sh
@@ -19,7 +19,7 @@
     cd ..
 fi
 
-mkdir glfw_build
+mkdir -p glfw_build
 cd glfw_build
 cmake ../glfw -DBUILD_SHARED_LIBS=OFF
 make
\ No newline at end of file
diff --git a/skia/renderer/include/skia_renderer.hpp b/skia/renderer/include/skia_renderer.hpp
index 96d9ba4..8239567 100644
--- a/skia/renderer/include/skia_renderer.hpp
+++ b/skia/renderer/include/skia_renderer.hpp
@@ -4,6 +4,7 @@
 #include "SkCanvas.h"
 #include "SkPaint.h"
 #include "SkPath.h"
+#include "SkImage.h"
 #include "rive/renderer.hpp"
 #include <vector>
 
@@ -91,6 +92,16 @@
 		void completeGradient() override;
 	};
 
+	class SkiaRenderImage : public RenderImage
+	{
+	private:
+		sk_sp<SkImage> m_SkImage;
+
+	public:
+		sk_sp<SkImage> skImage() const { return m_SkImage; };
+		bool decode(const uint8_t* bytes, std::size_t size) override;
+	};
+
 	class SkiaRenderer : public Renderer
 	{
 	protected:
@@ -102,6 +113,8 @@
 		void restore() override;
 		void transform(const Mat2D& transform) override;
 		void drawPath(RenderPath* path, RenderPaint* paint) override;
+		void
+		drawImage(RenderImage* image, BlendMode value, float opacity) override;
 		void clipPath(RenderPath* path) override;
 	};
 } // namespace rive
diff --git a/skia/renderer/src/skia_renderer.cpp b/skia/renderer/src/skia_renderer.cpp
index 4d05007..cb170b6 100644
--- a/skia/renderer/src/skia_renderer.cpp
+++ b/skia/renderer/src/skia_renderer.cpp
@@ -143,8 +143,34 @@
 	m_Canvas->clipPath(reinterpret_cast<SkiaRenderPath*>(path)->path(), true);
 }
 
+void SkiaRenderer::drawImage(RenderImage* image,
+                             BlendMode blendMode,
+                             float opacity)
+{
+	SkPaint paint;
+	paint.setAlphaf(opacity);
+	paint.setBlendMode(ToSkia::convert(blendMode));
+	auto skiaImage = reinterpret_cast<SkiaRenderImage*>(image);
+	SkSamplingOptions samplingOptions(SkFilterMode::kLinear,
+	                                  SkMipmapMode::kNone);
+	m_Canvas->drawImage(
+	    skiaImage->skImage(), 0.0f, 0.0f, samplingOptions, &paint);
+}
+
+bool SkiaRenderImage::decode(const uint8_t* bytes, std::size_t size)
+{
+
+	sk_sp<SkData> data = SkData::MakeWithoutCopy(bytes, size);
+	m_SkImage = SkImage::MakeFromEncoded(data);
+	m_Width = m_SkImage->width();
+	m_Height = m_SkImage->height();
+	printf("DECODING IMAGE! %i %i\n", m_Width, m_Height);
+	return true;
+}
+
 namespace rive
 {
 	RenderPath* makeRenderPath() { return new SkiaRenderPath(); }
 	RenderPaint* makeRenderPaint() { return new SkiaRenderPaint(); }
+	RenderImage* makeRenderImage() { return new SkiaRenderImage(); }
 } // namespace rive
\ No newline at end of file
diff --git a/skia/viewer/build/premake5.lua b/skia/viewer/build/premake5.lua
index 16eb857..acc6885 100644
--- a/skia/viewer/build/premake5.lua
+++ b/skia/viewer/build/premake5.lua
@@ -32,7 +32,6 @@
        "../../dependencies/imgui/imgui_draw.cpp"}
 
 buildoptions {"-Wall", "-fno-exceptions", "-fno-rtti", "-flto=full"}
--- linkoptions {"-Oz", "-flto=full"}
 filter "configurations:debug"
 defines {"DEBUG"}
 symbols "On"
diff --git a/src/assets/file_asset_contents.cpp b/src/assets/file_asset_contents.cpp
new file mode 100644
index 0000000..0b6ad54
--- /dev/null
+++ b/src/assets/file_asset_contents.cpp
@@ -0,0 +1,18 @@
+#include "rive/assets/file_asset_contents.hpp"
+#include "rive/assets/file_asset.hpp"
+#include "rive/importers/file_asset_importer.hpp"
+
+using namespace rive;
+
+StatusCode FileAssetContents::import(ImportStack& importStack)
+{
+	auto fileAssetImporter =
+	    importStack.latest<FileAssetImporter>(FileAsset::typeKey);
+	if (fileAssetImporter == nullptr)
+	{
+		return StatusCode::MissingObject;
+	}
+	fileAssetImporter->loadContents(*this);
+
+	return Super::import(importStack);
+}
\ No newline at end of file
diff --git a/src/assets/image_asset.cpp b/src/assets/image_asset.cpp
index 22ae470..1ff6d33 100644
--- a/src/assets/image_asset.cpp
+++ b/src/assets/image_asset.cpp
@@ -6,4 +6,7 @@
 ImageAsset::ImageAsset() : m_RenderImage(makeRenderImage()) {}
 
 ImageAsset::~ImageAsset() { delete m_RenderImage; }
-void ImageAsset::decode(const uint8_t* bytes) { m_RenderImage->decode(bytes); }
\ No newline at end of file
+void ImageAsset::decode(const uint8_t* bytes, std::size_t size)
+{
+	m_RenderImage->decode(bytes, size);
+}
\ No newline at end of file
diff --git a/src/file.cpp b/src/file.cpp
index 9a88194..a7eb452 100644
--- a/src/file.cpp
+++ b/src/file.cpp
@@ -7,6 +7,7 @@
 #include "rive/generated/core_registry.hpp"
 #include "rive/importers/artboard_importer.hpp"
 #include "rive/importers/backboard_importer.hpp"
+#include "rive/importers/file_asset_importer.hpp"
 #include "rive/importers/import_stack.hpp"
 #include "rive/importers/keyed_object_importer.hpp"
 #include "rive/importers/keyed_property_importer.hpp"
@@ -251,6 +252,10 @@
 				    new StateTransitionImporter(object->as<StateTransition>());
 				stackType = StateTransition::typeKey;
 				break;
+			case ImageAsset::typeKey:
+				stackObject = new FileAssetImporter(object->as<FileAsset>());
+				stackType = FileAsset::typeKey;
+				break;
 		}
 		if (importStack.makeLatest(stackType, stackObject) != StatusCode::Ok)
 		{
diff --git a/src/importers/file_asset_importer.cpp b/src/importers/file_asset_importer.cpp
new file mode 100644
index 0000000..9e62fe3
--- /dev/null
+++ b/src/importers/file_asset_importer.cpp
@@ -0,0 +1,21 @@
+#include "rive/importers/file_asset_importer.hpp"
+#include "rive/assets/file_asset_contents.hpp"
+#include "rive/assets/file_asset.hpp"
+
+using namespace rive;
+
+FileAssetImporter::FileAssetImporter(FileAsset* fileAsset) :
+    m_FileAsset(fileAsset)
+{
+}
+void FileAssetImporter::loadContents(const FileAssetContents& contents)
+{
+	const std::vector<uint8_t>& data = contents.bytes();
+	m_FileAsset->decode(&data[0], data.size());
+}
+
+StatusCode FileAssetImporter::resolve()
+{
+	// TODO: find data if the bytes weren't in band.
+	return StatusCode::Ok;
+}
\ No newline at end of file
diff --git a/src/shapes/image.cpp b/src/shapes/image.cpp
index 2256a1a..9eb58e7 100644
--- a/src/shapes/image.cpp
+++ b/src/shapes/image.cpp
@@ -8,12 +8,25 @@
 
 void Image::draw(Renderer* renderer)
 {
-	if (renderOpacity() == 0.0f)
+	if (m_ImageAsset == nullptr || renderOpacity() == 0.0f)
 	{
 		return;
 	}
-	renderer->drawImage(
-	    m_ImageAsset->renderImage(), blendMode(), renderOpacity());
+	renderer->save();
+
+	auto renderImage = m_ImageAsset->renderImage();
+	auto width = renderImage->width();
+	auto height = renderImage->height();
+
+	const Mat2D& transform = worldTransform();
+	renderer->transform(transform);
+
+	Mat2D originTranslation(
+	    1.0f, 0.0f, 0.0f, 1.0f, -width / 2.0f, -height / 2.0f);
+	renderer->transform(originTranslation);
+
+	renderer->drawImage(renderImage, blendMode(), renderOpacity());
+	renderer->restore();
 }
 
 StatusCode Image::import(ImportStack& importStack)
@@ -40,4 +53,11 @@
 	{
 		m_ImageAsset = asset->as<ImageAsset>();
 	}
+}
+
+Core* Image::clone() const
+{
+	Image* twin = ImageBase::clone()->as<Image>();
+	twin->m_ImageAsset = m_ImageAsset;
+	return twin;
 }
\ No newline at end of file