Giter Site home page Giter Site logo

asyncimagelibrary's Introduction

Async Image Library

Load Image asynchronously from external environment without blocking Main-Thread. And powerful SkiaSharp Library implemented and wrapped for better and convenient usage.

  • SkiaSharp Version - 2.88.3
  • Unity Version - 2019.3.x or newer
  • Build Support (Tested Only) -
    • Windows (IL2CPP)
    • Windows (Mono)
    • Android (IL2CPP)
    • Android (Mono)
    • iOS (IL2CPP)
    • Mac
    • Linux Distribution (Ubuntu tested)
  • Sample Project

Installation

Using Git

Open Package Manager in Unity and Click on Plus Icon -> Add package from git URL, paste following link

https://github.com/SrejonKhan/AsyncImageLibrary.git

and click Add.

Using OpenUPM

This package is available at OpenUPM. To install with openupm-cli -

openupm add com.srejonkhan.asyncimagelibrary

Other methods (Asset Store, Release Page) will be added later after a stable release.

Manual

To use this library, AsyncImageLibrary namespace should be defined, like this using AsyncImageLibrary;

AsyncImage (Class)

AsyncImage specifies an Image. It provides methods and properties for Loading, Saving and Processing an Image.

Constructor

Name Details
AsyncImage() Default Constructor. Every property sets to default value. Path or Buffer should be set before loading.
AsyncImage(string path) For creating Bitmap from Local File Path.
AsyncImage(string path, bool shouldGenerateTexture) For creating Bitmap from Local File Path and define if to Generate Texture upon Loading Bitmap.
AsyncImage(string path, bool shouldGenerateTexture, bool shouldQueueTextureProcess) For creating Bitmap from Local File Path and define if to Generate Texture when Bitmap is loaded and Queue Texture Generation Process in Main Thread.
AsyncImage(byte[] buffer) For creating Bitmap from Buffer. Suitable for creating Bitmap from Remote Image Buffer.
AsyncImage(byte[] buffer, bool shouldGenerateTexture) For creating Bitmap from Buffer. Define if to generate Texture when Bitmap is loaded.
AsyncImage(byte[] buffer, bool shouldGenerateTexture, bool shouldQueueTextureProcess) For creating Bitmap from Buffer. Define if to generate Texture when Bitmap is loaded and queue Texture Generation Process in Main Thread.

Properties

Name Details
Width* Width of Image
Height* Height of Image
Path Local file path of Image
Bitmap* SKBitmap reference
Texture** Texture2D of Image
ShouldGenerateTexture Generate Texture along with Bitmap, if true.
ShouldQueueTextureProcess Queue Texture Generation Process in MainThreadQueue to process later.

*Available when Bitmap is Loaded.

**Available when Texture is generated.

Methods

Name Details
Load() Load Bitmap from given path.
Load(Action cb) Load Bitmap from given path and callback upon completion.
GenerateTexture() Generate Texture2D from Bitmap. If Bitmap is not loaded, this will be queued for execute after Bitmaps load.
GenerateTexture(Action cb) Generate Texture2D from Bitmap. Get queued when Bitmap is not loaded. Callback when texture is generated. (Same as OnLoad delegate)
Save(string path, SKEncodedImageFormat format, int quality) Save Image to specified format.
Save(string path, SKEncodedImageFormat format, int quality, Action onComplete) Save Image to specified format.
GetEncodedBuffer(SKEncodedImageFormat format, int quality) Get Encoded Byte Array of Bitmap
Crop(Vector2 position, Vector2 targetDimension) Crop Bitmap to specified size in specified rect position.
Resize(int divideBy, ResizeQuality quality) Resize to (Actual Dimension / divideBy).
Resize(int divideBy, ResizeQuality quality, Action onComplete) Resize to (Actual Dimension / divideBy). Callback when completed.
Resize(Vector2 targetDimensions, ResizeQuality quality) Resize to given dimension.
Resize(Vector2 targetDimensions, ResizeQuality quality, Action onComplete) Resize to given dimension. Callback when completed.
DrawText(string text, Vector2 position, TextAlign textAlign, Color color, float textSize) Draw Text on Bitmap.
DrawText(string text, Vector2 position, TextAlign textAlign, Color color, float textSize, string fontFamilyName) Draw Text on Bitmap.
DrawText(string text, Vector2 position, TextAlign textAlign, Color color, float textSize, string fontFamilyName, Action onComplete) Draw Text on Bitmap.
DrawText(string text, Vector2 position, SKPaint paint) Draw Text on Bitmap, proving SKPaint for styling.
DrawText(string text, Vector2 position, SKPaint paint, Action onComplete) Draw Text on Bitmap, proving SKPaint for styling. Callback upon completion.

Delegates

Name Details
OnLoad Callback when Bitmap is loaded.
OnSave Callback when Bitmap is saved.
OnTextureLoad Callback when Texture2D is loaded.

Usage

Loading Image from Local

AsyncImage image = new AsyncImage(path);
image.Load();

Loading Image from Remote

string remoteImageUrl = "https://example.com/image.png";

