private SKBitmap CropWhiteSpace(SKBitmap bitmap) { var topmost = 0; for (int row = 0; row < bitmap.Height; ++row) { if (IsTransparentRow(bitmap, row)) { topmost = row + 1; } else { break; } } int bottommost = bitmap.Height; for (int row = bitmap.Height - 1; row >= 0; --row) { if (IsTransparentRow(bitmap, row)) { bottommost = row; } else { break; } } int leftmost = 0, rightmost = bitmap.Width; for (int col = 0; col < bitmap.Width; ++col) { if (IsTransparentColumn(bitmap, col)) { leftmost = col + 1; } else { break; } } for (int col = bitmap.Width - 1; col >= 0; --col) { if (IsTransparentColumn(bitmap, col)) { rightmost = col; } else { break; } } var newRect = SKRectI.Create(leftmost, topmost, rightmost - leftmost, bottommost - topmost); using (var image = SKImage.FromBitmap(bitmap)) { using (var subset = image.Subset(newRect)) { return(SKBitmap.FromImage(subset)); } } }
private Material GenerateGLTFMaterialFromRenderMaterial(VMaterial renderMaterial, ModelRoot model, string materialName) { var material = model .CreateMaterial(materialName) .WithDefault(); renderMaterial.IntParams.TryGetValue("F_TRANSLUCENT", out var isTranslucent); material.Alpha = isTranslucent > 0 ? AlphaMode.BLEND : AlphaMode.OPAQUE; float metalValue = 0; foreach (var floatParam in renderMaterial.FloatParams) { if (floatParam.Key == "g_flMetalness") { metalValue = floatParam.Value; } } // assume non-metallic unless prompted material.WithPBRMetallicRoughness(Vector4.One, null, metallicFactor: metalValue); foreach (var renderTexture in renderMaterial.TextureParams) { var texturePath = renderTexture.Value; var fileName = Path.GetFileNameWithoutExtension(texturePath); ProgressDialog.SetProgress($"Exporting texture: {texturePath}"); var textureResource = GuiContext.LoadFileByAnyMeansNecessary(texturePath + "_c"); if (textureResource == null) { continue; } var bitmap = ((ValveResourceFormat.ResourceTypes.Texture)textureResource.DataBlock).GenerateBitmap(); if (renderTexture.Key == "g_tColor" && material.Alpha == AlphaMode.OPAQUE) { // expensive transparency workaround for color maps for (int row = 0; row < bitmap.Width; row++) { for (int col = 0; col < bitmap.Height; col++) { var pixelAt = bitmap.GetPixel(row, col); bitmap.SetPixel(row, col, new SKColor(pixelAt.Red, pixelAt.Green, pixelAt.Blue, 255)); } } } var textureImage = SKImage.FromBitmap(bitmap); using var data = textureImage.Encode(SKEncodedImageFormat.Png, 100); var image = model.UseImageWithContent(data.ToArray()); // TODO find a way to change the image's URI to be the image name, right now it turns into (model)_0, (model)_1.... image.Name = fileName + $"_{model.LogicalImages.Count - 1}"; var sampler = model.UseTextureSampler(TextureWrapMode.REPEAT, TextureWrapMode.REPEAT, TextureMipMapFilter.NEAREST, TextureInterpolationFilter.DEFAULT); sampler.Name = fileName; var tex = model.UseTexture(image); tex.Name = fileName + $"_{model.LogicalTextures.Count - 1}"; tex.Sampler = sampler; switch (renderTexture.Key) { case "g_tColor": material.FindChannel("BaseColor")?.SetTexture(0, tex); var indexTexture = new JsonDictionary() { ["index"] = image.LogicalIndex }; var dict = material.TryUseExtrasAsDictionary(true); dict["baseColorTexture"] = indexTexture; break; case "g_tNormal": material.FindChannel("Normal")?.SetTexture(0, tex); break; case "g_tAmbientOcclusion": material.FindChannel("Occlusion")?.SetTexture(0, tex); break; case "g_tEmissive": material.FindChannel("Emissive")?.SetTexture(0, tex); break; case "g_tShadowFalloff": // example: tongue_gman, materials/default/default_skin_shadowwarp_tga_f2855b6e.vtex case "g_tCombinedMasks": // example: models/characters/gman/materials/gman_head_mouth_mask_tga_bb35dc38.vtex case "g_tDiffuseFalloff": // example: materials/default/default_skin_diffusewarp_tga_e58a9ed.vtex case "g_tIris": // example: case "g_tIrisMask": // example: models/characters/gman/materials/gman_eye_iris_mask_tga_a5bb4a1e.vtex case "g_tTintColor": // example: models/characters/lazlo/eyemeniscus_vmat_g_ttintcolor_a00ef19e.vtex case "g_tAnisoGloss": // example: gordon_beard, models/characters/gordon/materials/gordon_hair_normal_tga_272a44e9.vtex case "g_tBentNormal": // example: gman_teeth, materials/default/default_skin_shadowwarp_tga_f2855b6e.vtex case "g_tFresnelWarp": // example: brewmaster_color, materials/default/default_fresnelwarprim_tga_d9279d65.vtex case "g_tMasks1": // example: brewmaster_color, materials/models/heroes/brewmaster/brewmaster_base_metalnessmask_psd_58eaa40f.vtex case "g_tMasks2": // example: brewmaster_color,materials/models/heroes/brewmaster/brewmaster_base_specmask_psd_63e9fb90.vtex default: Console.WriteLine($"Warning: Unsupported Texture Type {renderTexture.Key}"); break; } } return(material); }
public void Save(string filename, ImageFormat format) { using (var stream = File.OpenWrite(filename)) SKImage.FromBitmap(nativeSkBitmap).Encode(format.format, 100).SaveTo(stream); }
public SKImage ToSKImage() { return(SKImage.FromBitmap(nativeSkBitmap)); }
public static SKImage[] GetImageRotations(SKBitmap Source) { lock (Source) { SKBitmap Rotate90 = RotateBitmap(Source, 90); SKBitmap Rotate180 = RotateBitmap(Source, 180); SKBitmap Rotate270 = RotateBitmap(Source, 270); return(new SKImage[] { SKImage.FromBitmap(Source), SKImage.FromBitmap(Rotate90), SKImage.FromBitmap(Rotate180), SKImage.FromBitmap(Rotate270) }); } }
private SKBitmap BuildThumbCollageBitmap(string[] paths, int width, int height) { var bitmap = new SKBitmap(width, height); using (var canvas = new SKCanvas(bitmap)) { canvas.Clear(SKColors.Black); // determine sizes for each image that will composited into the final image var iSlice = Convert.ToInt32(width * 0.23475); int iTrans = Convert.ToInt32(height * .25); int iHeight = Convert.ToInt32(height * .70); var horizontalImagePadding = Convert.ToInt32(width * 0.0125); var verticalSpacing = Convert.ToInt32(height * 0.01111111111111111111111111111111); int imageIndex = 0; for (int i = 0; i < 4; i++) { using (var currentBitmap = GetNextValidImage(paths, imageIndex, out int newIndex)) { imageIndex = newIndex; if (currentBitmap == null) { continue; } // resize to the same aspect as the original int iWidth = (int)Math.Abs(iHeight * currentBitmap.Width / currentBitmap.Height); using (var resizeBitmap = new SKBitmap(iWidth, iHeight, currentBitmap.ColorType, currentBitmap.AlphaType)) { currentBitmap.ScalePixels(resizeBitmap, SKFilterQuality.High); // crop image int ix = (int)Math.Abs((iWidth - iSlice) / 2); using (var image = SKImage.FromBitmap(resizeBitmap)) using (var subset = image.Subset(SKRectI.Create(ix, 0, iSlice, iHeight))) { // draw image onto canvas canvas.DrawImage(subset ?? image, (horizontalImagePadding * (i + 1)) + (iSlice * i), verticalSpacing); if (subset == null) { continue; } // create reflection of image below the drawn image using (var croppedBitmap = SKBitmap.FromImage(subset)) using (var reflectionBitmap = new SKBitmap(croppedBitmap.Width, croppedBitmap.Height / 2, croppedBitmap.ColorType, croppedBitmap.AlphaType)) { // resize to half height currentBitmap.ScalePixels(reflectionBitmap, SKFilterQuality.High); using (var flippedBitmap = new SKBitmap(reflectionBitmap.Width, reflectionBitmap.Height, reflectionBitmap.ColorType, reflectionBitmap.AlphaType)) using (var flippedCanvas = new SKCanvas(flippedBitmap)) { // flip image vertically var matrix = SKMatrix.MakeScale(1, -1); matrix.SetScaleTranslate(1, -1, 0, flippedBitmap.Height); flippedCanvas.SetMatrix(matrix); flippedCanvas.DrawBitmap(reflectionBitmap, 0, 0); flippedCanvas.ResetMatrix(); // create gradient to make image appear as a reflection var remainingHeight = height - (iHeight + (2 * verticalSpacing)); flippedCanvas.ClipRect(SKRect.Create(reflectionBitmap.Width, remainingHeight)); using (var gradient = new SKPaint()) { gradient.IsAntialias = true; gradient.BlendMode = SKBlendMode.SrcOver; gradient.Shader = SKShader.CreateLinearGradient(new SKPoint(0, 0), new SKPoint(0, remainingHeight), new[] { new SKColor(0, 0, 0, 128), new SKColor(0, 0, 0, 208), new SKColor(0, 0, 0, 240), new SKColor(0, 0, 0, 255) }, null, SKShaderTileMode.Clamp); flippedCanvas.DrawPaint(gradient); } // finally draw reflection onto canvas canvas.DrawBitmap(flippedBitmap, (horizontalImagePadding * (i + 1)) + (iSlice * i), iHeight + (2 * verticalSpacing)); } } } } } } } return(bitmap); }
public async Task <Tuple <Stream, LoadingResult, ImageInformation> > Resolve(string identifier, TaskParameter parameters, CancellationToken token) { ImageSource source = parameters.Source; if (!string.IsNullOrWhiteSpace(parameters.LoadingPlaceholderPath) && parameters.LoadingPlaceholderPath == identifier) { source = parameters.LoadingPlaceholderSource; } else if (!string.IsNullOrWhiteSpace(parameters.ErrorPlaceholderPath) && parameters.ErrorPlaceholderPath == identifier) { source = parameters.ErrorPlaceholderSource; } var resolvedData = await(Configuration.DataResolverFactory ?? new DataResolverFactory()) .GetResolver(identifier, source, parameters, Configuration) .Resolve(identifier, parameters, token).ConfigureAwait(false); if (resolvedData?.Item1 == null) { throw new FileNotFoundException(identifier); } var svg = new SKSvg() { ThrowOnUnsupportedElement = false, }; SKPicture picture; if (ReplaceStringMap == null || ReplaceStringMap.Count == 0) { using (var svgStream = resolvedData.Item1) { picture = svg.Load(resolvedData?.Item1); } } else { using (var svgStream = resolvedData.Item1) using (var reader = new StreamReader(svgStream)) { var builder = new StringBuilder(await reader.ReadToEndAsync()); foreach (var map in ReplaceStringMap) { builder.Replace(map.Key, map.Value); } using (var svgFinalStream = new MemoryStream(Encoding.UTF8.GetBytes(builder.ToString()))) { picture = svg.Load(svgFinalStream); } } } double sizeX = 0; double sizeY = 0; if (VectorWidth == 0 && VectorHeight == 0) { if (picture.CullRect.Width > 0) { sizeX = picture.CullRect.Width; } else { sizeX = 300; } if (picture.CullRect.Height > 0) { sizeY = picture.CullRect.Height; } else { sizeY = 300; } } else if (VectorWidth > 0 && VectorHeight > 0) { sizeX = VectorWidth; sizeY = VectorHeight; } else if (VectorWidth > 0) { sizeX = VectorWidth; sizeY = (VectorWidth / picture.CullRect.Width) * picture.CullRect.Height; } else { sizeX = (VectorHeight / picture.CullRect.Height) * picture.CullRect.Width; sizeY = VectorHeight; } if (UseDipUnits) { #if __ANDROID__ sizeX = sizeX.DpToPixels(); sizeY = sizeY.DpToPixels(); #else sizeX = sizeX.PointsToPixels(); sizeY = sizeY.PointsToPixels(); #endif } using (var bitmap = new SKBitmap(new SKImageInfo((int)sizeX, (int)sizeY))) //using (var bitmap = new SKBitmap((int)sizeX, (int)sizeY)) using (var canvas = new SKCanvas(bitmap)) using (var paint = new SKPaint()) { canvas.Clear(SKColors.Transparent); float scaleX = (float)sizeX / picture.CullRect.Width; float scaleY = (float)sizeY / picture.CullRect.Height; var matrix = SKMatrix.MakeScale(scaleX, scaleY); canvas.DrawPicture(picture, ref matrix, paint); canvas.Flush(); using (var image = SKImage.FromBitmap(bitmap)) //using (var data = image.Encode(SKImageEncodeFormat.Png, 100)) //TODO disabled because of https://github.com/mono/SkiaSharp/issues/285 using (var data = image.Encode()) { var stream = new MemoryStream(); data.SaveTo(stream); stream.Position = 0; //var stream = data?.AsStream(); return(new Tuple <Stream, LoadingResult, ImageInformation>(stream, resolvedData.Item2, resolvedData.Item3)); } } }
private void CreateFeature() { lock (_sync) { if (Feature == null) { // Create a new one Feature = new Feature { Geometry = Position.ToMapsui(), ["Label"] = Label, }; if (_callout != null) { _callout.Feature.Geometry = Position.ToMapsui(); } } // Check for bitmapId if (_bitmapId != -1) { // There is already a registered bitmap, so delete it BitmapRegistry.Instance.Unregister(_bitmapId); // We don't have any bitmap up to now _bitmapId = -1; } Stream stream = null; switch (Type) { case PinType.Svg: // Load the SVG document if (!string.IsNullOrEmpty(Svg)) { stream = new MemoryStream(Encoding.UTF8.GetBytes(Svg)); } if (stream == null) { return; } _bitmapId = BitmapRegistry.Instance.Register(stream); break; case PinType.Pin: // First we have to create a bitmap from Svg code // Create a new SVG object var svg = new SkiaSharp.Extended.Svg.SKSvg(); // Load the SVG document stream = Utilities.EmbeddedResourceLoader.Load("Images.Pin.svg", typeof(Pin)); if (stream == null) { return; } svg.Load(stream); Width = svg.CanvasSize.Width * Scale; Height = svg.CanvasSize.Height * Scale; // Create bitmap to hold canvas var info = new SKImageInfo((int)svg.CanvasSize.Width, (int)svg.CanvasSize.Height) { AlphaType = SKAlphaType.Premul }; var bitmap = new SKBitmap(info); var canvas = new SKCanvas(bitmap); // Now draw Svg image to bitmap using (var paint = new SKPaint() { IsAntialias = true }) { // Replace color while drawing paint.ColorFilter = SKColorFilter.CreateBlendMode(Color.ToSKColor(), SKBlendMode.SrcIn); // use the source color canvas.Clear(); canvas.DrawPicture(svg.Picture, paint); } // Now convert canvas to bitmap using (var image = SKImage.FromBitmap(bitmap)) using (var data = image.Encode(SKEncodedImageFormat.Png, 100)) { _bitmapData = data.ToArray(); } _bitmapId = BitmapRegistry.Instance.Register(new MemoryStream(_bitmapData)); break; case PinType.Icon: if (Icon != null) { using (var image = SKBitmap.Decode(Icon)) { Width = image.Width * Scale; Height = image.Height * Scale; _bitmapId = BitmapRegistry.Instance.Register(new MemoryStream(Icon)); } } break; } // If we have a bitmapId (and we should have one), than draw bitmap, otherwise nothing if (_bitmapId != -1) { // We only want to have one style Feature.Styles.Clear(); Feature.Styles.Add(new SymbolStyle { BitmapId = _bitmapId, SymbolScale = Scale, SymbolRotation = Rotation, SymbolOffset = new Offset(Anchor.X, Anchor.Y), Opacity = 1 - Transparency, Enabled = IsVisible, }); } } }
private void RenderPicker(int w = 0, int h = 0) { var disp = Dispatcher; double width = w > 0 ? w : this.Width; double height = h > 0 ? h : this.Height; if (width == -1 || height == -1) { return; } double colorVal = this.ColorValue; double offset = this.HueOffset; bool invert = this.InvertSaturation; float esize = this.ElementSize; ColorPickerMode mode = this.Mode; _ = Task.Run(() => { ColorPickerRenderer cw; if (w <= 0) { if (double.IsNaN(width)) { return; } w = (int)width; } if (h <= 0) { if (double.IsNaN(height)) { return; } h = (int)height; } if (w < 32 || h < 32) { return; } if (mode == ColorPickerMode.Wheel || mode == ColorPickerMode.HexagonWheel) { int rad; if (h < w) { rad = h / 2; w = h; } else { rad = w / 2; h = w; } cw = new ColorPickerRenderer(rad, colorVal, offset, invert, true); } else { cw = new ColorPickerRenderer(w, h, colorVal, offset, invert, mode == ColorPickerMode.LinearVertical, true); } Device.BeginInvokeOnMainThread(() => { SKImage img; SKBitmap bmp = new SKBitmap((int)cw.Bounds.Width, (int)cw.Bounds.Height, SKColorType.Bgra8888, SKAlphaType.Premul); var ptr = bmp.GetPixels(); unsafe { var gch = GCHandle.Alloc(cw.ImageBytes, GCHandleType.Pinned); Buffer.MemoryCopy((void *)gch.AddrOfPinnedObject(), (void *)ptr, cw.ImageBytes.Length, cw.ImageBytes.Length); gch.Free(); } bmp.SetImmutable(); img = SKImage.FromBitmap(bmp); SKData encoded = img.Encode(); Stream stream = encoded.AsStream(); var ret = ImageSource.FromStream(() => stream); cpRender = cw; PickerSite.Source = ret; }); }); }
/// <summary> /// 剪裁图片 /// </summary> /// <param name="bytes">图片内容</param> /// <returns>为空:剪裁失败或者不需要剪裁。</returns> /// <param name="url">图片地址</param> private async Task <HttpResponseInfo> CutImage(byte[] bytes, string url = null) { logger?.Info($"{nameof(CutImage)}: staring..."); try { using (var ms = new MemoryStream(bytes)) { ms.Position = 0; using (var inputStream = new SKManagedStream(ms)) { using (var bitmap = SKBitmap.Decode(inputStream)) { var h = bitmap.Height; var w = bitmap.Width; var w2 = h * 2 / 3; //封面宽度 if (w2 < w) //需要剪裁 { var x = await GetBaiduBodyAnalysisResult(bytes, url); var start_w = w - w2; //默认右边 if (x > 0) //百度人体识别,中心点位置 { if (x + w2 / 2 > w) //右边 { start_w = w - w2; } else if (x - w2 / 2 < 0)//左边 { start_w = 0; } else //居中 { start_w = (int)x - w2 / 2; } } var image = SKImage.FromBitmap(bitmap); var subset = image.Subset(SKRectI.Create(start_w, 0, w2, h)); var encodedData = subset.Encode(SKEncodedImageFormat.Jpeg, 90); logger?.Info($"{nameof(CutImage)}: Already cut {w}x{h} --> start_w: {start_w}"); return(new HttpResponseInfo() { Content = encodedData.AsStream(), ContentLength = encodedData.Size, ContentType = "image/jpeg", StatusCode = HttpStatusCode.OK, }); } logger?.Info($"{nameof(CutImage)}: not need to cut. {w}x{h}"); return(null); } } } } catch (Exception ex) { logger?.Warn($"{nameof(CutImage)}: cut image failed. {ex.Message}"); } logger?.Warn($"{nameof(CutImage)}: cut image failed."); return(null); }
private Stream Draw() { string chars = null; string upperData = null; if (string.IsNullOrEmpty(_data)) { chars = ".."; } else if (_data?.Length > 1) { upperData = _data.ToUpper(); chars = GetFirstLetters(upperData, 2); } else { chars = upperData = _data.ToUpper(); } var bgColor = StringToColor(upperData); var textColor = Color.White; var size = 50; var bitmap = new SKBitmap( size * 2, size * 2, SKImageInfo.PlatformColorType, SKAlphaType.Premul); var canvas = new SKCanvas(bitmap); canvas.Clear(SKColors.Transparent); var midX = canvas.LocalClipBounds.Size.ToSizeI().Width / 2; var midY = canvas.LocalClipBounds.Size.ToSizeI().Height / 2; var radius = midX - midX / 5; var circlePaint = new SKPaint { IsAntialias = true, Style = SKPaintStyle.Fill, StrokeJoin = SKStrokeJoin.Miter, Color = SKColor.Parse(bgColor.ToHex()) }; canvas.DrawCircle(midX, midY, radius, circlePaint); var typeface = SKTypeface.FromFamilyName("Arial", SKFontStyle.Normal); var textSize = midX / 1.3f; var textPaint = new SKPaint { IsAntialias = true, Style = SKPaintStyle.Fill, Color = SKColor.Parse(textColor.ToHex()), TextSize = textSize, TextAlign = SKTextAlign.Center, Typeface = typeface }; var rect = new SKRect(); textPaint.MeasureText(chars, ref rect); canvas.DrawText(chars, midX, midY + rect.Height / 2, textPaint); return(SKImage.FromBitmap(bitmap).Encode(SKEncodedImageFormat.Png, 100).AsStream()); }
public void InsertImageFromByteArrayNetStandard2() { //ExStart //ExFor:DocumentBuilder.InsertImage(Byte[]) //ExFor:DocumentBuilder.InsertImage(Byte[], Double, Double) //ExFor:DocumentBuilder.InsertImage(Byte[], RelativeHorizontalPosition, Double, RelativeVerticalPosition, Double, Double, Double, WrapType) //ExSummary:Shows how to insert an image from a byte array into a document (.NetStandard 2.0). Document doc = new Document(); DocumentBuilder builder = new DocumentBuilder(doc); // Decoding the image will convert it to the .png format. using (SKBitmap bitmap = SKBitmap.Decode(ImageDir + "Logo.jpg")) { using (SKImage image = SKImage.FromBitmap(bitmap)) { using (SKData data = image.Encode()) { byte[] imageByteArray = data.ToArray(); // Below are three ways of inserting an image from a byte array: // 1 - Inline shape with a default size based on the image's original dimensions: builder.InsertImage(imageByteArray); builder.InsertBreak(BreakType.PageBreak); // 2 - Inline shape with custom dimensions: builder.InsertImage(imageByteArray, ConvertUtil.PixelToPoint(250), ConvertUtil.PixelToPoint(144)); builder.InsertBreak(BreakType.PageBreak); // 3 - Floating shape with custom dimensions: builder.InsertImage(imageByteArray, RelativeHorizontalPosition.Margin, 100, RelativeVerticalPosition.Margin, 100, 200, 100, WrapType.Square); } } } doc.Save(ArtifactsDir + "DocumentBuilderImages.InsertImageFromByteArrayNetStandard2.docx"); //ExEnd doc = new Document(ArtifactsDir + "DocumentBuilderImages.InsertImageFromByteArrayNetStandard2.docx"); Shape imageShape = (Shape)doc.GetChild(NodeType.Shape, 0, true); Assert.AreEqual(300.0d, imageShape.Height, 0.1d); Assert.AreEqual(300.0d, imageShape.Width, 0.1d); Assert.AreEqual(0.0d, imageShape.Left); Assert.AreEqual(0.0d, imageShape.Top); Assert.AreEqual(WrapType.Inline, imageShape.WrapType); Assert.AreEqual(RelativeHorizontalPosition.Column, imageShape.RelativeHorizontalPosition); Assert.AreEqual(RelativeVerticalPosition.Paragraph, imageShape.RelativeVerticalPosition); TestUtil.VerifyImageInShape(400, 400, ImageType.Png, imageShape); Assert.AreEqual(300.0d, imageShape.ImageData.ImageSize.HeightPoints, 0.1d); Assert.AreEqual(300.0d, imageShape.ImageData.ImageSize.WidthPoints, 0.1d); imageShape = (Shape)doc.GetChild(NodeType.Shape, 1, true); Assert.AreEqual(108.0d, imageShape.Height); Assert.AreEqual(187.5d, imageShape.Width); Assert.AreEqual(0.0d, imageShape.Left); Assert.AreEqual(0.0d, imageShape.Top); Assert.AreEqual(WrapType.Inline, imageShape.WrapType); Assert.AreEqual(RelativeHorizontalPosition.Column, imageShape.RelativeHorizontalPosition); Assert.AreEqual(RelativeVerticalPosition.Paragraph, imageShape.RelativeVerticalPosition); TestUtil.VerifyImageInShape(400, 400, ImageType.Png, imageShape); Assert.AreEqual(300.0d, imageShape.ImageData.ImageSize.HeightPoints, 0.1d); Assert.AreEqual(300.0d, imageShape.ImageData.ImageSize.WidthPoints, 0.1d); imageShape = (Shape)doc.GetChild(NodeType.Shape, 2, true); Assert.AreEqual(100.0d, imageShape.Height); Assert.AreEqual(200.0d, imageShape.Width); Assert.AreEqual(100.0d, imageShape.Left); Assert.AreEqual(100.0d, imageShape.Top); Assert.AreEqual(WrapType.Square, imageShape.WrapType); Assert.AreEqual(RelativeHorizontalPosition.Margin, imageShape.RelativeHorizontalPosition); Assert.AreEqual(RelativeVerticalPosition.Margin, imageShape.RelativeVerticalPosition); TestUtil.VerifyImageInShape(400, 400, ImageType.Png, imageShape); Assert.AreEqual(300.0d, imageShape.ImageData.ImageSize.HeightPoints, 0.1d); Assert.AreEqual(300.0d, imageShape.ImageData.ImageSize.WidthPoints, 0.1d); }
private const int ThumbnailSizeHeight = 240; // height public static void ResizeImg(object data) { var(path, fileName) = (ValueTuple <string, string>)data; if (!Directory.Exists(path + "/thumbnails")) { Directory.CreateDirectory(Path.Combine(path, "thumbnails")); } if (!Directory.Exists(path + "/details")) { Directory.CreateDirectory(Path.Combine(path, "details")); } const int quality = 75; using var input = File.OpenRead(Path.Combine(path, fileName)); using var inputStream = new SKManagedStream(input); using var imgStream = new SKManagedStream(input); using var skData = SKData.Create(input); using var codec = SKCodec.Create(skData); using var originalBitmap = SKBitmap.Decode(codec); var original = AutoOrient(originalBitmap, codec.EncodedOrigin); /* * THUMBNAIL */ int thumbWidth; int thumbHeight; if (original.Height > original.Width) { // Thumbnail thumbWidth = Convert.ToInt32(original.Width * ThumbnailSizeHeight / (double)original.Height); thumbHeight = ThumbnailSizeHeight; } else { // Thumbnail thumbWidth = ThumbnailSizeWidth; thumbHeight = Convert.ToInt32(original.Height * ThumbnailSizeWidth / (double)original.Width); } // Thumbnail var thumbPath = Path.Combine(path, "thumbnails"); using var resizedToThumb = original.Resize(new SKImageInfo(thumbWidth, thumbHeight), SKFilterQuality.Medium); if (resizedToThumb == null) { return; } using var thumbImage = SKImage.FromBitmap(resizedToThumb); using var output = File.OpenWrite(Path.Combine(thumbPath, fileName)); thumbImage.Encode(SKEncodedImageFormat.Jpeg, quality).SaveTo(output); /* * DETAIL */ int detailWidth; int detailHeight; if (original.Height > original.Width) { // Detail detailWidth = Convert.ToInt32(original.Width * DetailSizeHeight / (double)original.Height); detailHeight = DetailSizeHeight; } else { // Detail detailWidth = DetailSizeWidth; detailHeight = Convert.ToInt32(original.Height * DetailSizeWidth / (double)original.Width); } // If image is small than define size if (original.Height < DetailSizeHeight && original.Width < DetailSizeWidth) { detailWidth = original.Width; detailHeight = original.Height; } // Detail var detailPath = Path.Combine(path, "details"); using var resizedToDetail = original.Resize(new SKImageInfo(detailWidth, detailHeight), SKFilterQuality.Medium); if (resizedToDetail == null) { return; } using var detailImage = SKImage.FromBitmap(resizedToDetail); using var detailOutput = File.OpenWrite(Path.Combine(detailPath, fileName)); detailImage.Encode(SKEncodedImageFormat.Jpeg, quality).SaveTo(detailOutput); }
public async Task <Tuple <Stream, LoadingResult, ImageInformation> > Resolve(string identifier, TaskParameter parameters, CancellationToken token) { ImageSource source = parameters.Source; if (!string.IsNullOrWhiteSpace(parameters.LoadingPlaceholderPath) && parameters.LoadingPlaceholderPath == identifier) { source = parameters.LoadingPlaceholderSource; } else if (!string.IsNullOrWhiteSpace(parameters.ErrorPlaceholderPath) && parameters.ErrorPlaceholderPath == identifier) { source = parameters.ErrorPlaceholderSource; } var resolvedData = await(Configuration.DataResolverFactory ?? new DataResolverFactory()) .GetResolver(identifier, source, parameters, Configuration) .Resolve(identifier, parameters, token).ConfigureAwait(false); if (resolvedData?.Item1 == null) { throw new FileNotFoundException(identifier); } var svg = new SKSvg() { ThrowOnUnsupportedElement = false, }; SKPicture picture; using (var svgStream = resolvedData.Item1) { picture = svg.Load(resolvedData?.Item1); } float sizeX = 0; float sizeY = 0; if (VectorWidth == 0 && VectorHeight == 0) { if (picture.CullRect.Width > 0) { sizeX = picture.CullRect.Width; } else { sizeX = 300; } if (picture.CullRect.Height > 0) { sizeY = picture.CullRect.Height; } else { sizeY = 300; } } else if (VectorWidth > 0 && VectorHeight > 0) { sizeX = VectorWidth; sizeY = VectorHeight; } else if (VectorWidth > 0) { sizeX = VectorWidth; sizeY = (VectorWidth / picture.CullRect.Width) * picture.CullRect.Height; } else { sizeX = (VectorHeight / picture.CullRect.Height) * picture.CullRect.Width; sizeY = VectorHeight; } using (var bitmap = new SKBitmap((int)sizeX, (int)sizeY)) using (var canvas = new SKCanvas(bitmap)) using (var paint = new SKPaint()) { canvas.Clear(SKColors.Transparent); float scaleX = sizeX / picture.CullRect.Width; float scaleY = sizeY / picture.CullRect.Height; var matrix = SKMatrix.MakeScale(scaleX, scaleY); canvas.DrawPicture(picture, ref matrix, paint); canvas.Flush(); using (var image = SKImage.FromBitmap(bitmap)) using (var data = image.Encode(SKImageEncodeFormat.Png, 80)) { var stream = new MemoryStream(); data.SaveTo(stream); stream.Position = 0; //var stream = data?.AsStream(); return(new Tuple <Stream, LoadingResult, ImageInformation>(stream, resolvedData.Item2, resolvedData.Item3)); } } }
private async void btnSend_Clicked(object sender, EventArgs e) { try { await SetIndicator(true); if (Settings.NoSetupDefined) { throw new Exception("Go to configuration and define settings"); } using (SKImage image = SKImage.FromBitmap(saveBitmap)) { SKData data = image.Encode(); DateTime dt = DateTime.Now; int year = dt.Year; int month = dt.Month; int day = dt.Day; int hour = dt.Hour; int minute = dt.Minute; int second = dt.Second; int milisecond = dt.Millisecond; string filename = String.Format("FingerPaint-{0:D4}{1:D2}{2:D2}-{3:D2}{4:D2}{5:D2}{6:D3}.png", year, month, day, hour, minute, second, milisecond); string jsonfilename = String.Format("FingerPaint-{0:D4}{1:D2}{2:D2}-{3:D2}{4:D2}{5:D2}{6:D3}.json", year, month, day, hour, minute, second, milisecond); int counter = 1; string jsonStrokes = string.Empty; jsonStrokes = "{" + "\"version\": 1, " + "\"language\": \"en-US\", " + "\"unit\": \"mm\", " + "\"strokes\": ["; //MOJE foreach (SKPath p in completedPaths) { string points = string.Empty; foreach (SKPoint pnt in p.Points) { points += pnt.X.ToString().Replace(",", ".") + "," + pnt.Y.ToString().Replace(",", ".") + ","; } points = points.Remove(points.Length - 1); jsonStrokes += "{" + "\"id\": " + counter + "," + "\"points\": \"" + points + "\"},"; counter++; } jsonStrokes = jsonStrokes.Remove(jsonStrokes.Length - 1); jsonStrokes += "]}"; IPhotoLibrary photoLibrary = DependencyService.Get <IPhotoLibrary>(); if (photoLibrary == null) { await UserDialogs.Instance.AlertAsync("Photo library is not acccessible", "Can't get photo library"); } else { bool result = await photoLibrary.SavePhotoAsync(data.ToArray(), "FingerPaint", filename); if (!result) { await UserDialogs.Instance.AlertAsync("Paint could not be saved", "Problem during saving image"); } bool jsonResult = await photoLibrary.SaveJsonAsync(jsonStrokes, "FingerPaint", jsonfilename); if (!jsonResult) { await UserDialogs.Instance.AlertAsync("Couldn't save strokes to file. Sorry!", "Problem saving strokes"); } //create request IAzureRecognition recognition = DependencyService.Get <IAzureRecognition>(); if (recognition != null) { string[] resultArr = recognition.GetOCR(jsonStrokes, Settings.EndpointSetting, Settings.KeyOcrSetting, Settings.LanguageSetting); if (resultArr != null && resultArr.Length >= 1) { string txtToSay = string.Empty; foreach (string t in resultArr) { txtToSay = txtToSay + t; } try { PromptResult pr = await UserDialogs.Instance.PromptAsync(new PromptConfig() { Title = "Text recognized, you may correct it. Increase media vol", CancelText = "Finish", OkText = "Say it", Message = txtToSay }); if (pr.Ok == true) { if (string.IsNullOrEmpty(pr.Text)) { await recognition.SayIT(txtToSay, Settings.KeySpeechSetting, Settings.RegionSetting, Settings.LanguageSetting); } else { await recognition.SayIT(pr.Text, Settings.KeySpeechSetting, Settings.RegionSetting, Settings.LanguageSetting); } } else { inProgressPaths.Clear(); completedPaths.Clear(); UpdateBitmap(); canvasView.InvalidateSurface(); } } catch (Exception exx) { await UserDialogs.Instance.AlertAsync(exx.Message, "Error parsing response from OCR/speech engine"); inProgressPaths.Clear(); completedPaths.Clear(); UpdateBitmap(); canvasView.InvalidateSurface(); } } else { await UserDialogs.Instance.AlertAsync("Paint doesn't contain any text", "Problem while getting strokes from image"); inProgressPaths.Clear(); completedPaths.Clear(); UpdateBitmap(); canvasView.InvalidateSurface(); } } else { await UserDialogs.Instance.AlertAsync("Can't get IAzureRecognition implementation", "Object not implemented"); } } } await SetIndicator(false); } catch (Exception ex) { await SetIndicator(false); await UserDialogs.Instance.AlertAsync(ex.Message, "Exception during execution"); } }
public void Draw(TetrisField Source, TetrisFieldDrawSkiaParameters parms, IStateOwner pState, SKCanvas g, SKRect Bounds) { Stopwatch sw = new Stopwatch(); sw.Start(); //first how big is each block? float BlockWidth = Bounds.Width / parms.COLCOUNT; float BlockHeight = Bounds.Height / (parms.VISIBLEROWS); //remember, we don't draw the top two rows- we start the drawing at row index 2, skipping 0 and 1 when drawing. lock (Source) { if (parms.FieldBitmap == null || !parms.LastFieldSave.Equals(Bounds) || Source.HasChanged) { Debug.Print("Beginning Field Paint:" + sw.Elapsed.ToString()); SKImageInfo info = new SKImageInfo((int)Bounds.Width, (int)Bounds.Height, SKColorType.Bgra8888); //Note: what we want to do here is actually allocate the field bitmap using a Surface texture. doing it this way paints more slowly, //because it is backed by a bitmap and drawn largely by the CPU. //(nmote using the surface we can retrieve an image snapshot). if (bitmapMode) { using (SKBitmap BuildField = new SKBitmap(info, SKBitmapAllocFlags.None)) { using (SKCanvas gfield = new SKCanvas(BuildField)) { gfield.Clear(SKColors.Transparent); hadAnimated = DrawFieldContents(pState, Source, parms, gfield, Bounds, false); if (parms.FieldBitmap != null) { parms.FieldBitmap.Dispose(); } parms.FieldBitmap = SKImage.FromBitmap(BuildField); } } } else { using (var CreateContext = GRContext.Create(GRBackend.OpenGL, GlobalResources.OpenGLInterface)) { SKCanvas gfield = null; if (FieldSurface == null) { FieldSurface = SKSurface.Create(CreateContext, GlobalResources.CreateRenderTarget((int)Bounds.Width, (int)Bounds.Height), GRSurfaceOrigin.BottomLeft, GlobalResources.DefaultColorType); } var FieldCanvas = FieldSurface.Canvas; FieldCanvas.Flush(); gfield = FieldCanvas; gfield.Clear(SKColors.Transparent); hadAnimated = DrawFieldContents(pState, Source, parms, gfield, Bounds, false); if (parms.FieldBitmap != null) { parms.FieldBitmap.Dispose(); } parms.FieldBitmap = FieldSurface.Snapshot(); } } parms.LastFieldSave = Bounds; Source.HasChanged = false; Debug.Print("Finished Field Paint:" + sw.Elapsed.ToString()); } } Debug.Print("Drawing Field Bitmap" + sw.Elapsed.ToString()); g.DrawImage(parms.FieldBitmap, new SKPoint(0, 0)); //g.DrawBitmap(parms.FieldBitmap,new SKPoint(0,0)); Debug.Print("Field Bitmap finished" + sw.Elapsed.ToString()); if (hadAnimated) { Debug.Print("Animated Field blocks found"); DrawFieldContents(pState, Source, parms, g, Bounds, true); } var activegroups = Source.GetActiveBlockGroups(); Debug.Print("Painting Active Groups:" + sw.Elapsed.ToString()); lock (activegroups) { foreach (Nomino bg in activegroups) { int BaseXPos = bg.X; int BaseYPos = bg.Y; const float RotationTime = 150; double useAngle = 0; TimeSpan tsRotate = DateTime.Now - bg.GetLastRotation(); if (tsRotate.TotalMilliseconds > 0 && tsRotate.TotalMilliseconds < RotationTime) { if (!bg.LastRotateCCW) { useAngle = -90 + ((tsRotate.TotalMilliseconds / RotationTime) * 90); } else { useAngle = 90 - ((tsRotate.TotalMilliseconds / RotationTime) * 90); } } var translation = bg.GetHeightTranslation(pState, BlockHeight); float BlockPercent = translation / BlockHeight; float CalcValue = BlockPercent + (float)bg.Y; if (CalcValue > bg.HighestHeightValue) { bg.HighestHeightValue = CalcValue; } else { translation = (bg.HighestHeightValue - (float)bg.Y) * BlockHeight; } PointF doTranslate = new PointF(0, translation); if (!pState.Settings.std.SmoothFall) { doTranslate = new PointF(0, 0); } //if (Settings.SmoothFall) g.TranslateTransform(doTranslate.X, -BlockHeight + doTranslate.Y); if (pState.Settings.std.SmoothFall) { g.Translate(doTranslate.X, -BlockHeight + doTranslate.Y); } if (useAngle != 0 && pState.Settings.std.SmoothRotate) { int MaxXBlock = (from p in bg select p.X).Max(); int MaxYBlock = (from p in bg select p.Y).Max(); int MinXBlock = (from p in bg select p.X).Min(); int MinYBlock = (from p in bg select p.Y).Min(); int BlocksWidth = MaxXBlock - MinXBlock + 1; int BlocksHeight = MaxYBlock - MinYBlock + 1; PointF UsePosition = new PointF((bg.X + MinXBlock) * BlockWidth, (bg.Y - parms.HIDDENROWS + MinYBlock) * BlockHeight); SizeF tetronimosize = new Size((int)BlockWidth * (BlocksWidth), (int)BlockHeight * (BlocksHeight)); PointF useCenter = new PointF(UsePosition.X + tetronimosize.Width / 2, UsePosition.Y + tetronimosize.Height / 2); g.RotateDegrees((float)useAngle, useCenter.X, useCenter.Y); //g.TranslateTransform(useCenter.X, useCenter.Y); //g.RotateTransform((float)useAngle); //g.TranslateTransform(-useCenter.X, -useCenter.Y); } foreach (NominoElement bge in bg) { int DrawX = BaseXPos + bge.X; int DrawY = BaseYPos + bge.Y - parms.HIDDENROWS; if (DrawX >= 0 && DrawY >= 0 && DrawX < parms.COLCOUNT && DrawY < parms.ROWCOUNT) { float DrawXPx = DrawX * BlockWidth; float DrawYPx = DrawY * BlockHeight; SKRect BlockBounds = new SKRect(DrawXPx, DrawYPx, DrawXPx + BlockWidth, DrawYPx + BlockHeight); TetrisBlockDrawParameters tbd = new TetrisBlockDrawSkiaParameters(g, BlockBounds, bg, pState.Settings); RenderingProvider.Static.DrawElement(pState, g, bge.Block, tbd); } } g.ResetMatrix(); if (!bg.NoGhost) { var GrabGhost = Source.GetGhostDrop(pState, bg, out int dl); if (GrabGhost != null) { foreach (var iterateblock in bg) { float drawGhostX = BlockWidth * (GrabGhost.X + iterateblock.X); float drawGhostY = BlockHeight * (GrabGhost.Y + iterateblock.Y - 2); SKRect BlockBounds = new SKRect(drawGhostX, drawGhostY, drawGhostX + BlockWidth, drawGhostY + BlockHeight); TetrisBlockDrawSkiaParameters tbd = new TetrisBlockDrawSkiaParameters(g, BlockBounds, GrabGhost, pState.Settings); //ImageAttributes Shade = new ImageAttributes(); //SKColorMatrices.GetFader //Shade.SetColorMatrix(ColorMatrices.GetFader(0.5f)); //tbd.ApplyAttributes = Shade; //tbd.OverrideBrush = GhostBrush; tbd.ColorFilter = SKColorMatrices.GetFader(0.5f); var GetHandler = RenderingProvider.Static.GetHandler(typeof(SKCanvas), iterateblock.Block.GetType(), typeof(TetrisBlockDrawSkiaParameters)); GetHandler.Render(pState, tbd.g, iterateblock.Block, tbd); //iterateblock.Block.DrawBlock(tbd); } } } } } Debug.Print("Painting Active Groups Finished:" + sw.Elapsed.ToString()); }
public void Update(PageChatRender pageChatRender) { try { this.Width = Int32.Parse(pageChatRender.textWidth.Text) + 10; this.Height = Int32.Parse(pageChatRender.textHeight.Text) + 38; imgPreview.Height = Int32.Parse(pageChatRender.textHeight.Text); imgPreview.Width = Int32.Parse(pageChatRender.textWidth.Text); PreviewData previewData = JsonConvert.DeserializeObject <PreviewData>(File.ReadAllText("preview_data.json")); BlockingCollection <TwitchCommentPreview> finalComments = new BlockingCollection <TwitchCommentPreview>(); SKBitmap previewBitmap = new SKBitmap((int)this.Width, (int)imgPreview.Height); SKColor backgroundColor = new SKColor(pageChatRender.colorBackground.SelectedColor.Value.R, pageChatRender.colorBackground.SelectedColor.Value.G, pageChatRender.colorBackground.SelectedColor.Value.B); SKColor messageColor = new SKColor(pageChatRender.colorFont.SelectedColor.Value.R, pageChatRender.colorFont.SelectedColor.Value.G, pageChatRender.colorFont.SelectedColor.Value.B); RenderOptions renderOptions = new RenderOptions(pageChatRender.textJson.Text, "", backgroundColor, Int32.Parse(pageChatRender.textHeight.Text), Int32.Parse(pageChatRender.textWidth.Text), (bool)pageChatRender.checkBTTV.IsChecked, (bool)pageChatRender.checkFFZ.IsChecked, (bool)pageChatRender.checkOutline.IsChecked, (string)pageChatRender.comboFont.SelectedItem, Double.Parse(pageChatRender.textFontSize.Text), Double.Parse(pageChatRender.textUpdateTime.Text), (bool)pageChatRender.checkTimestamp.IsChecked, messageColor, Int32.Parse(pageChatRender.textFramerate.Text), Settings.Default.FfmpegInputArgs, Settings.Default.FfmpegOutputArgs); Size canvasSize = new Size(renderOptions.chat_width, renderOptions.text_height); SKPaint nameFont = new SKPaint() { Typeface = SKTypeface.FromFamilyName(renderOptions.font, SKFontStyle.Bold), LcdRenderText = true, SubpixelText = true, TextSize = (float)renderOptions.font_size, IsAntialias = true, HintingLevel = SKPaintHinting.Full, FilterQuality = SKFilterQuality.High }; SKPaint messageFont = new SKPaint() { Typeface = SKTypeface.FromFamilyName(renderOptions.font, SKFontStyle.Normal), LcdRenderText = true, SubpixelText = true, TextSize = (float)renderOptions.font_size, IsAntialias = true, HintingLevel = SKPaintHinting.Full, FilterQuality = SKFilterQuality.High, Color = renderOptions.message_color }; List <ThirdPartyEmote> thirdPartyEmotes = new List <ThirdPartyEmote>(); Dictionary <string, SKBitmap> chatEmotes = new Dictionary <string, SKBitmap>(); Dictionary <string, SKBitmap> emojiCache = new Dictionary <string, SKBitmap>(); string emojiRegex = "[#*0-9]\uFE0F\u20E3|[\u00A9\u00AE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23E9-\u23F3\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB-\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618]|\u261D(?:\uD83C[\uDFFB-\uDFFF])?|[\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u2648-\u2653\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E\u267F\u2692-\u2697\u2699\u269B\u269C\u26A0\u26A1\u26AA\u26AB\u26B0\u26B1\u26BD\u26BE\u26C4\u26C5\u26C8\u26CE\u26CF\u26D1\u26D3\u26D4\u26E9\u26EA\u26F0-\u26F5\u26F7\u26F8]|\u26F9(?:\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F)?|\uFE0F\u200D[\u2640\u2642]\uFE0F)?|[\u26FA\u26FD\u2702\u2705\u2708\u2709]|[\u270A-\u270D](?:\uD83C[\uDFFB-\uDFFF])?|[\u270F\u2712\u2714\u2716\u271D\u2721\u2728\u2733\u2734\u2744\u2747\u274C\u274E\u2753-\u2755\u2757\u2763\u2764\u2795-\u2797\u27A1\u27B0\u27BF\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B50\u2B55\u3030\u303D\u3297\u3299]|\uD83C(?:[\uDC04\uDCCF\uDD70\uDD71\uDD7E\uDD7F\uDD8E\uDD91-\uDD9A]|\uDDE6\uD83C[\uDDE8-\uDDEC\uDDEE\uDDF1\uDDF2\uDDF4\uDDF6-\uDDFA\uDDFC\uDDFD\uDDFF]|\uDDE7\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEF\uDDF1-\uDDF4\uDDF6-\uDDF9\uDDFB\uDDFC\uDDFE\uDDFF]|\uDDE8\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDEE\uDDF0-\uDDF5\uDDF7\uDDFA-\uDDFF]|\uDDE9\uD83C[\uDDEA\uDDEC\uDDEF\uDDF0\uDDF2\uDDF4\uDDFF]|\uDDEA\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDED\uDDF7-\uDDFA]|\uDDEB\uD83C[\uDDEE-\uDDF0\uDDF2\uDDF4\uDDF7]|\uDDEC\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEE\uDDF1-\uDDF3\uDDF5-\uDDFA\uDDFC\uDDFE]|\uDDED\uD83C[\uDDF0\uDDF2\uDDF3\uDDF7\uDDF9\uDDFA]|\uDDEE\uD83C[\uDDE8-\uDDEA\uDDF1-\uDDF4\uDDF6-\uDDF9]|\uDDEF\uD83C[\uDDEA\uDDF2\uDDF4\uDDF5]|\uDDF0\uD83C[\uDDEA\uDDEC-\uDDEE\uDDF2\uDDF3\uDDF5\uDDF7\uDDFC\uDDFE\uDDFF]|\uDDF1\uD83C[\uDDE6-\uDDE8\uDDEE\uDDF0\uDDF7-\uDDFB\uDDFE]|\uDDF2\uD83C[\uDDE6\uDDE8-\uDDED\uDDF0-\uDDFF]|\uDDF3\uD83C[\uDDE6\uDDE8\uDDEA-\uDDEC\uDDEE\uDDF1\uDDF4\uDDF5\uDDF7\uDDFA\uDDFF]|\uDDF4\uD83C\uDDF2|\uDDF5\uD83C[\uDDE6\uDDEA-\uDDED\uDDF0-\uDDF3\uDDF7-\uDDF9\uDDFC\uDDFE]|\uDDF6\uD83C\uDDE6|\uDDF7\uD83C[\uDDEA\uDDF4\uDDF8\uDDFA\uDDFC]|\uDDF8\uD83C[\uDDE6-\uDDEA\uDDEC-\uDDF4\uDDF7-\uDDF9\uDDFB\uDDFD-\uDDFF]|\uDDF9\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDED\uDDEF-\uDDF4\uDDF7\uDDF9\uDDFB\uDDFC\uDDFF]|\uDDFA\uD83C[\uDDE6\uDDEC\uDDF2\uDDF3\uDDF8\uDDFE\uDDFF]|\uDDFB\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDEE\uDDF3\uDDFA]|\uDDFC\uD83C[\uDDEB\uDDF8]|\uDDFD\uD83C\uDDF0|\uDDFE\uD83C[\uDDEA\uDDF9]|\uDDFF\uD83C[\uDDE6\uDDF2\uDDFC]|[\uDE01\uDE02\uDE1A\uDE2F\uDE32-\uDE3A\uDE50\uDE51\uDF00-\uDF21\uDF24-\uDF84]|\uDF85(?:\uD83C[\uDFFB-\uDFFF])?|[\uDF86-\uDF93\uDF96\uDF97\uDF99-\uDF9B\uDF9E-\uDFC1]|\uDFC2(?:\uD83C[\uDFFB-\uDFFF])?|[\uDFC3\uDFC4](?:\u200D[\u2640\u2642]\uFE0F|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F)?)?|[\uDFC5\uDFC6]|\uDFC7(?:\uD83C[\uDFFB-\uDFFF])?|[\uDFC8\uDFC9]|\uDFCA(?:\u200D[\u2640\u2642]\uFE0F|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F)?)?|[\uDFCB\uDFCC](?:\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F)?|\uFE0F\u200D[\u2640\u2642]\uFE0F)?|[\uDFCD-\uDFF0]|\uDFF3(?:\uFE0F\u200D\uD83C\uDF08)?|\uDFF4(?:\u200D\u2620\uFE0F|\uDB40\uDC67\uDB40\uDC62\uDB40(?:\uDC65\uDB40\uDC6E\uDB40\uDC67|\uDC73\uDB40\uDC63\uDB40\uDC74|\uDC77\uDB40\uDC6C\uDB40\uDC73)\uDB40\uDC7F)?|[\uDFF5\uDFF7-\uDFFF])|\uD83D(?:[\uDC00-\uDC14]|\uDC15(?:\u200D\uD83E\uDDBA)?|[\uDC16-\uDC40]|\uDC41(?:\uFE0F\u200D\uD83D\uDDE8\uFE0F)?|[\uDC42\uDC43](?:\uD83C[\uDFFB-\uDFFF])?|[\uDC44\uDC45]|[\uDC46-\uDC50](?:\uD83C[\uDFFB-\uDFFF])?|[\uDC51-\uDC65]|[\uDC66\uDC67](?:\uD83C[\uDFFB-\uDFFF])?|\uDC68(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F|\u2764\uFE0F\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?|[\uDC68\uDC69]\u200D\uD83D(?:\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?)|[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92])|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD]))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:\uDD1D\u200D\uD83D\uDC68\uD83C\uDFFB|[\uDDAF-\uDDB3\uDDBC\uDDBD])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB\uDFFC]|[\uDDAF-\uDDB3\uDDBC\uDDBD])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB-\uDFFD]|[\uDDAF-\uDDB3\uDDBC\uDDBD])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB-\uDFFE]|[\uDDAF-\uDDB3\uDDBC\uDDBD])))?))?|\uDC69(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F|\u2764\uFE0F\u200D\uD83D(?:\uDC8B\u200D\uD83D)?[\uDC68\uDC69]|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?|\uDC69\u200D\uD83D(?:\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?)|[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92])|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFC-\uDFFF]|[\uDDAF-\uDDB3\uDDBC\uDDBD])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:\uDD1D\u200D\uD83D(?:\uDC68\uD83C[\uDFFB\uDFFD-\uDFFF]|\uDC69\uD83C\uDFFB)|[\uDDAF-\uDDB3\uDDBC\uDDBD])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:\uDD1D\u200D\uD83D(?:\uDC68\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF]|\uDC69\uD83C[\uDFFB\uDFFC])|[\uDDAF-\uDDB3\uDDBC\uDDBD])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:\uDD1D\u200D\uD83D(?:\uDC68\uD83C[\uDFFB-\uDFFD\uDFFF]|\uDC69\uD83C[\uDFFB-\uDFFD])|[\uDDAF-\uDDB3\uDDBC\uDDBD])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFE]|[\uDDAF-\uDDB3\uDDBC\uDDBD])))?))?|\uDC6A|[\uDC6B-\uDC6D](?:\uD83C[\uDFFB-\uDFFF])?|\uDC6E(?:\u200D[\u2640\u2642]\uFE0F|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F)?)?|\uDC6F(?:\u200D[\u2640\u2642]\uFE0F)?|\uDC70(?:\uD83C[\uDFFB-\uDFFF])?|\uDC71(?:\u200D[\u2640\u2642]\uFE0F|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F)?)?|\uDC72(?:\uD83C[\uDFFB-\uDFFF])?|\uDC73(?:\u200D[\u2640\u2642]\uFE0F|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F)?)?|[\uDC74-\uDC76](?:\uD83C[\uDFFB-\uDFFF])?|\uDC77(?:\u200D[\u2640\u2642]\uFE0F|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F)?)?|\uDC78(?:\uD83C[\uDFFB-\uDFFF])?|[\uDC79-\uDC7B]|\uDC7C(?:\uD83C[\uDFFB-\uDFFF])?|[\uDC7D-\uDC80]|[\uDC81\uDC82](?:\u200D[\u2640\u2642]\uFE0F|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F)?)?|\uDC83(?:\uD83C[\uDFFB-\uDFFF])?|\uDC84|\uDC85(?:\uD83C[\uDFFB-\uDFFF])?|[\uDC86\uDC87](?:\u200D[\u2640\u2642]\uFE0F|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F)?)?|[\uDC88-\uDCA9]|\uDCAA(?:\uD83C[\uDFFB-\uDFFF])?|[\uDCAB-\uDCFD\uDCFF-\uDD3D\uDD49-\uDD4E\uDD50-\uDD67\uDD6F\uDD70\uDD73]|\uDD74(?:\uD83C[\uDFFB-\uDFFF])?|\uDD75(?:\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F)?|\uFE0F\u200D[\u2640\u2642]\uFE0F)?|[\uDD76-\uDD79]|\uDD7A(?:\uD83C[\uDFFB-\uDFFF])?|[\uDD87\uDD8A-\uDD8D]|[\uDD90\uDD95\uDD96](?:\uD83C[\uDFFB-\uDFFF])?|[\uDDA4\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA-\uDE44]|[\uDE45-\uDE47](?:\u200D[\u2640\u2642]\uFE0F|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F)?)?|[\uDE48-\uDE4A]|\uDE4B(?:\u200D[\u2640\u2642]\uFE0F|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F)?)?|\uDE4C(?:\uD83C[\uDFFB-\uDFFF])?|[\uDE4D\uDE4E](?:\u200D[\u2640\u2642]\uFE0F|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F)?)?|\uDE4F(?:\uD83C[\uDFFB-\uDFFF])?|[\uDE80-\uDEA2]|\uDEA3(?:\u200D[\u2640\u2642]\uFE0F|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F)?)?|[\uDEA4-\uDEB3]|[\uDEB4-\uDEB6](?:\u200D[\u2640\u2642]\uFE0F|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F)?)?|[\uDEB7-\uDEBF]|\uDEC0(?:\uD83C[\uDFFB-\uDFFF])?|[\uDEC1-\uDEC5\uDECB]|\uDECC(?:\uD83C[\uDFFB-\uDFFF])?|[\uDECD-\uDED2\uDED5\uDEE0-\uDEE5\uDEE9\uDEEB\uDEEC\uDEF0\uDEF3-\uDEFA\uDFE0-\uDFEB])|\uD83E(?:[\uDD0D\uDD0E]|\uDD0F(?:\uD83C[\uDFFB-\uDFFF])?|[\uDD10-\uDD17]|[\uDD18-\uDD1C](?:\uD83C[\uDFFB-\uDFFF])?|\uDD1D|[\uDD1E\uDD1F](?:\uD83C[\uDFFB-\uDFFF])?|[\uDD20-\uDD25]|\uDD26(?:\u200D[\u2640\u2642]\uFE0F|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F)?)?|[\uDD27-\uDD2F]|[\uDD30-\uDD36](?:\uD83C[\uDFFB-\uDFFF])?|\uDD37(?:\u200D[\u2640\u2642]\uFE0F|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F)?)?|[\uDD38\uDD39](?:\u200D[\u2640\u2642]\uFE0F|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F)?)?|\uDD3A|\uDD3C(?:\u200D[\u2640\u2642]\uFE0F)?|[\uDD3D\uDD3E](?:\u200D[\u2640\u2642]\uFE0F|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F)?)?|[\uDD3F-\uDD45\uDD47-\uDD71\uDD73-\uDD76\uDD7A-\uDDA2\uDDA5-\uDDAA\uDDAE-\uDDB4]|[\uDDB5\uDDB6](?:\uD83C[\uDFFB-\uDFFF])?|\uDDB7|[\uDDB8\uDDB9](?:\u200D[\u2640\u2642]\uFE0F|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F)?)?|\uDDBA|\uDDBB(?:\uD83C[\uDFFB-\uDFFF])?|[\uDDBC-\uDDCA]|[\uDDCD-\uDDCF](?:\u200D[\u2640\u2642]\uFE0F|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F)?)?|\uDDD0|\uDDD1(?:\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1|\uD83C(?:\uDFFB(?:\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1\uD83C\uDFFB)?|\uDFFC(?:\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB\uDFFC])?|\uDFFD(?:\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFD])?|\uDFFE(?:\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFE])?|\uDFFF(?:\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])?))?|[\uDDD2-\uDDD5](?:\uD83C[\uDFFB-\uDFFF])?|\uDDD6(?:\u200D[\u2640\u2642]\uFE0F|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F)?)?|[\uDDD7-\uDDDD](?:\u200D[\u2640\u2642]\uFE0F|\uD83C[\uDFFB-\uDFFF](?:\u200D[\u2640\u2642]\uFE0F)?)?|[\uDDDE\uDDDF](?:\u200D[\u2640\u2642]\uFE0F)?|[\uDDE0-\uDDFF\uDE70-\uDE73\uDE78-\uDE7A\uDE80-\uDE82\uDE90-\uDE95])"; using (SKCanvas previewCanvas = new SKCanvas(previewBitmap)) { previewCanvas.Clear(backgroundColor); foreach (PreviewEmote previewDataEmote in previewData.emotes) { byte[] imageBytes = Convert.FromBase64String(previewDataEmote.image); SKBitmap emoteBitmap = SKBitmap.Decode(imageBytes); SKCodec emoteCodec; using (MemoryStream ms = new MemoryStream(imageBytes)) emoteCodec = SKCodec.Create(ms); ThirdPartyEmote emote = new ThirdPartyEmote(new List <SKBitmap>() { emoteBitmap }, emoteCodec, previewDataEmote.name, ".png", "0", 1); thirdPartyEmotes.Add(emote); } foreach (PreviewComment previewComment in previewData.comments) { int default_x = 2; Point drawPos = new Point(default_x, 0); string userName = previewComment.name; SKColor userColor = new SKColor(Convert.ToByte(previewComment.color.Substring(0, 2), 16), Convert.ToByte(previewComment.color.Substring(2, 2), 16), Convert.ToByte(previewComment.color.Substring(4, 2), 16)); List <SKBitmap> imageList = new List <SKBitmap>(); SKBitmap sectionImage = new SKBitmap((int)canvasSize.Width, (int)canvasSize.Height); List <GifEmote> currentGifEmotes = new List <GifEmote>(); List <SKBitmap> emoteList = new List <SKBitmap>(); List <CheerEmote> cheerEmotes = new List <CheerEmote>(); List <SKRect> emotePositionList = new List <SKRect>(); new SKCanvas(sectionImage).Clear(renderOptions.background_color); Comment comment = new Comment(); comment.message = new Message(); Fragment msg = new Fragment(); msg.text = previewComment.message; comment.message.fragments = new List <Fragment>(); comment.message.fragments.Add(msg); if (renderOptions.chat_timestamp) { sectionImage = pageChatRender.DrawTimestamp(sectionImage, imageList, messageFont, renderOptions, comment, canvasSize, ref drawPos, ref default_x); } if (previewComment.badges != null) { sectionImage = DrawBadges(sectionImage, imageList, renderOptions, canvasSize, ref drawPos, previewComment); } sectionImage = pageChatRender.DrawUsername(sectionImage, imageList, renderOptions, nameFont, userName, userColor, canvasSize, ref drawPos); sectionImage = pageChatRender.DrawMessage(sectionImage, imageList, renderOptions, currentGifEmotes, messageFont, emojiCache, chatEmotes, thirdPartyEmotes, cheerEmotes, comment, canvasSize, ref drawPos, emojiRegex, ref default_x, emoteList, emotePositionList); int finalHeight = 0; foreach (var img in imageList) { finalHeight += img.Height; } SKBitmap finalImage = new SKBitmap((int)canvasSize.Width, finalHeight); SKCanvas finalImageCanvas = new SKCanvas(finalImage); finalHeight = 0; foreach (var img in imageList) { finalImageCanvas.DrawBitmap(img, 0, finalHeight); finalHeight += img.Height; img.Dispose(); } finalComments.Add(new TwitchCommentPreview(finalImage, Double.Parse(comment.content_offset_seconds.ToString()), currentGifEmotes, emoteList, emotePositionList)); } int y = 0; int tempHeight = 0; foreach (TwitchCommentPreview twitchCommentPreview in finalComments) { tempHeight += twitchCommentPreview.section.Height; } SKBitmap tempBitmap = new SKBitmap((int)this.Width, tempHeight); using (SKCanvas tempCanvas = new SKCanvas(tempBitmap)) { foreach (TwitchCommentPreview twitchCommentPreview in finalComments) { tempCanvas.DrawBitmap(twitchCommentPreview.section, 0, y, imagePaint); for (int i = 0; i < twitchCommentPreview.normalEmotes.Count; i++) { SKRect refrenceRect = twitchCommentPreview.normalEmotesPositions[i]; tempCanvas.DrawBitmap(twitchCommentPreview.normalEmotes[i], new SKRect(refrenceRect.Left, refrenceRect.Top + y, refrenceRect.Right, refrenceRect.Bottom + y), imagePaint); } y += twitchCommentPreview.section.Height; } } previewCanvas.DrawBitmap(tempBitmap, 0, previewBitmap.Height - tempBitmap.Height); } using (var stream = new MemoryStream()) { SKImage.FromBitmap(previewBitmap).Encode(SKEncodedImageFormat.Png, 100).SaveTo(stream); var bitmap = new BitmapImage(); bitmap.BeginInit(); bitmap.StreamSource = stream; bitmap.CacheOption = BitmapCacheOption.OnLoad; bitmap.EndInit(); bitmap.Freeze(); imgPreview.Source = bitmap; } } catch { try { this.Width = 500; this.Height = 338; imgPreview.Width = 500; imgPreview.Height = 300; SKBitmap errorBitmap = new SKBitmap(500, 300); using (SKCanvas skCanvas = new SKCanvas(errorBitmap)) { skCanvas.DrawText("ERROR, UNABLE TO RENDER CHAT", 40, 150, new SKPaint() { Typeface = SKTypeface.FromFamilyName("Arial", SKFontStyle.Bold), TextSize = 18, IsAntialias = true, FilterQuality = SKFilterQuality.High }); SKBitmap peepo = SKBitmap.Decode(Application .GetResourceStream(new Uri("pack://application:,,,/Images/peepoSad.png")).Stream); skCanvas.DrawBitmap(peepo, 370, 132); } using (var stream = new MemoryStream()) { SKImage.FromBitmap(errorBitmap).Encode(SKEncodedImageFormat.Png, 100).SaveTo(stream); var bitmap = new BitmapImage(); bitmap.BeginInit(); bitmap.StreamSource = stream; bitmap.CacheOption = BitmapCacheOption.OnLoad; bitmap.EndInit(); bitmap.Freeze(); imgPreview.Source = bitmap; } } catch { } } }
public List <byte[]> Draw() { Logger.Info("Start drawing"); var images = new List <byte[]>(); var currentPage = 0; foreach (var page in this.pages) { var template = string.Empty; if (currentPage < this.templates.Count) { template = this.templates[currentPage]; } currentPage++; Logger.Debug($"Drawing page {currentPage} on {this.pages.Count}"); using (var bitmap = new SKBitmap(CanvanWidth, CanvasHeight)) using (var canvas = new SKCanvas(bitmap)) { canvas.DrawRect(0, 0, CanvanWidth, CanvasHeight, new SKPaint { Color = new SKColor(255, 255, 255) }); if (!string.IsNullOrWhiteSpace(template)) { var templateBitmap = SKBitmap.Decode($"{this.TemplateRoot}{template}.png"); canvas.DrawBitmap(templateBitmap, 0, 0); } var currentLayer = 0; foreach (var layer in page.Layers) { currentLayer++; Logger.Debug($"Drawing layer {currentLayer} on {page.Layers.Count}"); var currentStroke = 0; foreach (var stroke in layer.Strokes) { currentStroke++; Logger.Debug($"Drawing stroke {currentStroke} on {layer.Strokes.Count}"); for (var currentSegment = 0; currentSegment < stroke.Segments.Count; currentSegment++) { Logger.Debug($"Drawing segment {currentSegment} on {stroke.Segments.Count}"); if (currentSegment < stroke.Segments.Count - 1) { this.DrawSegment(stroke.Segments[currentSegment], stroke.Segments[currentSegment + 1], canvas); } } } } canvas.Flush(); var image = SKImage.FromBitmap(bitmap); var data = image.Encode(SKEncodedImageFormat.Png, 100); using (var stream = new MemoryStream()) { data.SaveTo(stream); images.Add(data.ToArray()); } } } return(images); }
public void Update(PageChatRender pageChatRender) { try { this.Width = Int32.Parse(pageChatRender.textWidth.Text) + 10; this.Height = Int32.Parse(pageChatRender.textHeight.Text) + 38; imgPreview.Height = Int32.Parse(pageChatRender.textHeight.Text); imgPreview.Width = Int32.Parse(pageChatRender.textWidth.Text); PreviewData previewData = JsonConvert.DeserializeObject<PreviewData>(File.ReadAllText("preview_data.json")); BlockingCollection<TwitchCommentPreview> finalComments = new BlockingCollection<TwitchCommentPreview>(); SKBitmap previewBitmap = new SKBitmap((int)this.Width, (int)imgPreview.Height); SKColor backgroundColor = new SKColor(pageChatRender.colorBackground.SelectedColor.Value.R, pageChatRender.colorBackground.SelectedColor.Value.G, pageChatRender.colorBackground.SelectedColor.Value.B); SKColor messageColor = new SKColor(pageChatRender.colorFont.SelectedColor.Value.R, pageChatRender.colorFont.SelectedColor.Value.G, pageChatRender.colorFont.SelectedColor.Value.B); ChatRenderOptions renderOptions = new ChatRenderOptions() { InputFile = pageChatRender.textJson.Text, OutputFile = "", BackgroundColor = backgroundColor, ChatHeight = Int32.Parse(pageChatRender.textHeight.Text), ChatWidth = Int32.Parse(pageChatRender.textWidth.Text), BttvEmotes = (bool)pageChatRender.checkBTTV.IsChecked, FfzEmotes = (bool)pageChatRender.checkFFZ.IsChecked, Outline = (bool)pageChatRender.checkOutline.IsChecked, Font = (string)pageChatRender.comboFont.SelectedItem, FontSize = Double.Parse(pageChatRender.textFontSize.Text), UpdateRate = Double.Parse(pageChatRender.textUpdateTime.Text), Timestamp = (bool)pageChatRender.checkTimestamp.IsChecked, MessageColor = messageColor, Framerate = Int32.Parse(pageChatRender.textFramerate.Text), InputArgs = Settings.Default.FfmpegInputArgs, OutputArgs = Settings.Default.FfmpegOutputArgs, MessageFontStyle = SKFontStyle.Normal, UsernameFontStyle = SKFontStyle.Bold }; System.Drawing.Size canvasSize = new System.Drawing.Size(renderOptions.ChatWidth, renderOptions.SectionHeight); SKPaint nameFont = new SKPaint() { Typeface = SKTypeface.FromFamilyName(renderOptions.Font, renderOptions.UsernameFontStyle), LcdRenderText = true, SubpixelText = true, TextSize = (float)renderOptions.FontSize, IsAntialias = true, HintingLevel = SKPaintHinting.Full, FilterQuality = SKFilterQuality.High }; SKPaint messageFont = new SKPaint() { Typeface = SKTypeface.FromFamilyName(renderOptions.Font, renderOptions.MessageFontStyle), LcdRenderText = true, SubpixelText = true, TextSize = (float)renderOptions.FontSize, IsAntialias = true, HintingLevel = SKPaintHinting.Full, FilterQuality = SKFilterQuality.High, Color = renderOptions.MessageColor }; List<TwitchEmote> thirdPartyEmotes = new List<TwitchEmote>(); List<TwitchEmote> chatEmotes = new List<TwitchEmote>(); Dictionary<string, SKBitmap> emojiCache = new Dictionary<string, SKBitmap>(); using (SKCanvas previewCanvas = new SKCanvas(previewBitmap)) { previewCanvas.Clear(backgroundColor); foreach (PreviewEmote previewDataEmote in previewData.emotes) { byte[] imageBytes = Convert.FromBase64String(previewDataEmote.image); SKBitmap emoteBitmap = SKBitmap.Decode(imageBytes); SKCodec emoteCodec; using (MemoryStream ms = new MemoryStream(imageBytes)) emoteCodec = SKCodec.Create(ms); TwitchEmote emote = new TwitchEmote(new List<SKBitmap>() { emoteBitmap }, emoteCodec, previewDataEmote.name, ".png", "0", 1, imageBytes); thirdPartyEmotes.Add(emote); } foreach (PreviewComment previewComment in previewData.comments) { int default_x = 2; System.Drawing.Point drawPos = new System.Drawing.Point(default_x, 0); string userName = previewComment.name; SKColor userColor = new SKColor(Convert.ToByte(previewComment.color.Substring(0, 2), 16), Convert.ToByte(previewComment.color.Substring(2, 2), 16), Convert.ToByte(previewComment.color.Substring(4, 2), 16)); List<SKBitmap> imageList = new List<SKBitmap>(); SKBitmap sectionImage = new SKBitmap(canvasSize.Width, canvasSize.Height); List<GifEmote> currentGifEmotes = new List<GifEmote>(); List<SKBitmap> emoteList = new List<SKBitmap>(); List<CheerEmote> cheerEmotes = new List<CheerEmote>(); List<SKRect> emotePositionList = new List<SKRect>(); new SKCanvas(sectionImage).Clear(renderOptions.BackgroundColor); Comment comment = new Comment(); comment.message = new Message(); Fragment msg = new Fragment(); msg.text = previewComment.message; comment.message.fragments = new List<Fragment>(); comment.message.fragments.Add(msg); if (renderOptions.Timestamp) sectionImage = ChatRenderer.DrawTimestamp(sectionImage, imageList, messageFont, renderOptions, comment, canvasSize, ref drawPos, ref default_x); if (previewComment.badges != null) sectionImage = DrawBadges(sectionImage, imageList, renderOptions, canvasSize, ref drawPos, previewComment); sectionImage = ChatRenderer.DrawUsername(sectionImage, imageList, renderOptions, nameFont, userName, userColor, canvasSize, ref drawPos); sectionImage = ChatRenderer.DrawMessage(sectionImage, imageList, renderOptions, currentGifEmotes, messageFont, emojiCache, chatEmotes, thirdPartyEmotes, cheerEmotes, comment, canvasSize, ref drawPos, ref default_x, emoteList, emotePositionList); int finalHeight = 0; foreach (var img in imageList) finalHeight += img.Height; SKBitmap finalImage = new SKBitmap(canvasSize.Width, finalHeight); SKCanvas finalImageCanvas = new SKCanvas(finalImage); finalHeight = 0; foreach (var img in imageList) { finalImageCanvas.DrawBitmap(img, 0, finalHeight); finalHeight += img.Height; img.Dispose(); } finalComments.Add(new TwitchCommentPreview(finalImage, Double.Parse(comment.content_offset_seconds.ToString()), currentGifEmotes, emoteList, emotePositionList)); } int y = 0; int tempHeight = 0; foreach (TwitchCommentPreview twitchCommentPreview in finalComments) tempHeight += twitchCommentPreview.section.Height; SKBitmap tempBitmap = new SKBitmap((int)this.Width, tempHeight); using (SKCanvas tempCanvas = new SKCanvas(tempBitmap)) { foreach (TwitchCommentPreview twitchCommentPreview in finalComments) { tempCanvas.DrawBitmap(twitchCommentPreview.section, 0, y, imagePaint); for (int i = 0; i < twitchCommentPreview.normalEmotes.Count; i++) { SKRect refrenceRect = twitchCommentPreview.normalEmotesPositions[i]; tempCanvas.DrawBitmap(twitchCommentPreview.normalEmotes[i], new SKRect(refrenceRect.Left, refrenceRect.Top + y, refrenceRect.Right, refrenceRect.Bottom + y), imagePaint); } y += twitchCommentPreview.section.Height; } } previewCanvas.DrawBitmap(tempBitmap, 0, previewBitmap.Height - tempBitmap.Height); } using (var stream = new MemoryStream()) { SKImage.FromBitmap(previewBitmap).Encode(SKEncodedImageFormat.Png, 100).SaveTo(stream); var bitmap = new BitmapImage(); bitmap.BeginInit(); bitmap.StreamSource = stream; bitmap.CacheOption = BitmapCacheOption.OnLoad; bitmap.EndInit(); bitmap.Freeze(); imgPreview.Source = bitmap; } } catch { try { this.Width = 500; this.Height = 338; imgPreview.Width = 500; imgPreview.Height = 300; SKBitmap errorBitmap = new SKBitmap(500, 300); using (SKCanvas skCanvas = new SKCanvas(errorBitmap)) { skCanvas.DrawText("ERROR, UNABLE TO RENDER CHAT", 40, 150, new SKPaint() { Typeface = SKTypeface.FromFamilyName("Arial", SKFontStyle.Bold), TextSize = 18, IsAntialias = true, FilterQuality = SKFilterQuality.High }); SKBitmap peepo = SKBitmap.Decode(Application .GetResourceStream(new Uri("pack://application:,,,/Images/peepoSad.png")).Stream); skCanvas.DrawBitmap(peepo, 370, 132); } using (var stream = new MemoryStream()) { SKImage.FromBitmap(errorBitmap).Encode(SKEncodedImageFormat.Png, 100).SaveTo(stream); var bitmap = new BitmapImage(); bitmap.BeginInit(); bitmap.StreamSource = stream; bitmap.CacheOption = BitmapCacheOption.OnLoad; bitmap.EndInit(); bitmap.Freeze(); imgPreview.Source = bitmap; } } catch { } } }
}//end write JPEG public bool writeJpeg(CloudCoin cc, string tag, string filePath, string targetPath, string printMessage) { // Console.Out.WriteLine("Writing jpeg " + cc.sn); // CoinUtils cu = new CoinUtils(cc); filePath = filePath.Replace("\\\\", "\\"); bool fileSavedSuccessfully = true; /* BUILD THE CLOUDCOIN STRING */ String cloudCoinStr = "01C34A46494600010101006000601D05"; //THUMBNAIL HEADER BYTES for (int i = 0; (i < 25); i++) { cloudCoinStr = cloudCoinStr + cc.an[i]; } // end for each an //cloudCoinStr += "204f42455920474f4420262044454645415420545952414e545320";// Hex for " OBEY GOD & DEFEAT TYRANTS " //cloudCoinStr += "20466f756e6465727320372d352d3137";// Founders 7-5-17 cloudCoinStr += "4c6976652046726565204f7220446965"; // Live Free or Die cloudCoinStr += "00000000000000000000000000"; //Set to unknown so program does not export user data // for (int i =0; i < 25; i++) { // switch () { }//end switch pown char // }//end for each pown cloudCoinStr += "00"; // HC: Has comments. 00 = No cc.CalcExpirationDate(); cloudCoinStr += cc.edHex; // 01;//Expiration date Sep 2016 (one month after zero month) cloudCoinStr += "01"; // cc.nn;//network number String hexSN = cc.sn.ToString("X6"); String fullHexSN = ""; switch (hexSN.Length) { case 1: fullHexSN = ("00000" + hexSN); break; case 2: fullHexSN = ("0000" + hexSN); break; case 3: fullHexSN = ("000" + hexSN); break; case 4: fullHexSN = ("00" + hexSN); break; case 5: fullHexSN = ("0" + hexSN); break; case 6: fullHexSN = hexSN; break; } cloudCoinStr = (cloudCoinStr + fullHexSN); /* BYTES THAT WILL GO FROM 04 to 454 (Inclusive)*/ byte[] ccArray = this.hexStringToByteArray(cloudCoinStr); /* READ JPEG TEMPLATE*/ byte[] jpegBytes = null; //jpegBytes = readAllBytes(filePath); jpegBytes = File.ReadAllBytes(filePath); /* WRITE THE SERIAL NUMBER ON THE JPEG */ //Bitmap bitmapimage; SKBitmap bitmapimage; //using (var ms = new MemoryStream(jpegBytes)) { //bitmapimage = new Bitmap(ms); bitmapimage = SKBitmap.Decode(jpegBytes); } SKCanvas canvas = new SKCanvas(bitmapimage); //Graphics graphics = Graphics.FromImage(bitmapimage); //graphics.SmoothingMode = SmoothingMode.AntiAlias; //graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; SKPaint textPaint = new SKPaint() { IsAntialias = true, Color = SKColors.White, TextSize = 14, Typeface = SKTypeface.FromFamilyName("Arial") }; //PointF drawPointAddress = new PointF(30.0F, 25.0F); canvas.DrawText(printMessage, 30, 40, textPaint); //graphics.DrawString(String.Format("{0:N0}", cc.sn) + " of 16,777,216 on Network: 1", new Font("Arial", 10), Brushes.White, drawPointAddress); //ImageConverter converter = new ImageConverter(); //byte[] snBytes = (byte[])converter.ConvertTo(bitmapimage, typeof(byte[])); SKImage image = SKImage.FromBitmap(bitmapimage); SKData data = image.Encode(SKEncodedImageFormat.Jpeg, 100); byte[] snBytes = data.ToArray(); List <byte> b1 = new List <byte>(snBytes); List <byte> b2 = new List <byte>(ccArray); b1.InsertRange(4, b2); if (tag == "random") { Random r = new Random(); int rInt = r.Next(100000, 1000000); //for ints tag = rInt.ToString(); } string fileName = targetPath; File.WriteAllBytes(fileName, b1.ToArray()); Console.Out.WriteLine("Writing to " + fileName); //CoreLogger.Log("Writing to " + fileName); return(fileSavedSuccessfully); }//end write JPEG
public void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args) { if (_refreshing) { return; } SKCanvas canvas = args.Surface.Canvas; canvas.Clear(SKColors.White); float xBounds = 0; float yBounds = 0; foreach (var c in _components) { //only make scaling decisions based on visible components if (c.IsVisible) { if ((c.X + c.Width) > xBounds) { xBounds = c.X + c.Width; } if ((c.Y + c.Height) > yBounds) { yBounds = c.Y + c.Height; } } } float canvasScalarX = 1; float canvasScalarY = 1; //only start scaling down if the edge of the canvas reaches the components if (xBounds > canvas.DeviceClipBounds.Width) { canvasScalarX = canvas.DeviceClipBounds.Width / xBounds; } if (yBounds > canvas.DeviceClipBounds.Height) { canvasScalarY = canvas.DeviceClipBounds.Height / yBounds; } //maintain aspect ratio var scale = Math.Min(canvasScalarX, canvasScalarY); _canvas.WidthScale = scale; _canvas.HeightScale = scale; canvas.Scale(scale); //paint components to surface in their display order var componentsOrdered = _components.OrderBy(c => c.DisplayOrder); foreach (var c in componentsOrdered) { c.OnDraw(canvas); } //if the _currentComponent was merely selected, it gets drawn in the above loop, //but if it was newly created, it's not part of the components yet, but should be drawn still if (!_components.Contains(_currentComponent)) { _currentComponent?.OnDraw(canvas); } if (_saveSurface) { _saveSurface = false; using (var image = args.Surface.Snapshot()) { if (_thumbnailSize <= 0) { _thumbnailData = image.Encode(SKEncodedImageFormat.Png, 100); } else { //square the image var minLength = Math.Min(image.Width, image.Height); var rect = SKRectI.Create((image.Width - minLength) / 2, (image.Height - minLength) / 2, minLength, minLength); using (var subImage = image.Subset(rect)) { using (var bitmap = SKBitmap.FromImage(subImage)) { using (var sizedBitmap = bitmap.Resize(new SKImageInfo(_thumbnailSize, _thumbnailSize), SKBitmapResizeMethod.Lanczos3)) { using (var img = SKImage.FromBitmap(sizedBitmap)) { _thumbnailData = image.Encode(SKEncodedImageFormat.Png, 100); } } } } } } thumbnailCompletion.SetResult(true); } }
private void ExportToolStripMenuItem_Click(object sender, EventArgs e) { //ToolTipText is the full filename var fileName = ((ToolStripMenuItem)sender).ToolTipText; var tag = ((ToolStripMenuItem)sender).Tag as ExportData; var resource = tag.Resource; Console.WriteLine($"Export requested for {fileName}"); string[] extensions = null; switch (resource.ResourceType) { case ResourceType.Sound: //WAV or MP3 extensions = new[] { ((Sound)resource.Blocks[BlockType.DATA]).Type.ToString().ToLower() }; break; case ResourceType.Texture: extensions = new[] { "png", "jpg", "gif", "bmp" }; break; case ResourceType.PanoramaLayout: extensions = new[] { "xml", "vxml" }; break; case ResourceType.PanoramaScript: extensions = new[] { "js", "vjs" }; break; case ResourceType.PanoramaStyle: extensions = new[] { "css", "vcss" }; break; case ResourceType.Mesh: extensions = new[] { "obj" }; break; } //Did we find a format we like? if (extensions != null) { var dialog = new SaveFileDialog { FileName = Path.GetFileName(Path.ChangeExtension(fileName, extensions[0])), InitialDirectory = Settings.Config.SaveDirectory, DefaultExt = extensions[0], }; var filter = string.Empty; foreach (var extension in extensions) { filter += $"{extension} files (*.{extension})|*.{extension}|"; } //Remove the last | dialog.Filter = filter.Substring(0, filter.Length - 1); var result = dialog.ShowDialog(); if (result == DialogResult.OK) { Settings.Config.SaveDirectory = Path.GetDirectoryName(dialog.FileName); Settings.Save(); using (var stream = dialog.OpenFile()) { switch (resource.ResourceType) { case ResourceType.Sound: var soundData = ((Sound)resource.Blocks[BlockType.DATA]).GetSound(); stream.Write(soundData, 0, soundData.Length); break; case ResourceType.Texture: var format = SKEncodedImageFormat.Png; switch (dialog.FilterIndex) { case 2: format = SKEncodedImageFormat.Jpeg; break; case 3: format = SKEncodedImageFormat.Gif; break; case 4: format = SKEncodedImageFormat.Bmp; break; } var image = SKImage.FromBitmap(((Texture)resource.Blocks[BlockType.DATA]).GenerateBitmap()); using (var data = image.Encode(format, 100)) { data.SaveTo(stream); } break; case ResourceType.PanoramaLayout: case ResourceType.PanoramaScript: case ResourceType.PanoramaStyle: var panoramaData = ((Panorama)resource.Blocks[BlockType.DATA]).Data; stream.Write(panoramaData, 0, panoramaData.Length); break; case ResourceType.Mesh: using (var objStream = new StreamWriter(stream)) using (var mtlStream = new StreamWriter(Path.ChangeExtension(dialog.FileName, "mtl"))) { MeshObject.WriteObject(objStream, mtlStream, Path.GetFileNameWithoutExtension(dialog.FileName), resource); } foreach (var texture in tag.Renderer.MaterialLoader.LoadedTextures) { Console.WriteLine($"Exporting texture for mesh: {texture}"); var textureResource = FileExtensions.LoadFileByAnyMeansNecessary(texture + "_c", tag.Renderer.CurrentFileName, tag.Renderer.CurrentPackage); var textureImage = SKImage.FromBitmap(((Texture)textureResource.Blocks[BlockType.DATA]).GenerateBitmap()); using (var texStream = new FileStream(Path.Combine(Path.GetDirectoryName(dialog.FileName), Path.GetFileNameWithoutExtension(texture) + ".png"), FileMode.Create, FileAccess.Write)) using (var data = textureImage.Encode(SKEncodedImageFormat.Png, 100)) { data.SaveTo(texStream); } } break; } } } } Console.WriteLine($"Export requested for {fileName} Complete"); }
public async Task <DataResolverResult> Resolve(string identifier, TaskParameter parameters, CancellationToken token) { ImageSource source = parameters.Source; if (!string.IsNullOrWhiteSpace(parameters.LoadingPlaceholderPath) && parameters.LoadingPlaceholderPath == identifier) { source = parameters.LoadingPlaceholderSource; } else if (!string.IsNullOrWhiteSpace(parameters.ErrorPlaceholderPath) && parameters.ErrorPlaceholderPath == identifier) { source = parameters.ErrorPlaceholderSource; } var resolvedData = await(Configuration.DataResolverFactory ?? new DataResolverFactory()) .GetResolver(identifier, source, parameters, Configuration) .Resolve(identifier, parameters, token).ConfigureAwait(false); if (resolvedData?.Stream == null) { throw new FileNotFoundException(identifier); } var svg = new SKSvg() { ThrowOnUnsupportedElement = false, }; SKPicture picture; if (ReplaceStringMap == null || ReplaceStringMap.Count == 0) { using (var svgStream = resolvedData.Stream) { picture = svg.Load(svgStream); } } else { using (var svgStream = resolvedData.Stream) using (var reader = new StreamReader(svgStream)) { var inputString = await reader.ReadToEndAsync(); foreach (var map in ReplaceStringMap .Where(v => v.Key.StartsWith("regex:"))) { inputString = Regex.Replace(inputString, map.Key.Substring(6), map.Value); } var builder = new StringBuilder(inputString); foreach (var map in ReplaceStringMap .Where(v => !v.Key.StartsWith("regex:", StringComparison.OrdinalIgnoreCase))) { builder.Replace(map.Key, map.Value); } using (var svgFinalStream = new MemoryStream(Encoding.UTF8.GetBytes(builder.ToString()))) { picture = svg.Load(svgFinalStream); } } } double sizeX = 0; double sizeY = 0; if (VectorWidth <= 0 && VectorHeight <= 0) { if (picture.CullRect.Width > 0) { sizeX = picture.CullRect.Width; } else { sizeX = 300; } if (picture.CullRect.Height > 0) { sizeY = picture.CullRect.Height; } else { sizeY = 300; } } else if (VectorWidth > 0 && VectorHeight > 0) { sizeX = VectorWidth; sizeY = VectorHeight; } else if (VectorWidth > 0) { sizeX = VectorWidth; sizeY = (VectorWidth / picture.CullRect.Width) * picture.CullRect.Height; } else { sizeX = (VectorHeight / picture.CullRect.Height) * picture.CullRect.Width; sizeY = VectorHeight; } if (UseDipUnits) { sizeX = sizeX.DpToPixels(); sizeY = sizeY.DpToPixels(); } resolvedData.ImageInformation.SetType(ImageInformation.ImageType.SVG); using (var bitmap = new SKBitmap(new SKImageInfo((int)sizeX, (int)sizeY))) using (var canvas = new SKCanvas(bitmap)) using (var paint = new SKPaint()) { canvas.Clear(SKColors.Transparent); float scaleX = (float)sizeX / picture.CullRect.Width; float scaleY = (float)sizeY / picture.CullRect.Height; var matrix = SKMatrix.MakeScale(scaleX, scaleY); canvas.DrawPicture(picture, ref matrix, paint); canvas.Flush(); #if __IOS__ var info = bitmap.Info; CGImage cgImage; IntPtr size; using (var provider = new CGDataProvider(bitmap.GetPixels(out size), size.ToInt32())) using (var colorSpace = CGColorSpace.CreateDeviceRGB()) using (cgImage = new CGImage(info.Width, info.Height, 8, info.BitsPerPixel, info.RowBytes, colorSpace, CGBitmapFlags.PremultipliedLast | CGBitmapFlags.ByteOrder32Big, provider, null, false, CGColorRenderingIntent.Default)) { return(new DataResolverResult <UIImage>(new UIImage(cgImage), resolvedData.LoadingResult, resolvedData.ImageInformation)); } #elif __MACOS__ var info = bitmap.Info; CGImage cgImage; IntPtr size; using (var provider = new CGDataProvider(bitmap.GetPixels(out size), size.ToInt32())) using (var colorSpace = CGColorSpace.CreateDeviceRGB()) using (cgImage = new CGImage(info.Width, info.Height, 8, info.BitsPerPixel, info.RowBytes, colorSpace, CGBitmapFlags.PremultipliedLast | CGBitmapFlags.ByteOrder32Big, provider, null, false, CGColorRenderingIntent.Default)) { return(new DataResolverResult <NSImage>(new NSImage(cgImage, CGSize.Empty), resolvedData.LoadingResult, resolvedData.ImageInformation)); } #elif __ANDROID__ using (var skiaPixmap = bitmap.PeekPixels()) { var info = skiaPixmap.Info; // destination values var config = Bitmap.Config.Argb8888; var dstInfo = new SKImageInfo(info.Width, info.Height); // try keep the pixel format if we can switch (info.ColorType) { case SKColorType.Alpha8: config = Bitmap.Config.Alpha8; dstInfo.ColorType = SKColorType.Alpha8; break; case SKColorType.Rgb565: config = Bitmap.Config.Rgb565; dstInfo.ColorType = SKColorType.Rgb565; dstInfo.AlphaType = SKAlphaType.Opaque; break; case SKColorType.Argb4444: config = Bitmap.Config.Argb4444; dstInfo.ColorType = SKColorType.Argb4444; break; } // destination bitmap var bmp = Bitmap.CreateBitmap(info.Width, info.Height, config); var ptr = bmp.LockPixels(); // copy var success = skiaPixmap.ReadPixels(dstInfo, ptr, dstInfo.RowBytes); // confirm bmp.UnlockPixels(); if (!success) { bmp.Recycle(); bmp.Dispose(); bmp = null; } return(new DataResolverResult <SelfDisposingBitmapDrawable>(new SelfDisposingBitmapDrawable(bmp), resolvedData.LoadingResult, resolvedData.ImageInformation)); } #elif __WINDOWS__ WriteableBitmap writeableBitmap = null; await Configuration.MainThreadDispatcher.PostAsync(async() => { using (var skiaImage = SKImage.FromPixels(bitmap.PeekPixels())) { var info = new SKImageInfo(skiaImage.Width, skiaImage.Height); writeableBitmap = new WriteableBitmap(info.Width, info.Height); var buffer = writeableBitmap.PixelBuffer as IBufferByteAccess; if (buffer == null) { throw new InvalidCastException("Unable to convert WriteableBitmap.PixelBuffer to IBufferByteAccess."); } IntPtr ptr; var hr = buffer.Buffer(out ptr); if (hr < 0) { throw new InvalidCastException("Unable to retrieve pixel address from WriteableBitmap.PixelBuffer."); } using (var pixmap = new SKPixmap(info, ptr)) { skiaImage.ReadPixels(pixmap, 0, 0); } writeableBitmap.Invalidate(); } }); return(new DataResolverResult <WriteableBitmap>(writeableBitmap, resolvedData.LoadingResult, resolvedData.ImageInformation)); #else lock (_encodingLock) { using (var image = SKImage.FromBitmap(bitmap)) //using (var data = image.Encode(SKImageEncodeFormat.Png, 100)) //TODO disabled because of https://github.com/mono/SkiaSharp/issues/285 using (var data = image.Encode()) { var stream = new MemoryStream(); data.SaveTo(stream); stream.Position = 0; return(new DataResolverResult(stream, resolvedData.LoadingResult, resolvedData.ImageInformation)); } } #endif } }
public void Save(Stream stream, ImageFormat format) { SKImage.FromBitmap(nativeSkBitmap).Encode(format.format, 100).SaveTo(stream); }
public TileRenderResponse Invoke(TileRenderRequestArgument arg) { try { // Tile requests can be a significant resource commitment. Ensure TPaaS will be listening... PerformTPaaSRequestLivelinessCheck(arg); var requestStopWatch = Stopwatch.StartNew(); _log.LogInformation("In TileRenderRequestComputeFunc.Invoke()"); try { // Supply the TRex ID of the Ignite node currently running this code to permit processing contexts to send // sub grid results to it. arg.TRexNodeID = TRexNodeID.ThisNodeID(StorageMutability.Immutable); _log.LogInformation($"Assigned TRexNodeId from local node is {arg.TRexNodeID}"); var render = new RenderOverlayTile (arg.ProjectID, arg.Mode, new XYZ(arg.Extents.MinX, arg.Extents.MinY), new XYZ(arg.Extents.MaxX, arg.Extents.MaxY), arg.CoordsAreGrid, arg.PixelsX, arg.PixelsY, arg.Filters, arg.ReferenceDesign, arg.Palette, Color.Black, arg.TRexNodeID, arg.LiftParams, arg.VolumeType); _log.LogInformation("Executing render.ExecuteAsync()"); using var bmp = render.ExecuteAsync().WaitAndUnwrapException(); _log.LogInformation($"Render status = {render.ResultStatus}"); if (bmp == null) { _log.LogInformation("Null bitmap returned by executor"); return(new TileRenderResponse { TileBitmapData = null, ResultStatus = render.ResultStatus }); } using var image = SKImage.FromBitmap(bmp); using var data = image.Encode(SKEncodedImageFormat.Png, 100); using var stream = RecyclableMemoryStreamManagerHelper.Manager.GetStream(); data.SaveTo(stream); return(new TileRenderResponse { TileBitmapData = stream.ToArray(), ResultStatus = render.ResultStatus }); } finally { _log.LogInformation($"Exiting TileRenderRequestComputeFunc.Invoke() in {requestStopWatch.Elapsed}"); // Flag tile renders that take more than 20 seconds to render... if (requestStopWatch.Elapsed > _tileRequestTimeSpanWarnLimit) { _log.LogInformation($"Tile render request required more than {_tileRequestTimeSpanWarnLimit} to complete"); } } } catch (Exception e) { _log.LogError(e, "Exception occurred in TileRenderRequestComputeFunc.Invoke()"); return(new TileRenderResponse { ResultStatus = Types.RequestErrorStatus.Exception }); } }
public async Task ResizeImagesAsync(string sourcePath, string destPath, double scale, CancellationToken token) { if (!Directory.Exists(destPath)) { Directory.CreateDirectory(destPath); } await Task.Yield(); var allFiles = FindImages(sourcePath); List <Task> tasks = new List <Task>(); foreach (var filePath in allFiles) { await Task.Yield(); tasks.Add(Task.Run(() => { Console.ForegroundColor = ConsoleColor.White; Console.WriteLine(string.Format("Thread ID: {0}", System.Threading.Thread.CurrentThread.ManagedThreadId)); var bitmap = SKBitmap.Decode(filePath); var imgPhoto = SKImage.FromBitmap(bitmap); var imgName = Path.GetFileNameWithoutExtension(filePath); var sourceWidth = imgPhoto.Width; var sourceHeight = imgPhoto.Height; var destinationWidth = (int)(sourceWidth * scale); var destinationHeight = (int)(sourceHeight * scale); if (!token.IsCancellationRequested) { using var scaledBitmap = bitmap.Resize( new SKImageInfo(destinationWidth, destinationHeight), SKFilterQuality.High); using var scaledImage = SKImage.FromBitmap(scaledBitmap); using var data = scaledImage.Encode(SKEncodedImageFormat.Jpeg, 100); using var s = File.OpenWrite(Path.Combine(destPath, imgName + ".jpg")); data.SaveTo(s); Console.ForegroundColor = ConsoleColor.Yellow; Console.WriteLine(string.Format("Finish Thread ID: {0}", System.Threading.Thread.CurrentThread.ManagedThreadId)); } }, token)); } try { Task.WaitAll(tasks.ToArray()); } catch (OperationCanceledException) { //Console.WriteLine($"{Environment.NewLine}已經取消"); } catch (Exception ex) { //Console.WriteLine($"{Environment.NewLine}發現例外異常 {ex.Message}"); foreach (var task in tasks) { switch (task.Status) { case TaskStatus.Created: break; case TaskStatus.WaitingForActivation: break; case TaskStatus.WaitingToRun: break; case TaskStatus.Running: break; case TaskStatus.WaitingForChildrenToComplete: break; case TaskStatus.RanToCompletion: Console.WriteLine(string.Format("Task ID: {0} Completion", task.Id)); break; case TaskStatus.Canceled: Console.WriteLine(string.Format("Task ID: {0} Canceled", task.Id)); break; case TaskStatus.Faulted: Console.WriteLine(string.Format("Task ID: {0} Faulted", task.Id)); break; default: break; } } } }
void Process(SKImage image, List <RestrictedFaceArea> hiddenRects, int jpegQuality) { this.jpegQuality = jpegQuality; bytes = null; using (SKBitmap bitmap = SKBitmap.FromImage(image)) { for (int f = 0; f < hiddenRects.Count; f++) { SKBitmap faceBlurBitmap = null; SKBitmap ovalMask = null; // кварат зоны наложения маски SKRect target = new SKRect(hiddenRects[f].x, hiddenRects[f].y, hiddenRects[f].x + hiddenRects[f].w, hiddenRects[f].y + hiddenRects[f].h); float rotateAngle = hiddenRects[f].a; float blurSideSize = (float)(Math.Max(target.Width, target.Height) * 1.5); float sigma = blurSideSize / 25; // квадрат с запасом для равномерного размыливания изображения SKRect targetPlus = new SKRect(target.MidX - blurSideSize / 2, target.MidY - blurSideSize / 2, target.MidX + blurSideSize / 2, target.MidY + blurSideSize / 2); using (SKSurface surfaceBlur = SKSurface.Create(new SKImageInfo((int)targetPlus.Width, (int)targetPlus.Height))) using (SKCanvas canvasBlur = surfaceBlur.Canvas) { using (SKImageFilter imageFilterBlur = SKImageFilter.CreateBlur(sigma, sigma)) using (SKPaint paintBlur = new SKPaint { ImageFilter = imageFilterBlur, IsAntialias = false, }) { canvasBlur.DrawImage(image, targetPlus, new SKRect(0, 0, targetPlus.Width, targetPlus.Height), paintBlur); } using (SKImage imageBlur = surfaceBlur.Snapshot()) { faceBlurBitmap = SKBitmap.FromImage(imageBlur); //if (trace) SaveJpegImage(imageBlur, "FaceBlur.jpg"); } } // формируем эллипс-маску с учётом требуемого наклона float width = Math.Max(target.Width, target.Height); using (SKSurface surfaceOval = SKSurface.Create(new SKImageInfo((int)width, (int)width))) using (SKCanvas canvasOval = surfaceOval.Canvas) { using (SKRoundRect roundRectOval = new SKRoundRect(new SKRect((width - target.Width) / 2, (width - target.Height) / 2, (width - target.Width) / 2 + target.Width, (width - target.Height) / 2 + target.Height), (float)(target.Width / 2.2), (float)(target.Height / 2.2))) using (SKPaint paintOval = new SKPaint { IsAntialias = true, Style = SKPaintStyle.Fill, Color = SKColors.White }) { canvasOval.Save(); canvasOval.RotateDegrees(rotateAngle, (float)(width / 2), (float)(width / 2)); canvasOval.DrawRoundRect(roundRectOval, paintOval); // на прежнем канвасе canvasOval.Restore(); } using (SKImage imageOval = surfaceOval.Snapshot()) { ovalMask = SKBitmap.FromImage(imageOval); //if (trace) SaveJpegImage(imageOval, "OvalMask.jpg"); } } bytes = ovalMask.Bytes; int imageX = 0, imageY = 0, blurX = 0, blurY = 0; int deltaBlurXImage = (int)(target.MidX - (float)ovalMask.Width / 2); int deltaBlurYImage = (int)(target.MidY - (float)ovalMask.Height / 2); int deltaMaskBlurX = (int)Math.Round((float)faceBlurBitmap.Width / 2 - (float)ovalMask.Width / 2); int deltaMaskBlurY = (int)Math.Round((float)faceBlurBitmap.Height / 2 - (float)ovalMask.Height / 2); int col = 0; int row = 0; try { for (int i = 3; i < bytes.Length; i = i + 4) { if (bytes[i] > 0) { imageX = col + deltaBlurXImage; imageY = row + deltaBlurYImage; blurX = col + deltaMaskBlurX; blurY = row + deltaMaskBlurY; if (imageX < bitmap.Width && imageY < bitmap.Height && imageX < bitmap.Width && imageY < bitmap.Height) { bitmap.SetPixel(imageX, imageY, faceBlurBitmap.GetPixel(blurX, blurY)); } } col++; if (col >= ovalMask.RowBytes >> 2) { col = 0; row++; } } } catch (Exception exc) { } using (SKImage sKImage = SKImage.FromBitmap(bitmap)) using (SKData tmpData = sKImage.Encode(SKEncodedImageFormat.Jpeg, jpegQuality)) { bytes = tmpData.ToArray(); if (trace) { using (FileStream tmpStream = new FileStream("Blur result.jpg", FileMode.Create)) tmpData.SaveTo(tmpStream); } } faceBlurBitmap = null; ovalMask = null; } } dtStop = DateTime.Now; }
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; bool isCached = _memoryCache.TryGetValue <byte[]>(cacheKey, out byte[] imageBytes); if (isCached) { return(SKData.CreateCopy(imageBytes)); } // this represents the EXIF orientation var 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 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, SKFilterQuality.Medium); // 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); }
public static async Task <HLinkMediaModel> CreateClippedMediaModel(HLinkLoadImageModel argHLinkLoadImageModel) { if (argHLinkLoadImageModel is null) { throw new ArgumentNullException(nameof(argHLinkLoadImageModel)); } if (!argHLinkLoadImageModel.DeRef.Valid) { throw new ArgumentException("CreateClippedMediaModel argument is invalid", nameof(argHLinkLoadImageModel)); } // TODO cleanup code. Multiple copies of things in use MediaModel theMediaModel = argHLinkLoadImageModel.DeRef; SKBitmap resourceBitmap = new SKBitmap(); MediaModel newMediaModel = new MediaModel(); string newHLinkKey = argHLinkLoadImageModel.HLinkKey + "-" + argHLinkLoadImageModel.GCorner1X + argHLinkLoadImageModel.GCorner1Y + argHLinkLoadImageModel.GCorner2X + argHLinkLoadImageModel.GCorner2Y; string outFileName = Path.Combine("Cropped", newHLinkKey + ".png"); string outFilePath = Path.Combine(DataStore.AD.CurrentDataFolder.FullName, outFileName); Debug.WriteLine(argHLinkLoadImageModel.DeRef.MediaStorageFilePath); // Check if already exists MediaModel fileExists = DV.MediaDV.GetModelFromHLinkString(newHLinkKey); if (!fileExists.Valid) { // Needs clipping using (StreamReader stream = new StreamReader(theMediaModel.MediaStorageFilePath)) { resourceBitmap = SKBitmap.Decode(stream.BaseStream); } // Check for too large a bitmap Debug.WriteLine("Image ResourceBitmap size: " + resourceBitmap.ByteCount); if (resourceBitmap.ByteCount > int.MaxValue - 1000) { // TODO Handle this better. Perhaps resize? Delete for now resourceBitmap = new SKBitmap(); } float crleft = (float)(argHLinkLoadImageModel.GCorner1X / 100d * theMediaModel.MetaDataWidth); float crright = (float)(argHLinkLoadImageModel.GCorner2X / 100d * theMediaModel.MetaDataWidth); float crtop = (float)(argHLinkLoadImageModel.GCorner1Y / 100d * theMediaModel.MetaDataHeight); float crbottom = (float)(argHLinkLoadImageModel.GCorner2Y / 100d * theMediaModel.MetaDataHeight); SKRect cropRect = new SKRect(crleft, crtop, crright, crbottom); SKBitmap croppedBitmap = new SKBitmap( (int)cropRect.Width, (int)cropRect.Height ); SKRect dest = new SKRect( 0, 0, cropRect.Width, cropRect.Height ); SKRect source = new SKRect( cropRect.Left, cropRect.Top, cropRect.Right, cropRect.Bottom); using (SKCanvas canvas = new SKCanvas(croppedBitmap)) { canvas.DrawBitmap(resourceBitmap, source, dest); } // create an image COPY SKImage image = SKImage.FromBitmap(croppedBitmap); // encode the image (defaults to PNG) SKData encoded = image.Encode(); // get a stream over the encoded data using (Stream stream = File.Open(outFilePath, FileMode.OpenOrCreate, System.IO.FileAccess.Write, FileShare.ReadWrite)) { encoded.SaveTo(stream); } croppedBitmap.Dispose(); // ------------ Save new MediaObject newMediaModel = theMediaModel.Copy(); newMediaModel.HLinkKey = newHLinkKey; newMediaModel.HomeImageHLink.HLinkKey = newHLinkKey; newMediaModel.HomeImageHLink.HomeImageType = CommonConstants.HomeImageTypeThumbNail; newMediaModel.HomeImageHLink.HomeSymbol = CommonConstants.IconMedia; newMediaModel.OriginalFilePath = outFileName; newMediaModel.MediaStorageFile = await StoreFolder.FolderGetFileAsync(DataStore.AD.CurrentDataFolder, outFileName).ConfigureAwait(false); newMediaModel.HomeImageHLink.HomeImageType = CommonConstants.HomeImageTypeThumbNail; newMediaModel.IsClippedFile = true; newMediaModel.MetaDataHeight = cropRect.Height; newMediaModel.MetaDataWidth = cropRect.Width; DataStore.DS.MediaData.Add(newMediaModel); //await StorePostLoad.fixMediaFile(newMediaModel).ConfigureAwait(false); } resourceBitmap.Dispose(); return(newMediaModel.HLink); }