private SKBitmap Crop(SKBitmap original, ResizeParams resizeParams) { var cropSides = 0; var cropTopBottom = 0; // calculate amount of pixels to remove from sides and top/bottom if ((float)resizeParams.w / original.Width < resizeParams.h / original.Height) // crop sides { cropSides = original.Width - (int)Math.Round((float)original.Height / resizeParams.h * resizeParams.w); } else { cropTopBottom = original.Height - (int)Math.Round((float)original.Width / resizeParams.w * resizeParams.h); } // setup crop rect var cropRect = new SKRectI { Left = cropSides / 2, Top = cropTopBottom / 2, Right = original.Width - cropSides + cropSides / 2, Bottom = original.Height - cropTopBottom + cropTopBottom / 2 }; // crop SKBitmap bitmap = new SKBitmap(cropRect.Width, cropRect.Height); original.ExtractSubset(bitmap, cropRect); original.Dispose(); return(bitmap); }
internal static SKBitmap WatermarkText(SKBitmap original, ResizeParams resizeParams, WatermarkTextModel watermarkText) { var toBitmap = new SKBitmap(original.Width, original.Height); var canvas = new SKCanvas(toBitmap); // Draw a bitmap rescaled var paint = new SKPaint(); //paint.Typeface = SKTypeface.FromFamilyName("Arial"); paint.TextSize = watermarkText.TextSize; paint.TextAlign = watermarkText.TextAlign.GetSKTextAlign(); if (watermarkText.IsVerticalText) { paint.IsVerticalText = true; } else { paint.IsLinearText = true; } if (watermarkText.Type == 2) { paint.IsStroke = true; paint.StrokeWidth = watermarkText.StrokeWidth; paint.StrokeCap = SKStrokeCap.Round; } paint.Style = watermarkText.Type.GetSKPaintStyle(); paint.FilterQuality = watermarkText.Quality.GetSKFilterQuality(); paint.TextSkewX = watermarkText.TextSkewX; paint.IsAntialias = true; //https://www.color-hex.com/ if (SKColor.TryParse(watermarkText.Color, out SKColor color)) { paint.Color = color; } else { paint.Color = SKColors.Black; } canvas.DrawBitmap(original, 0, 0); var x = watermarkText.PositionMeasureType == 1 ? watermarkText.X : watermarkText.X.ToPixel(original.Width); var y = watermarkText.PositionMeasureType == 1 ? watermarkText.Y : watermarkText.Y.ToPixel(original.Height); canvas.DrawText(watermarkText.Value, x, y, paint); canvas.Flush(); canvas.Dispose(); paint.Dispose(); original.Dispose(); return(toBitmap); }
public async Task Invoke(HttpContext context) { PathString path = context.Request.Path; // hand to next middleware if we are not dealing with an image if (context.Request.Query.Count == 0 || !IsImagePath(path)) { await _next.Invoke(context); return; } // hand to next middleware if we are dealing with an image but it doesn't have any usable resize querystring params ResizeParams resizeParams = GetResizeParams(path, context.Request.Query); if (!resizeParams.hasParams || (resizeParams.w == 0 && resizeParams.h == 0)) { await _next.Invoke(context); return; } // get the image location on disk string imagePath = Path.Combine( _env.WebRootPath, path.Value.Replace('/', Path.DirectorySeparatorChar).TrimStart(Path.DirectorySeparatorChar)); // check file lastwrite DateTime lastWriteTimeUtc = File.GetLastWriteTimeUtc(imagePath); if (lastWriteTimeUtc.Year == 1601) // file doesn't exist, pass to next middleware { await _next.Invoke(context); return; } SKData imageData = GetImageData(imagePath, resizeParams, lastWriteTimeUtc); // write to stream context.Response.ContentType = resizeParams.format == "png" ? "image/png" : "image/jpeg"; context.Response.ContentLength = imageData.Size; await context.Response.Body.WriteAsync(imageData.ToArray(), 0, (int)imageData.Size); // cleanup imageData.Dispose(); }
private ResizeParams GetResizeParams(PathString path, IQueryCollection query) { ResizeParams resizeParams = new ResizeParams(); // before we extract, do a quick check for resize params resizeParams.hasParams = resizeParams.GetType().GetTypeInfo() .GetFields().Where(f => f.Name != "hasParams") .Any(f => query.ContainsKey(f.Name)); // if no params present, bug out if (!resizeParams.hasParams) { return(resizeParams); } // extract resize params if (query.ContainsKey("format")) { resizeParams.format = query["format"]; } else { resizeParams.format = path.Value.Substring(path.Value.LastIndexOf('.') + 1); } if (query.ContainsKey("autorotate")) { bool.TryParse(query["autorotate"], out resizeParams.autorotate); } int quality = 100; if (query.ContainsKey("quality")) { int.TryParse(query["quality"], out quality); } resizeParams.quality = quality; int w = 0; if (query.ContainsKey("w")) { int.TryParse(query["w"], out w); } resizeParams.w = w; int h = 0; if (query.ContainsKey("h")) { int.TryParse(query["h"], out h); } resizeParams.h = h; resizeParams.mode = "max"; // only apply mode if it's a valid mode and both w and h are specified if (h != 0 && w != 0 && query.ContainsKey("mode") && ResizeParams.modes.Any(m => query["mode"] == m)) { resizeParams.mode = query["mode"]; } return(resizeParams); }
private SKData GetImageData(string imagePath, ResizeParams resizeParams, DateTime lastWriteTimeUtc) { // check cache and return if cached long cacheKey; unchecked { cacheKey = imagePath.GetHashCode() + lastWriteTimeUtc.ToBinary() + resizeParams.ToString().GetHashCode(); } SKData imageData; byte[] imageBytes; bool isCached = _memoryCache.TryGetValue <byte[]>(cacheKey, out imageBytes); if (isCached) { _logger.LogInformation("Serving from cache"); return(SKData.CreateCopy(imageBytes)); } SKCodecOrigin origin; // this represents the EXIF orientation var bitmap = LoadBitmap(File.OpenRead(imagePath), out origin); // always load as 32bit (to overcome issues with indexed color) // if autorotate = true, and origin isn't correct for the rotation, rotate it if (resizeParams.autorotate && origin != SKCodecOrigin.TopLeft) { bitmap = RotateAndFlip(bitmap, origin); } // if either w or h is 0, set it based on ratio of original image if (resizeParams.h == 0) { resizeParams.h = (int)Math.Round(bitmap.Height * (float)resizeParams.w / bitmap.Width); } else if (resizeParams.w == 0) { resizeParams.w = (int)Math.Round(bitmap.Width * (float)resizeParams.h / bitmap.Height); } // if we need to crop, crop the original before resizing if (resizeParams.mode == "crop") { bitmap = Crop(bitmap, resizeParams); } // store padded height and width var paddedHeight = resizeParams.h; var paddedWidth = resizeParams.w; // if we need to pad, or max, set the height or width according to ratio if (resizeParams.mode == "pad" || resizeParams.mode == "max") { var bitmapRatio = (float)bitmap.Width / bitmap.Height; var resizeRatio = (float)resizeParams.w / resizeParams.h; if (bitmapRatio > resizeRatio) // original is more "landscape" { resizeParams.h = (int)Math.Round(bitmap.Height * ((float)resizeParams.w / bitmap.Width)); } else { resizeParams.w = (int)Math.Round(bitmap.Width * ((float)resizeParams.h / bitmap.Height)); } } // resize var resizedImageInfo = new SKImageInfo(resizeParams.w, resizeParams.h, SKImageInfo.PlatformColorType, bitmap.AlphaType); var resizedBitmap = bitmap.Resize(resizedImageInfo, SKBitmapResizeMethod.Lanczos3); // optionally pad if (resizeParams.mode == "pad") { resizedBitmap = Pad(resizedBitmap, paddedWidth, paddedHeight, resizeParams.format != "png"); } // encode var resizedImage = SKImage.FromBitmap(resizedBitmap); var encodeFormat = resizeParams.format == "png" ? SKEncodedImageFormat.Png : SKEncodedImageFormat.Jpeg; imageData = resizedImage.Encode(encodeFormat, resizeParams.quality); // cache the result _memoryCache.Set <byte[]>(cacheKey, imageData.ToArray()); // cleanup resizedImage.Dispose(); bitmap.Dispose(); resizedBitmap.Dispose(); return(imageData); }
internal static global::System.Runtime.InteropServices.HandleRef getCPtr(ResizeParams obj) { return((obj == null) ? new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero) : obj.swigCPtr); }
internal static SKBitmap WatermarkImage(SKBitmap original, ResizeParams resizeParams, WatermarkImageModel watermarkImage) { return(null); }
private SKData GetImageData(string imagePath, ResizeParams resizeParams, DateTime lastWriteTimeUtc) { // check cache and return if cached string cacheKey; unchecked { cacheKey = "imgasc_" + imagePath.GetHashCode() + lastWriteTimeUtc.ToBinary() + resizeParams.ToString().GetHashCode(); } SKData imageData; byte[] cacheData = _asyncCacheService.GetByKeyAsync <byte[]>(cacheKey).Result; if (cacheData != null) { return(SKData.CreateCopy(cacheData)); } // this represents the EXIF orientation SKBitmap bitmap = LoadBitmap(File.OpenRead(imagePath), out SKEncodedOrigin origin); // always load as 32bit (to overcome issues with indexed color) // if autorotate = true, and origin isn't correct for the rotation, rotate it if (resizeParams.autorotate && origin != SKEncodedOrigin.TopLeft) { bitmap = RotateAndFlip(bitmap, origin); } // if either w or h is 0, set it based on ratio of original image if (resizeParams.h == 0) { resizeParams.h = (int)Math.Round(bitmap.Height * (float)resizeParams.w / bitmap.Width); } else if (resizeParams.w == 0) { resizeParams.w = (int)Math.Round(bitmap.Width * (float)resizeParams.h / bitmap.Height); } // if we need to crop, crop the original before resizing if (resizeParams.mode == "crop") { bitmap = Crop(bitmap, resizeParams); } // store padded height and width int paddedHeight = resizeParams.h; int paddedWidth = resizeParams.w; // if we need to pad, or max, set the height or width according to ratio if (resizeParams.mode == "pad" || resizeParams.mode == "max") { float bitmapRatio = (float)bitmap.Width / bitmap.Height; float resizeRatio = (float)resizeParams.w / resizeParams.h; if (bitmapRatio > resizeRatio) // original is more "landscape" { resizeParams.h = (int)Math.Round(bitmap.Height * ((float)resizeParams.w / bitmap.Width)); } else { resizeParams.w = (int)Math.Round(bitmap.Width * ((float)resizeParams.h / bitmap.Height)); } } // resize SKImageInfo resizedImageInfo = new SKImageInfo(resizeParams.w, resizeParams.h, SKImageInfo.PlatformColorType, bitmap.AlphaType); SKBitmap resizedBitmap = bitmap.Resize(resizedImageInfo, SKFilterQuality.None); // optionally pad if (resizeParams.mode == "pad") { resizedBitmap = Pad(resizedBitmap, paddedWidth, paddedHeight, resizeParams.format != "png"); } // encode SKImage resizedImage = SKImage.FromBitmap(resizedBitmap); SKEncodedImageFormat encodeFormat = resizeParams.format == "png" ? SKEncodedImageFormat.Png : SKEncodedImageFormat.Jpeg; imageData = resizedImage.Encode(encodeFormat, resizeParams.quality); // cache the result _asyncCacheService.SetValueAsync(cacheKey, imageData.ToArray()); // cleanup resizedImage.Dispose(); bitmap.Dispose(); resizedBitmap.Dispose(); return(imageData); }