-
-
Save saucecontrol/b1940571f7151a2d4b2822de587df71c to your computer and use it in GitHub Desktop.
MagicScaler with SkiaSharp on Linux
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.IO; | |
using System.Drawing; | |
using System.Runtime.InteropServices; | |
using SkiaSharp; | |
using PhotoSauce.MagicScaler; | |
class Program | |
{ | |
// Ideally an IPixelSource implementation would use Skia's ScanLine or Incremental decoding | |
// if supported by the codec. This one wraps a fully-decoded image. | |
private class SkiaPixelSource : BitmapPixelSource | |
{ | |
private readonly byte[] pixels; | |
public SkiaPixelSource(Guid format, int width, int height, int stride, byte[] pixels) | |
: base(format, width, height, stride) => this.pixels = pixels; | |
protected override ReadOnlySpan<byte> Span => pixels.AsSpan(); | |
} | |
public static void Main() | |
{ | |
string inImgPath = "/mnt/c/img/bigimage.jpg"; | |
string outImgPath = "/mnt/c/img/smallimage.jpg"; | |
// Use SKCodec so we can control the details of the decoding. | |
using var skCodec = SKCodec.Create(inImgPath); | |
var skSrcInfo = skCodec.Info; | |
// Alternate SKImageInfo settings force the decoder to convert the pixel format on decode. | |
// This could be smarter about pixel format mapping. For now, we pick a format that is compatible between | |
// Skia and MagicScaler (SkiaSharp.SKColorType.Bgra8888 == PhotoSauce.MagicScaler.PixelFormats.Bgra32bpp) | |
// Since we can't retrieve an ICC profile directly from Skia, we ask it to convert to sRGB on decode. | |
// Note that this sample doesn't handle Exif Orientation, which is encoded in `SKCodec.EncodedOrigin` | |
var skDecodeInfo = new SKImageInfo { | |
Width = skSrcInfo.Width, | |
Height = skSrcInfo.Height, | |
ColorType = SKColorType.Bgra8888, | |
AlphaType = SKAlphaType.Unpremul, | |
ColorSpace = SKColorSpace.CreateSrgb() | |
}; | |
// Create a buffer to hold the decoded pixels. | |
int inStride = skDecodeInfo.Width * skDecodeInfo.BytesPerPixel; | |
var inPixels = new byte[inStride * skDecodeInfo.Height]; | |
var inHandle = GCHandle.Alloc(inPixels, GCHandleType.Pinned); | |
// Decode the input image into the buffer. | |
skCodec.GetPixels(skDecodeInfo, inHandle.AddrOfPinnedObject(), inStride, SKCodecOptions.Default); | |
inHandle.Free(); | |
// Create an IPixelSource to wrap the buffer. The pixel format must be binary-compatible with the Skia pixel format. | |
using var psSource = new SkiaPixelSource(PixelFormats.Bgra32bpp, skDecodeInfo.Width, skDecodeInfo.Height, inStride, inPixels); | |
// Create a MagicScaler pipeline to resize the image, then retrieve its IPixelSource. | |
using var psPipeline = MagicImageProcessor.BuildPipeline(psSource, new ProcessImageSettings { Width = 400 }); | |
var psOutput = psPipeline.PixelSource; | |
// Retrieve the target size from the pipeline. We keep the pixel format and color space from the source. | |
var skDstInfo = skDecodeInfo.WithSize(psOutput.Width, psOutput.Height); | |
// Create a buffer for the resized image. | |
int outStride = skDstInfo.Width * skDstInfo.BytesPerPixel; | |
var outPixels = new byte[outStride * skDstInfo.Height]; | |
var outHandle = GCHandle.Alloc(outPixels, GCHandleType.Pinned); | |
// Resize the image into the buffer. | |
psOutput.CopyPixels(new Rectangle(0, 0, psOutput.Width, psOutput.Height), outStride, outPixels); | |
// Wrap the buffer in an SKImage. | |
using var skDstImage = SKImage.FromPixels(skDstInfo, outHandle.AddrOfPinnedObject(), outStride); | |
// And save the encoded output. | |
using var outFile = new FileStream(outImgPath, FileMode.Create); | |
skDstImage.Encode(SKEncodedImageFormat.Jpeg, psPipeline.Settings.JpegQuality).SaveTo(outFile); | |
outHandle.Free(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<Project Sdk="Microsoft.NET.Sdk"> | |
<PropertyGroup> | |
<OutputType>Exe</OutputType> | |
<TargetFramework>netcoreapp3.1</TargetFramework> | |
<RestoreAdditionalProjectSources>https://pkgs.dev.azure.com/saucecontrol/PhotoSauce/_packaging/photosauce_ci/nuget/v3/index.json</RestoreAdditionalProjectSources> | |
</PropertyGroup> | |
<ItemGroup> | |
<PackageReference Include="PhotoSauce.MagicScaler" Version="0.10.4-ci*" /> | |
<PackageReference Include="SkiaSharp" Version="1.68.1.1" /> | |
<PackageReference Condition="$([MSBuild]::IsOSPlatform('linux'))" Include="SkiaSharp.NativeAssets.Linux" Version="1.68.1.1" /> | |
</ItemGroup> | |
</Project> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment