public void Resize(DpiPath dpi, string destination) { var originalSize = GetOriginalSize(); var(scaledSize, scale) = GetScaledSize(originalSize, dpi.Scale); var sw = new Stopwatch(); sw.Start(); // Allocate using (var tempBitmap = new SKBitmap(scaledSize.Width, scaledSize.Height)) { // Draw (copy) using (var canvas = new SKCanvas(tempBitmap)) { canvas.Clear(SKColors.Transparent); canvas.Save(); canvas.Scale(scale, scale); DrawUnscaled(canvas); } // Save (encode) using (var pixmap = tempBitmap.PeekPixels()) using (var wrapper = new SKFileWStream(destination)) { pixmap.Encode(wrapper, SKPngEncoderOptions.Default); } } sw.Stop(); Logger?.Log($"Save Image took {sw.ElapsedMilliseconds}ms ({destination})"); }
public void Resize(DpiPath dpi, string destination) { var originalSize = GetOriginalSize(); var(scaledSize, scale) = GetScaledSize(originalSize, dpi.Scale); var sw = new Stopwatch(); sw.Start(); // Allocate using (var tempBitmap = new SKBitmap(scaledSize.Width, scaledSize.Height)) { // Draw (copy) using (var canvas = new SKCanvas(tempBitmap)) { canvas.Clear(SKColors.Transparent); canvas.Save(); canvas.Scale(scale, scale); DrawUnscaled(canvas, scale); } // Save (encode) using var stream = File.Create(destination); tempBitmap.Encode(stream, SKEncodedImageFormat.Png, 100); } sw.Stop(); Logger?.Log($"Save Image took {sw.ElapsedMilliseconds}ms ({destination})"); }
public void Resize(DpiPath dpi, string destination) { int sourceNominalWidth = Info.BaseSize?.Width ?? (int)svg.Picture.CullRect.Width; int sourceNominalHeight = Info.BaseSize?.Height ?? (int)svg.Picture.CullRect.Height; var resizeRatio = dpi.Scale; // Find the actual size of the SVG var sourceActualWidth = svg.Picture.CullRect.Width; var sourceActualHeight = svg.Picture.CullRect.Height; // Figure out what the ratio to convert the actual image size to the nominal size is var nominalRatio = Math.Max((double)sourceNominalWidth / (double)sourceActualWidth, (double)sourceNominalHeight / (double)sourceActualHeight); // Multiply nominal ratio by the resize ratio to get our final ratio we actually adjust by var adjustRatio = nominalRatio * (double)resizeRatio; // Figure out our scaled width and height to make a new canvas for //var scaledWidth = sourceActualWidth * adjustRatio; //var scaledHeight = sourceActualHeight * adjustRatio; var sw = new Stopwatch(); sw.Start(); using (var stream = File.OpenWrite(destination)) { svg.Picture.ToImage(stream, SKColors.Empty, SKEncodedImageFormat.Png, 100, (float)adjustRatio, (float)adjustRatio, SKColorType.Argb4444, SKAlphaType.Premul); } sw.Stop(); Logger?.Log($"Save Image took {sw.ElapsedMilliseconds}ms"); }
public ResizedImageInfo Resize(DpiPath dpi, string inputsFile) { var destination = GetFileDestination(dpi); if (Info.IsVector) { destination = Path.ChangeExtension(destination, ".png"); } if (IsUpToDate(Info.Filename, destination, inputsFile, Logger)) { return new ResizedImageInfo { Filename = destination, Dpi = dpi } } ; if (tools == null) { tools = SkiaSharpTools.Create(Info.IsVector, Info.Filename, Info.BaseSize, Info.TintColor, Logger); } tools.Resize(dpi, destination); return(new ResizedImageInfo { Filename = destination, Dpi = dpi }); } }
void ProcessAppIcon(SharedImageInfo img, ConcurrentBag <ResizedImageInfo> resizedImages) { var appIconName = img.OutputName; // Generate the actual bitmap app icons themselves var appIconDpis = DpiPath.GetAppIconDpis(PlatformType, appIconName); Log.LogMessage(MessageImportance.Low, $"App Icon"); // Apple and Android have special additional files to generate for app icons if (PlatformType == "android") { Log.LogMessage(MessageImportance.Low, $"Android Adaptive Icon Generator"); appIconName = appIconName.ToLowerInvariant(); var adaptiveIconGen = new AndroidAdaptiveIconGenerator(img, appIconName, IntermediateOutputPath, this); var iconsGenerated = adaptiveIconGen.Generate(); foreach (var iconGenerated in iconsGenerated) { resizedImages.Add(iconGenerated); } } else if (PlatformType == "ios") { Log.LogMessage(MessageImportance.Low, $"iOS Icon Assets Generator"); var appleAssetGen = new AppleIconAssetsGenerator(img, appIconName, IntermediateOutputPath, appIconDpis, this); var assetsGenerated = appleAssetGen.Generate(); foreach (var assetGenerated in assetsGenerated) { resizedImages.Add(assetGenerated); } } Log.LogMessage(MessageImportance.Low, $"Generating App Icon Bitmaps for DPIs"); var appTool = new SkiaSharpAppIconTools(img, this); Log.LogMessage(MessageImportance.Low, $"App Icon: Intermediate Path " + IntermediateOutputPath); foreach (var dpi in appIconDpis) { Log.LogMessage(MessageImportance.Low, $"App Icon: " + dpi); var destination = Resizer.GetFileDestination(img, dpi, IntermediateOutputPath) .Replace("{name}", appIconName); Log.LogMessage(MessageImportance.Low, $"App Icon Destination: " + destination); appTool.Resize(dpi, Path.ChangeExtension(destination, ".png")); } }
public (SKSizeI, float) GetScaledSize(SKSize originalSize, DpiPath dpi) { if (dpi.Size.HasValue) { return(GetScaledSize(originalSize, dpi.Scale, dpi.Size.Value)); } else { return(GetScaledSize(originalSize, dpi.Scale)); } }
void ProcessImageCopy(SharedImageInfo img, DpiPath originalScaleDpi, ConcurrentBag <ResizedImageInfo> resizedImages) { var resizer = new Resizer(img, IntermediateOutputPath, this); Log.LogMessage(MessageImportance.Low, $"Copying {img.Filename}"); var r = resizer.CopyFile(originalScaleDpi, InputsFile, PlatformType.ToLower().Equals("android")); resizedImages.Add(r); Log.LogMessage(MessageImportance.Low, $"Copied {img.Filename}"); }
public static string GetFileDestination(SharedImageInfo info, DpiPath dpi, string intermediateOutputPath) { var fullIntermediateOutputPath = new DirectoryInfo(intermediateOutputPath); var destination = Path.Combine(fullIntermediateOutputPath.FullName, dpi.Path, info.OutputName + dpi.FileSuffix + info.OutputExtension); var fileInfo = new FileInfo(destination); if (!fileInfo.Directory.Exists) { fileInfo.Directory.Create(); } return(destination); }
public ResizedImageInfo CopyFile(DpiPath dpi, string inputsFile, bool isAndroid = false) { var destination = GetFileDestination(dpi); var androidVector = false; if (isAndroid && Info.IsVector && !Info.Resize) { // Update destination to be .xml file destination = Path.ChangeExtension(destination, ".xml"); androidVector = true; } if (IsUpToDate(Info.Filename, destination, inputsFile, Logger)) { return new ResizedImageInfo { Filename = destination, Dpi = dpi } } ; if (androidVector) { Logger.Log("Converting SVG to Android Drawable Vector: " + Info.Filename); // Transform into an android vector drawable var convertErr = Svg2VectorDrawable.Svg2Vector.Convert(Info.Filename, destination); if (!string.IsNullOrEmpty(convertErr)) { throw new Svg2AndroidDrawableConversionException(convertErr, Info.Filename); } } else { // Otherwise just copy it straight File.Copy(Info.Filename, destination, true); } return(new ResizedImageInfo { Filename = destination, Dpi = dpi }); }
public ResizedImageInfo Resize(DpiPath dpi, string inputsFile) { var destination = GetFileDestination(dpi); if (Info.IsVector) { destination = Path.ChangeExtension(destination, ".png"); } if (IsUpToDate(Info.Filename, destination, inputsFile, Logger)) { return new ResizedImageInfo { Filename = destination, Dpi = dpi } } ; if (Info.IsVector) { if (svgTools == null) { svgTools = new SkiaSharpSvgTools(Info, Logger); } svgTools.Resize(dpi, destination); } else { if (bmpTools == null) { bmpTools = new SkiaSharpBitmapTools(Info, Logger); } bmpTools.Resize(dpi, destination); } return(new ResizedImageInfo { Filename = destination, Dpi = dpi }); } }
public void Resize(DpiPath dpi, string destination) { int sourceNominalWidth = Info.BaseSize?.Width ?? bmp.Width; int sourceNominalHeight = Info.BaseSize?.Height ?? bmp.Height; var resizeRatio = dpi.Scale; var sourceActualWidth = bmp.Width; var sourceActualHeight = bmp.Height; var nominalRatio = Math.Max((double)sourceNominalWidth / (double)sourceActualWidth, (double)sourceNominalHeight / (double)sourceActualHeight); var adjustRatio = nominalRatio * Convert.ToDouble(resizeRatio); var newWidth = (int)Math.Floor(bmp.Width * adjustRatio); var newHeight = (int)Math.Floor(bmp.Height * adjustRatio); using (var rzBitmap = bmp.Resize(new SKImageInfo(newWidth, newHeight), SKFilterQuality.High)) using (var img = SKImage.FromBitmap(rzBitmap)) using (var data = img.Encode(SKEncodedImageFormat.Png, 100)) using (var fs = File.Open(destination, FileMode.Create)) { data.SaveTo(fs); } }
public static ResizedImageInfo CopyFile(SharedImageInfo info, DpiPath dpi, string intermediateOutputPath, string inputsFile, ILogger logger, bool isAndroid = false) { var destination = Resizer.GetFileDestination(info, dpi, intermediateOutputPath); var androidVector = false; if (isAndroid && info.IsVector && !info.Resize) { // TODO: Turn SVG into Vector Drawable format // Update destination to be .xml file destination = Path.ChangeExtension(info.Filename, ".xml"); androidVector = true; } if (IsUpToDate(info.Filename, destination, inputsFile, logger)) { return new ResizedImageInfo { Filename = destination, Dpi = dpi } } ; if (androidVector) { // TODO: Don't just copy, let's transform to android vector File.Copy(info.Filename, destination, true); } else { // Otherwise just copy it straight File.Copy(info.Filename, destination, true); } return(new ResizedImageInfo { Filename = destination, Dpi = dpi }); }
System.Threading.Tasks.Task DoExecute() { Svg.SvgDocument.SkipGdiPlusCapabilityCheck = true; var images = ParseImageTaskItems(SharedImages); var dpis = DpiPath.GetDpis(PlatformType); if (dpis == null || dpis.Length <= 0) { return(System.Threading.Tasks.Task.CompletedTask); } var originalScaleDpi = DpiPath.GetOriginal(PlatformType); var resizedImages = new ConcurrentBag <ResizedImageInfo>(); System.Threading.Tasks.Parallel.ForEach(images, img => { var opStopwatch = new Stopwatch(); opStopwatch.Start(); var op = "Resize"; // By default we resize, but let's make sure if (img.Resize) { var resizer = new Resizer(img, IntermediateOutputPath, this); foreach (var dpi in dpis) { var r = resizer.Resize(dpi, InputsFile); resizedImages.Add(r); } } else { op = "Copy"; // Otherwise just copy the thing over to the 1.0 scale var r = Resizer.CopyFile(img, originalScaleDpi, IntermediateOutputPath, InputsFile, this, PlatformType.ToLower().Equals("android")); resizedImages.Add(r); } opStopwatch.Stop(); Log.LogMessage(MessageImportance.Low, $"{op} took {opStopwatch.ElapsedMilliseconds}ms"); }); var copiedResources = new List <TaskItem>(); foreach (var img in resizedImages) { var attr = new Dictionary <string, string>(); string itemSpec = Path.GetFullPath(img.Filename); // Fix the item spec to be relative for mac if (bool.TryParse(IsMacEnabled, out bool isMac) && isMac) { itemSpec = img.Filename; } // Add DPI info to the itemspec so we can use it in the targets attr.Add("_ResizetizerDpiPath", img.Dpi.Path); attr.Add("_ResizetizerDpiScale", img.Dpi.Scale.ToString()); copiedResources.Add(new TaskItem(itemSpec, attr)); } CopiedResources = copiedResources.ToArray(); return(System.Threading.Tasks.Task.CompletedTask); }
public string GetFileDestination(DpiPath dpi) => GetFileDestination(Info, dpi, IntermediateOutputPath);
public ResizedImageInfo Resize(DpiPath dpi, string destination) { var sw = new Stopwatch(); sw.Start(); var(bgScaledSize, bgScale) = backgroundTools.GetScaledSize(backgroundOriginalSize, dpi); // Allocate using (var tempBitmap = new SKBitmap(bgScaledSize.Width, bgScaledSize.Height)) { // Draw (copy) using (var canvas = new SKCanvas(tempBitmap)) { canvas.Clear(SKColors.Transparent); canvas.Save(); canvas.Scale(bgScale, bgScale); backgroundTools.DrawUnscaled(canvas); canvas.Restore(); if (hasForeground) { var userFgScale = (float)Info.ForegroundScale; // get the ratio to make the foreground fill the background var fitRatio = bgScaledSize.Width / foregroundOriginalSize.Width; // calculate the scale for the foreground to fit the background exactly var(fgScaledSize, fgScale) = foregroundTools.GetScaledSize(foregroundOriginalSize, (decimal)fitRatio); Logger.Log("dpi.Size: " + dpi.Size); Logger.Log("dpi.Scale: " + dpi.Scale); Logger.Log("bgScaledSize: " + bgScaledSize); Logger.Log("bgScale: " + bgScale); Logger.Log("foregroundOriginalSize: " + foregroundOriginalSize); Logger.Log("fgScaledSize: " + fgScaledSize); Logger.Log("fgScale: " + fgScale); Logger.Log("userFgScale: " + userFgScale); // now work out the center as if the canvas was exactly the same size as the foreground var fgScaledSizeCenterX = foregroundOriginalSize.Width / 2; var fgScaledSizeCenterY = foregroundOriginalSize.Height / 2; Logger.Log("fgScaledSizeCenterX: " + fgScaledSizeCenterX); Logger.Log("fgScaledSizeCenterY: " + fgScaledSizeCenterY); // scale so the forground is the same size as the background canvas.Scale(fgScale, fgScale); // scale to the user scale, centering canvas.Scale(userFgScale, userFgScale, fgScaledSizeCenterX, fgScaledSizeCenterY); foregroundTools.DrawUnscaled(canvas); } } // Save (encode) using (var pixmap = tempBitmap.PeekPixels()) using (var wrapper = new SKFileWStream(destination)) { pixmap.Encode(wrapper, SKPngEncoderOptions.Default); } } sw.Stop(); Logger?.Log($"Save Image took {sw.ElapsedMilliseconds}ms"); return(new ResizedImageInfo { Dpi = dpi, Filename = destination }); }
System.Threading.Tasks.Task DoExecute() { Svg.SvgDocument.SkipGdiPlusCapabilityCheck = true; var images = ParseImageTaskItems(SharedImages); var dpis = DpiPath.GetDpis(PlatformType); if (dpis == null || dpis.Length <= 0) { return(System.Threading.Tasks.Task.CompletedTask); } var originalScaleDpi = DpiPath.GetOriginal(PlatformType); var resizedImages = new ConcurrentBag <ResizedImageInfo>(); System.Threading.Tasks.Parallel.ForEach(images, img => { if (img.IsAppIcon) { var appIconName = "appicon"; // Path.GetFileNameWithoutExtension(img.Filename); // Generate the actual bitmap app icons themselves var appIconDpis = DpiPath.GetAppIconDpis(PlatformType, appIconName); Log.LogMessage(MessageImportance.Low, $"App Icon"); // Apple and Android have special additional files to generate for app icons if (PlatformType == "android") { Log.LogMessage(MessageImportance.Low, $"Android Adaptive Icon Generator"); appIconName = appIconName.ToLowerInvariant(); var adaptiveIconGen = new AndroidAdaptiveIconGenerator(img, appIconName, IntermediateOutputPath, this); var iconsGenerated = adaptiveIconGen.Generate(); foreach (var iconGenerated in iconsGenerated) { resizedImages.Add(iconGenerated); } } else if (PlatformType == "ios") { Log.LogMessage(MessageImportance.Low, $"iOS Icon Assets Generator"); var appleAssetGen = new AppleIconAssetsGenerator(img, appIconName, IntermediateOutputPath, appIconDpis, this); var assetsGenerated = appleAssetGen.Generate(); foreach (var assetGenerated in assetsGenerated) { resizedImages.Add(assetGenerated); } } Log.LogMessage(MessageImportance.Low, $"Generating App Icon Bitmaps for DPIs"); var appTool = new SkiaSharpAppIconTools(img, this); Log.LogMessage(MessageImportance.Low, $"App Icon: Intermediate Path " + IntermediateOutputPath); foreach (var dpi in appIconDpis) { Log.LogMessage(MessageImportance.Low, $"App Icon: " + dpi); var destination = Resizer.GetFileDestination(img, dpi, IntermediateOutputPath) .Replace("{name}", appIconName); Log.LogMessage(MessageImportance.Low, $"App Icon Destination: " + destination); appTool.Resize(dpi, Path.ChangeExtension(destination, ".png")); } } else { var opStopwatch = new Stopwatch(); opStopwatch.Start(); var op = "Resize"; // By default we resize, but let's make sure if (img.Resize) { var resizer = new Resizer(img, IntermediateOutputPath, this); foreach (var dpi in dpis) { Log.LogMessage(MessageImportance.Low, $"Resizing {img.Filename}"); var r = resizer.Resize(dpi, InputsFile); resizedImages.Add(r); Log.LogMessage(MessageImportance.Low, $"Resized {img.Filename}"); } } else { op = "Copy"; Log.LogMessage(MessageImportance.Low, $"Copying {img.Filename}"); // Otherwise just copy the thing over to the 1.0 scale var r = Resizer.CopyFile(img, originalScaleDpi, IntermediateOutputPath, InputsFile, this, PlatformType.ToLower().Equals("android")); resizedImages.Add(r); Log.LogMessage(MessageImportance.Low, $"Copied {img.Filename}"); } opStopwatch.Stop(); Log.LogMessage(MessageImportance.Low, $"{op} took {opStopwatch.ElapsedMilliseconds}ms"); } }); var copiedResources = new List <TaskItem>(); foreach (var img in resizedImages) { var attr = new Dictionary <string, string>(); string itemSpec = Path.GetFullPath(img.Filename); // Fix the item spec to be relative for mac if (bool.TryParse(IsMacEnabled, out bool isMac) && isMac) { itemSpec = img.Filename; } // Add DPI info to the itemspec so we can use it in the targets attr.Add("_ResizetizerDpiPath", img.Dpi.Path); attr.Add("_ResizetizerDpiScale", img.Dpi.Scale.ToString()); copiedResources.Add(new TaskItem(itemSpec, attr)); } CopiedResources = copiedResources.ToArray(); return(System.Threading.Tasks.Task.CompletedTask); }
System.Threading.Tasks.Task DoExecute() { Svg.SvgDocument.SkipGdiPlusCapabilityCheck = true; var images = ParseImageTaskItems(SharedImages); var dpis = DpiPath.GetDpis(PlatformType); if (dpis == null || dpis.Length <= 0) { return(System.Threading.Tasks.Task.CompletedTask); } var originalScaleDpi = DpiPath.GetOriginal(PlatformType); var resizedImages = new ConcurrentBag <ResizedImageInfo>(); System.Threading.Tasks.Parallel.ForEach(images, img => { try { var opStopwatch = new Stopwatch(); opStopwatch.Start(); string op; if (img.IsAppIcon) { // App icons are special ProcessAppIcon(img, resizedImages); op = "App Icon"; } else { // By default we resize, but let's make sure if (img.Resize) { ProcessImageResize(img, dpis, resizedImages); op = "Resize"; } else { // Otherwise just copy the thing over to the 1.0 scale ProcessImageCopy(img, originalScaleDpi, resizedImages); op = "Copy"; } } opStopwatch.Stop(); Log.LogMessage(MessageImportance.Low, $"{op} took {opStopwatch.ElapsedMilliseconds}ms"); } catch (Exception ex) { Log.LogErrorFromException(ex); throw; } }); var copiedResources = new List <TaskItem>(); foreach (var img in resizedImages) { var attr = new Dictionary <string, string>(); string itemSpec = Path.GetFullPath(img.Filename); // Fix the item spec to be relative for mac if (bool.TryParse(IsMacEnabled, out bool isMac) && isMac) { itemSpec = img.Filename; } // Add DPI info to the itemspec so we can use it in the targets attr.Add("_ResizetizerDpiPath", img.Dpi.Path); attr.Add("_ResizetizerDpiScale", img.Dpi.Scale.ToString()); copiedResources.Add(new TaskItem(itemSpec, attr)); } CopiedResources = copiedResources.ToArray(); return(System.Threading.Tasks.Task.CompletedTask); }