AsyncImage image = new AsyncImage(remoteImageUrl);
image.Load();

Loading Texture

To load texture, the Bitmap must be loaded. Calling image.GenerateTexture() will throw error if the Bitmap is not loaded. Also, calling image.GenerateTexture() just after image.Load() won't work most cases as it's an asynchronous call. So, it's better to load a texture like this -

AsyncImage image = new AsyncImage(path);

image.OnTextureLoad += () =>
{
    Texture2D loadedTexture = image.Texture;
};

image.Load();

If AsyncImage is constructed by the following way -

AsyncImage image = new AsyncImage(path, false);

or, defined not to generate texture -

AsyncImage image = new AsyncImage(path);
image.ShouldGenerateTexture = false; // don't generate texture on Load

It won't Generate Texture Automatically after bitmap is loaded. So, in that circumstances, we have to generate Texture manually. we have to keep in mind that, we can only generate Texture when bitmap is loaded. Please check next section for how to deal with that.

Generate Texture2D on demand

By default, Texture2D automatically generated on main thread after bitmap is loadeed. After it is generated, it can be accessible by image.Texture.

Whatever, in some scenerio, it's not necessery to generate Texture2D along with loading Bitmap. In that case, we can define not to load it by simply passing another argument in constructor -

AsyncImage image = new AsyncImage(path, false);

For generating Texture2D -

image.GenerateTexture(() =>
{
    Debug.Log("Texture2D loaded!");
});

Alternatively -

image.OnTextureLoad += () =>
{
    Debug.Log("Texture2D loaded!");
};
// generate Texture2D
image.GenerateTexture();

Saving Bitmap

For saving, Bitmap must be loaded. To save a Bitmap -

AsyncImage image = new AsyncImage(path);

image.Save(@"E:\image.png", SkiaSharp.SKEncodedImageFormat.Png, 100);

Listen to Events

There are 2 important events where you can subscribe.

OnLoad

OnLoad will be called as soon as the Bitmap is loaded. It's ideal to use when you would like to know when Bitmap is loaded and do other works e.g calling GenerateTexture().

AsyncImage image = new AsyncImage(path);
image.OnLoad += () =>
{
   Debug.Log("Bitmap loaded!");
   // do your works
};
image.Load();

OnSave

OnSave will be called as soon as the Bitmap is saved to local file. It returns bool in callback as result. true = successfully saved, false = error encountered while saving

AsyncImage image = new AsyncImage(path);
image.OnSave += (result) =>
{
   // result is boolean
   Debug.Log("Saved - " + result);
};
image.Save(@"E:\image.png", SkiaSharp.SKEncodedImageFormat.Png, 100);

OnTextureLoad

OnTextureLoad will be called when Texture2D is generated from the Bitmap. By default, whenever Load() is called, it generates Texture2D after Bitmap is loaded. It can be defined either to generate Texture2D afterward or call GenerateTexture() later on-demand.

AsyncImage image = new AsyncImage(path);
image.OnTextureLoad += () =>
{
    Debug.Log("Texture2D loaded!");
    // do your works
};
image.Load();

Load Image Info Only

To load Image info only -

AsyncImage image = new AsyncImage(path);

var (info, format) = image.GetInfo();

Learn more about info (SKImageInfo) and format (SKEncodedImageFormat).

Note that, it's not possible to get Info from Image that is generated from Buffer.

Image Process

Resizing

There are two ways to resize an Image.

Divide By

Let's say we have a image of 1000px _ 1000px dimension. To resize it down to half of it's resolution, 500px _ 500px, we need to divide it by 2 (1000px/2 = 500px). So, we can simply -

AsyncImage image = new AsyncImage(path);

image.Resize(2, ResizeQuality.Medium); // resize

image.OnTextureLoad += MethodA;
image.Load();

Target Dimensions

To resize an Image to a defined dimension -

AsyncImage image = new AsyncImage(path);

// x of Vector2 is Width, y of Vector2 is Height
image.Resize(new Vector2(200,200), ResizeQuality.Medium);

image.OnTextureLoad += MethodA;
image.Load();

Draw Text

Simple

Simply draw a text by passing straight-forward parameters.

public void DrawText(string text, Vector2 position, TextAlign textAlign, Color color, float textSize, string fontFamilyName = "Arial", Action onComplete = null)
Parameters Details
text Text to draw on Image
position The x & y coordinate of the origin of the text being drawn
textAlign Text Align (Left, Center, Right)
color Color of Text (RGB)
textSize Text Height in Pixel
fontFamilyName* Font family name for typeface
onComplete* Callback on completion

*Optional Parameters.

Example

AsyncImage image = new AsyncImage(path);

var (info, format) = image.GetInfo();

// drawing text at the center (vertically and horizontally)
image.DrawText("Hello from the other side!", new Vector2(info.Width/2, info.Height / 2), TextAlign.Center, Color.white);

image.OnTextureLoad += MethodA;
image.Load();

Advanced (SKPaint)

Draw text with SKPaint, more flexibility to use SkiaSharp directly. SKPaint gives a lot of Properties and Methods to apply any filters or whatsoever.

