PicReady.Lite
1.0.2
dotnet add package PicReady.Lite --version 1.0.2
NuGet\Install-Package PicReady.Lite -Version 1.0.2
<PackageReference Include="PicReady.Lite" Version="1.0.2" />
<PackageVersion Include="PicReady.Lite" Version="1.0.2" />
<PackageReference Include="PicReady.Lite" />
paket add PicReady.Lite --version 1.0.2
#r "nuget: PicReady.Lite, 1.0.2"
#:package PicReady.Lite@1.0.2
#addin nuget:?package=PicReady.Lite&version=1.0.2
#tool nuget:?package=PicReady.Lite&version=1.0.2
PicReady
PicReady turns an uploaded photo into a file you can store and serve: oriented upright, fitted to a box, cropped or masked, optionally watermarked, and encoded as JPEG, PNG, or WebP. PicReady.Lite is the free MIT subset for a plain resize.
Both packages target net8.0 and net9.0. Rendering is SkiaSharp only. There is no System.Drawing and no ImageSharp dependency.
- Developer: $19/year per developer, for 1–50 seats. Buy a Developer key.
- Team: $79/year, up to 10 developers. Buy a Team key.
The license key is emailed within about an hour of purchase. Activation is below.
Quick start
dotnet add package PicReady.Lite
using PicReady;
var thumb = LiteJob.Load(upload)
.Resize(480, 480, FitMode.Contain)
.Background(RgbColor.White)
.Jpeg(JpegPreset.Medium)
.ToBytes();
Pro:
dotnet add package PicReady
PicReadyLicense.Register(licenseKey);
var webp = PicJob.Load(upload)
.Resize(960, 960, FitMode.Cover)
.Webp(80)
.ToBytes();
Pic.Process accepts a byte[], a Stream, or a file path. Every synchronous Pro method has an async twin with the same result. Streams are not disposed by the library. File output is written to a temporary file and moved into place.
Avatar upload, WebP under 100 KB
var avatar = PicJob.Load(upload)
.Circle(256)
.MaxBytes(100 * 1024, OutputFormat.Webp)
.ToBytes();
Circle cover-fits the photo into a square and clears the pixels outside the circle. PNG and WebP keep that outside area transparent. JPEG paints AvatarBackground, and a transparent background becomes white. MaxBytes binary-searches quality and returns the highest quality that fits. If quality MinAutoQuality is still too big, it throws and names the budget and the smallest size it reached.
Product images at 320, 640, and 1280
var set = PicJob.Load(upload)
.Png()
.ResizeMany(320, 640, 1280);
One decode, then one encode per longest side, in the order you asked for. A crop set on the same job is applied before the responsive scale.
Strip camera EXIF
Orientation is applied by default, then metadata is dropped, so a phone photo is stored upright and a later viewer does not rotate it again.
var stored = Pic.Process(upload, new PicSettings
{
Width = 1600,
Fit = FitMode.MaxWidth,
Format = OutputFormat.Jpeg,
Quality = 85
});
var info = Pic.GetInfo(stored);
// info.HasExif is false. info.ExifOrientation is 1.
KeepMetadata = true copies the EXIF block (and PNG text chunks) and sets the orientation tag to 1 after the pixels have been rotated. Leave ApplyExifOrientation false only when you intentionally want the stored tag left as the camera wrote it.
ASP.NET Core
using PicReady.AspNetCore;
app.MapPost("/photos", async (IFormFile file) =>
{
var settings = new PicSettings
{
Width = 1280,
Fit = FitMode.MaxWidth,
Format = OutputFormat.Webp,
MaxBytes = 180 * 1024
};
var bytes = await PicFormFile.ProcessAsync(file, settings);
return Results.File(bytes, PicContent.GetContentType(settings.Format));
});
An empty upload throws. The content type comes from the bytes you asked to encode, not from the filename. PicContent.TryDetect and ImageContentTypes.TryDetect sniff JPEG, PNG, GIF, and WebP headers.
Batch a folder
var files = Directory.GetFiles(inbox, "*.jpg");
var results = await Pic.BatchProcessAsync(
files,
path => Path.Combine(outbox, Path.GetFileNameWithoutExtension(path) + ".webp"),
new PicSettings { Width = 1600, Fit = FitMode.MaxWidth, Format = OutputFormat.Webp, Quality = 80 },
maxDegreeOfParallelism: 4);
foreach (var item in results.Where(item => !item.Success))
Console.Error.WriteLine($"{item.SourcePath}: {item.Error}");
A bad file is reported on that index. The rest of the batch continues. Cancellation stops scheduling further work. maxDegreeOfParallelism below 1 throws.
Watermark a gallery
var marked = PicJob.Load(upload)
.Resize(1200, 1200, FitMode.MaxWidth)
.Watermark("Northwind", mark =>
{
mark.Gravity = Gravity.Bottom;
mark.Margin = 16;
mark.Opacity = 0.85f;
mark.Color = RgbColor.White;
})
.Jpeg(85)
.ToBytes();
Text and image marks are drawn on the finished canvas. They do not change the width or height. Opacity 0 leaves the pixels unchanged. A mark larger than the photo is scaled down so it stays inside the margin.
Contain, Cover, and Stretch
| Mode | Result |
|---|---|
Contain |
The whole image is inside the box. The leftover area is Background. Nothing is cropped. |
Cover |
The box is filled. Overflow is cropped using Gravity or the focal point. There is no letterbox. |
Stretch |
The image is scaled to the exact box. Aspect ratio is not kept. |
MaxWidth |
Width becomes the requested width. Height follows the aspect ratio, including upscale. |
MaxHeight |
Height becomes the requested height. Width follows. |
MaxLongestSide clamps the output after the fit. A 4000px photo is still decoded (within the safety caps) and then scaled down. It is not rejected just because it is larger than the clamp.
Docker and Linux
The packages reference SkiaSharp.NativeAssets.Linux.NoDependencies, plus the Windows and macOS asset packages, so a normal dotnet restore on Linux pulls a native build that does not need a system libfontconfig. The DejaVu Sans font used for watermarks and the trial mark is embedded.
FROM mcr.microsoft.com/dotnet/aspnet:8.0
WORKDIR /app
COPY publish/ .
ENTRYPOINT ["dotnet", "YourApp.dll"]
Publish with dotnet publish -c Release. You do not need apt-get install fontconfig for the built-in text path.
Lite and Pro
| PicReady.Lite | PicReady | |
|---|---|---|
| License | MIT | Commercial EULA, offline key |
| JPEG, PNG, GIF decode | Yes, GIF is the first frame | Yes, plus WebP |
| Encode | JPEG, PNG | JPEG, PNG, WebP |
| Fit modes | Contain, Cover, Stretch, MaxWidth, MaxHeight | Same |
| JPEG quality | Presets 60, 75, 90 | 1–100, plus MaxBytes search |
| EXIF orient and strip | No | Yes |
| Crop, focal, rotate, flip | No | Yes |
| Circle and rounded-rect avatars | No | Yes |
| Text and image watermarks | No | Yes |
ResizeMany, batch, async, IFormFile |
No | Yes |
Lite JPEG preset 75 matches a licensed Pro JPEG at quality 75 for the same PNG source and the same fit. WebP input or an unknown Lite format throws an exception whose message contains "Pro". Leaving Lite width and height at 0 re-encodes at the original size, the same as omitting Pro width and height.
Options
LiteSettings: Width, Height, Fit, Background, Format, Quality, MaxLongestSide, MaxPixels, MaxInputBytes.
PicSettings adds CropWidth, CropHeight, Gravity, FocalX, FocalY, RotateDegrees, Flip, Avatar, AvatarSize, CornerRadius, AvatarBackground, ApplyExifOrientation, KeepMetadata, TextWatermark, ImageWatermark, MaxBytes, MinAutoQuality, MaxAutoQuality.
TextWatermark: Text, Gravity, Opacity, Margin, FontSize, Color.
ImageWatermark: Image, Gravity, Opacity, Margin.
Operation order: decode, EXIF orientation, rotate, flip, crop, avatar mask, resize, image watermark, text watermark, trial mark, encode.
Hard safety caps, applied before Skia allocates a decoded bitmap: longest side 16384, 80 million pixels, 200 MB input. Defaults are 8192, 40 million pixels, and 80 MB. Raising a setting never goes past the hard cap. A header over the cap throws a managed PicException.
Licensing
Buy a Developer key ($19/year per developer, 1–50 seats) or a Team key ($79/year, up to 10 developers). The key is emailed within about an hour of purchase.
Activate it in any one of these places. The first value that is present wins:
- Call
PicReadyLicense.Register(key)at startup. - Set the
PICREADY_LICENSE_KEYenvironment variable to the token. - Put the token in a
picready.licfile next to the application. - Put the token in
license.keyunder the PicReady application-data folder.PICREADY_APPDATAoverrides that folder.
PicReadyLicense.Register(Environment.GetEnvironmentVariable("PICREADY_LICENSE_KEY"));
PicReadyLicense.Register validates the key immediately and throws PicLicenseException when the key is invalid, expired, tampered, or for the wrong product. If a valid key is already active, that key stays in place. If no valid key is active, the failure is latched: later processing throws PicLicenseException instead of producing a trial image, until a valid key is registered. A key that is present in PICREADY_LICENSE_KEY, picready.lic, or license.key and is invalid does not fall through to a later location or to the trial. The key is checked offline. The package does not phone home.
Trial
With no key loaded, and when Register has not rejected a key, Pro still runs.
- Output is a valid JPEG, PNG, or WebP of the same dimensions, with a small corner mark that reads "PicReady trial". The mark does not replace the photo.
- Outside Development, the first Pro call writes a stamp file and starts a 14-day window.
PicReadyLicense.Noticereports the days remaining. At the instant that window ends, processing throwsPicLicenseExceptionandLicenseStatus.OutputAllowedis false. - Development does not expire. Set
ASPNETCORE_ENVIRONMENTorDOTNET_ENVIRONMENTtoDevelopment. PicReadyLicense.Registerwith a valid unexpired key removes the mark.PicReadyLicense.Statusthen reportsLicenseMode.Licensed.
Comparison
| PicReady | ImageSharp | SkiaSharp | Magick.NET | |
|---|---|---|---|---|
| Price | Developer $19/yr per developer (1–50 seats). Team $79/yr, up to 10 developers | ImageSharp Boutique is listed at $799/year for up to 10 developers | MIT | Apache-2.0 |
| License check | Offline key, or a visible trial mark | ImageSharp 3.2 / 4.x documents a build-time license key | None | None |
| Scope | Upload to a served image | General imaging | Low-level drawing | ImageMagick operations |
| Native bits | Skia via NuGet assets | Managed | You choose the asset package | ImageMagick native dependencies |
Sources for the ImageSharp figures: sixlabors.com/pricing and the licence enforcement post. PicReady is not a drop-in ImageSharp replacement. It does not offer ImageSharp's pixel API, and it does not aim to.
Measured speed
Stopwatch, Release build, one warmup plus five iterations, median. Source 1280×720 noise, output 640×360 Contain. Machine cursor, 4 processors. These are the numbers from that run, not a laptop claim and not a BenchmarkDotNet suite.
| .NET 8.0.33 | .NET 9.0.22 | |
|---|---|---|
| Decode, resize, JPEG quality 80 | 46.4 ms | 48.0 ms |
| Decode, resize, WebP quality 80 | 74.3 ms | 76.8 ms |
Same JPEG with MaxBytes 80 KB |
135.7 ms | 134.3 ms |
MaxBytes encodes several qualities. It is slower than a single encode on purpose.
Limits
- GIF and animated WebP: the first frame is decoded. GIF cannot be encoded.
- CMYK JPEG is decoded to RGB. There is no CMYK output.
- JPEG metadata keep copies the EXIF TIFF block. Other APP segments (a separate XMP packet, IPTC, ICC) are not copied. PNG keep copies
tEXt,zTXt,iTXt, andeXIf. WebP keep copies the EXIF chunk. - WebP encode is lossy. There is no lossless WebP switch.
- Angles other than 90, 180, and 270 grow the canvas and resample. Right angles are pixel copies.
- Seat counts are in the key and in the EULA. The library does not count running developers.
- HEIC, AVIF, and TIFF are rejected.
Build
dotnet test PicReady.sln -c Release
dotnet pack src/PicReady.Lite/PicReady.Lite.csproj -c Release
dotnet pack src/PicReady/PicReady.csproj -c Release
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- SkiaSharp (>= 4.155.0)
- SkiaSharp.NativeAssets.Linux.NoDependencies (>= 4.155.0)
- SkiaSharp.NativeAssets.macOS (>= 4.155.0)
- SkiaSharp.NativeAssets.Win32 (>= 4.155.0)
-
net9.0
- SkiaSharp (>= 4.155.0)
- SkiaSharp.NativeAssets.Linux.NoDependencies (>= 4.155.0)
- SkiaSharp.NativeAssets.macOS (>= 4.155.0)
- SkiaSharp.NativeAssets.Win32 (>= 4.155.0)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on PicReady.Lite:
| Package | Downloads |
|---|---|
|
PicReady
Paid image toolkit for web uploads. Resize, crop, avatar masks, WebP, EXIF orientation and stripping, byte-budget quality search, watermarks, batch processing, and ASP.NET Core IFormFile helpers on top of SkiaSharp. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.2 | 0 | 11/9/2026 |