All formats

SkiaSharp

LanguageC# (.NET, .NET Framework, Xamarin/MAUI)
LicenseMIT (Skia itself: BSD-3-Clause)
Repositorygithub.com/mono/SkiaSharp
DocumentationSkiaSharp API reference
Depends onnative Skia binaries (NuGet packages per platform, included automatically on Windows and macOS)
Read / writeyes / yes; baseline and progressive decoding, baseline encoding with 4:2:0, 4:2:2 or 4:4:4

SkiaSharp wraps Skia, the 2D graphics engine of Chrome, Android and Flutter. Skia decodes JPEG with libjpeg-turbo, so decoding is fast, and it can decode directly to ½, ¼ or 1/8 size. It’s the usual choice for drawing, image resizing and rendering in .NET desktop and mobile apps.

SkiaSharp doesn’t parse Exif beyond the orientation (SKCodec.EncodedOrigin) and doesn’t copy metadata when encoding: re-encoded files lose Exif, XMP and the ICC profile. Use MetadataExtractor to read metadata.

Installation#

Shell
dotnet add package SkiaSharp
# Linux servers also need the native library package
dotnet add package SkiaSharp.NativeAssets.Linux

Basic usage: load, resize and save a JPEG#

C#
using SkiaSharp;

using SKBitmap original = SKBitmap.Decode("in.jpg")
    ?? throw new Exception("not an image");
Console.WriteLine($"{original.Width} x {original.Height}");

int width = 800;
int height = original.Height * width / original.Width;
var sampling = new SKSamplingOptions(SKFilterMode.Linear, SKMipmapMode.Linear);
using SKBitmap resized = original.Resize(new SKImageInfo(width, height), sampling);

using SKData data = resized.Encode(SKEncodedImageFormat.Jpeg, 85);
using FileStream output = File.OpenWrite("out.jpg");
data.SaveTo(output);

How to get JPEG size and orientation without decoding#

SKCodec reads the header only:

C#
using SKCodec codec = SKCodec.Create("in.jpg");
SKImageInfo info = codec.Info;
Console.WriteLine($"{info.Width} x {info.Height}, origin {codec.EncodedOrigin}");
// EncodedOrigin: TopLeft (normal), RightTop (rotate 90° clockwise), BottomRight (180°), LeftBottom (90° counter-clockwise)

How to decode a JPEG at reduced size (fast thumbnails)#

The JPEG decoder can scale by 1/8 steps while decoding. Ask the codec for the nearest supported size:

C#
using SKCodec codec = SKCodec.Create("big.jpg");
SKSizeI size = codec.GetScaledDimensions(0.25f);   // about 1/4
var info = new SKImageInfo(size.Width, size.Height, SKColorType.Rgba8888, SKAlphaType.Premul);
using SKBitmap thumb = SKBitmap.Decode(codec, info);

How to apply the Exif orientation#

SKBitmap.Decode returns pixels as stored. Rotate with a canvas when the origin isn’t TopLeft:

C#
static SKBitmap Rotate90(SKBitmap src)
{
    var dst = new SKBitmap(src.Height, src.Width);
    using var canvas = new SKCanvas(dst);
    canvas.Translate(dst.Width, 0);
    canvas.RotateDegrees(90);
    canvas.DrawBitmap(src, 0, 0);
    return dst;
}

using SKCodec codec = SKCodec.Create("photo.jpg");
using SKBitmap bitmap = SKBitmap.Decode(codec);
using SKBitmap upright = codec.EncodedOrigin == SKEncodedOrigin.RightTop ? Rotate90(bitmap) : bitmap.Copy();

How to set chroma subsampling when encoding#

SKJpegEncoderOptions controls quality, subsampling and how alpha is handled:

C#
using SKPixmap pixmap = bitmap.PeekPixels();
var options = new SKJpegEncoderOptions(92, SKJpegEncoderDownsample.Downsample444, SKJpegEncoderAlphaOption.Ignore);
using FileStream output = File.OpenWrite("out.jpg");
pixmap.Encode(output, options);

Tips#