public void DrawText(string text, Vector2 position, SKPaint paint, Action onComplete = null)
Parameters Details
text Text to draw on Image
position The x & y coordinate of the origin of the text being drawn
paint SKPaint object reference, for styling text.
onComplete* Callback on completion

*Optional Parameters.

Example

AsyncImage image = new AsyncImage(path);

var (info, format) = image.GetInfo();

string text = "Leaves are on the ground, fall has come.";

var paint = new SKPaint();
// Convert RGB color to HSV color
Color.RGBToHSV(Color.white, out float h, out float s, out float v);
paint.Color = SKColor.FromHsv(h * 360, s * 100, v * 100);
// Text Align
paint.TextAlign = SKTextAlign.Center;
// Loading Font from file
paint.Typeface = SKTypeface.FromFile(@"E:\Font\Hack-Italic.ttf", 0);
// Adjust TextSize property so text is 90% of screen width
float textWidth = paint.MeasureText(text);
paint.TextSize = 0.9f * info.Width * paint.TextSize / textWidth;

// drawing text at the center (vertically and horizontally)
image.DrawText(text, new Vector2(info.Width / 2, info.Height/2), paint);

image.OnTextureLoad += MethodA;
image.Load();

Note: MeasureText() should be called after a certain typeface loads. Or, it will lead to miscalculation. Arial is the fallback font for DrawText(). In case of font was not loaded, it will try to load Arial.

asyncimagelibrary's People

Contributors

srejonkhan avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

asyncimagelibrary's Issues

Unable to load DLL 'libSkiaSharp' on iOS

Hello,

When I build for iOS using this package I get the following error:

DllNotFoundException: Unable to load DLL 'libSkiaSharp'. Tried the load the following dynamic libraries: Unable to load dynamic library '/libSkiaSharp' because of 'Failed to open the requested dynamic library (0x06000000) dlerror() = dlopen(/libSkiaSharp, 0x0005): tried: '/libSkiaSharp' (errno=2), '/private/preboot/Cryptexes/OS/libSkiaSharp' (errno=2), '/libSkiaSharp' (errno=2)

Please help.

Crash when calling `DrawText()` multiple time

Editor crash when calling DrawText() multiple times to draw multiple texts, not tested in build.

Stack trace -

Stack Trace of Crashed Thread 32028:
0x00007FFB637E4910 (libSkiaSharp) sk_font_get_typeface
0x000002C2FBCE68FF (SkiaSharp) SkiaSharp.SkiaApi.sk_font_get_typeface()
0x000002C2FBCE673B (SkiaSharp) SkiaSharp.SKFont.get_Typeface()
0x000002C2FBCE6603 (SkiaSharp) SkiaSharp.SKPaint.get_Typeface()
0x000002C2FBC9540B (SrejonKhan.AsyncImageLibrary.Runtime) AsyncImageLibrary.ImageProcess.DrawText()
0x000002C2FBCE5F93 (SrejonKhan.AsyncImageLibrary.Runtime) <>c__DisplayClass2_0.<DrawText>b__1()
0x000002C296B838A7 (mscorlib) <Module>.invoke_void()
0x000002C2FBCE54A9 (SrejonKhan.AsyncImageLibrary.Runtime) AsyncImageLibrary.ImageLoadSave.ProcessBitmap()
0x000002C2FBC98543 (SrejonKhan.AsyncImageLibrary.Runtime) AsyncImageLibrary.ImageLoadSave.LoadBitmapFromFileStream()
0x000002C2FBC98233 (SrejonKhan.AsyncImageLibrary.Runtime) <>c__DisplayClass1_0.<Load>b__0()
0x000002C2FBC9812A (mscorlib) System.Threading.QueueUserWorkItemCallback.WaitCallback_Context()
0x000002C292C3F8F9 (mscorlib) System.Threading.ExecutionContext.RunInternal()
0x000002C292C3F25B (mscorlib) System.Threading.ExecutionContext.Run()
0x000002C2FBC98013 (mscorlib) System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
0x000002C292C38B81 (mscorlib) System.Threading.ThreadPoolWorkQueue.Dispatch()
0x000002C292C36E03 (mscorlib) System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()
0x000002C292C37735 (mscorlib) <Module>.runtime_invoke_bool()
0x00007FFBD29CE630 (mono-2.0-bdwgc) mono_get_runtime_build_info
0x00007FFBD2952AC2 (mono-2.0-bdwgc) mono_perfcounters_init
0x00007FFBD297A351 (mono-2.0-bdwgc) mono_unity_managed_callstack
0x00007FFBD297C9D1 (mono-2.0-bdwgc) mono_unity_managed_callstack
0x00007FFBD2976BB8 (mono-2.0-bdwgc) mono_unity_managed_callstack
0x00007FFBD2976946 (mono-2.0-bdwgc) mono_unity_managed_callstack
0x00007FFC6B067034 (KERNEL32) BaseThreadInitThunk
0x00007FFC6B342651 (ntdll) RtlUserThreadStart

Texture2D is not readable

I went through the code and at line 76 you are making the texture not readable. Is there a reason for this?
It is making it difficult working with the texture.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.