public override void Perform(Pixmap pixmap, PreviewImageQuery query) { Point2 desiredSize = new Point2(query.DesiredWidth, query.DesiredHeight); Point2 cropToSize = new Point2(4096, 4096); PixelData layer = pixmap.MainLayer; if (layer == null) { query.Result = new Bitmap(1, 1); return; } // If the desired preview is way smaller than the source data, specify a crop size if (layer.Width > desiredSize.X * 8) { cropToSize.X = Math.Min(cropToSize.X, desiredSize.X * 8); } if (layer.Height > desiredSize.Y * 8) { cropToSize.Y = Math.Min(cropToSize.Y, desiredSize.Y * 8); } // If out image is too big, crop it if (layer.Width > cropToSize.X || layer.Height > cropToSize.Y) { layer = layer.CloneSubImage( layer.Width / 2 - MathF.Min(layer.Width, cropToSize.X) / 2, layer.Height / 2 - MathF.Min(layer.Height, cropToSize.Y) / 2, MathF.Min(layer.Width, cropToSize.X), MathF.Min(layer.Height, cropToSize.Y)); } // Determine the target size for the preview based on desired and actual size Point2 targetSize; float widthRatio = (float)layer.Width / (float)MathF.Max(layer.Height, 1); if (query.SizeMode == PreviewSizeMode.FixedWidth) { targetSize = new Point2(desiredSize.X, MathF.RoundToInt(desiredSize.X / widthRatio)); } else if (query.SizeMode == PreviewSizeMode.FixedHeight) { targetSize = new Point2(MathF.RoundToInt(widthRatio * desiredSize.Y), desiredSize.Y); } else { targetSize = desiredSize; } // Create a properly resized version of the image data if (layer.Width != targetSize.X || layer.Height != targetSize.Y) { layer = layer.CloneRescale(targetSize.X, targetSize.Y, ImageScaleFilter.Linear); } query.Result = layer.ToBitmap(); }
public override void Perform(Pixmap pixmap, PreviewImageQuery query) { int desiredWidth = query.DesiredWidth; int desiredHeight = query.DesiredHeight; PixelData layer = pixmap.MainLayer; if (layer == null) { query.Result = new Bitmap(1, 1); return; } float widthRatio = (float)layer.Width / (float)layer.Height; if (pixmap.Width * pixmap.Height > 4096 * 4096) { layer = layer.CloneSubImage( pixmap.Width / 2 - Math.Min(desiredWidth, pixmap.Width) / 2, pixmap.Height / 2 - Math.Min(desiredHeight, pixmap.Height) / 2, Math.Min(desiredWidth, pixmap.Width), Math.Min(desiredHeight, pixmap.Height)); if (layer.Width != desiredWidth || layer.Height != desiredHeight) { layer = layer.CloneRescale(desiredWidth, desiredHeight, ImageScaleFilter.Linear); } } else if (query.SizeMode == PreviewSizeMode.FixedBoth) { layer = layer.CloneRescale(desiredWidth, desiredHeight, ImageScaleFilter.Linear); } else if (query.SizeMode == PreviewSizeMode.FixedWidth) { layer = layer.CloneRescale(desiredWidth, MathF.RoundToInt(desiredWidth / widthRatio), ImageScaleFilter.Linear); } else if (query.SizeMode == PreviewSizeMode.FixedHeight) { layer = layer.CloneRescale(MathF.RoundToInt(widthRatio * desiredHeight), desiredHeight, ImageScaleFilter.Linear); } else { layer = layer.Clone(); } query.Result = layer.ToBitmap(); }
/// <summary> /// Loads the specified <see cref="Duality.Resources.Pixmap">Pixmaps</see> pixel data. /// </summary> /// <param name="basePixmap">The <see cref="Duality.Resources.Pixmap"/> that is used as pixel data source.</param> /// <param name="sizeMode">Specifies behaviour in case the source data has non-power-of-two dimensions.</param> public void LoadData(ContentRef <Pixmap> basePixmap, TextureSizeMode sizeMode) { if (this.nativeTex == null) { this.nativeTex = DualityApp.GraphicsBackend.CreateTexture(); } this.needsReload = false; this.basePixmap = basePixmap; this.texSizeMode = sizeMode; if (!this.basePixmap.IsExplicitNull) { PixelData pixelData = null; Pixmap basePixmapRes = this.basePixmap.IsAvailable ? this.basePixmap.Res : null; if (basePixmapRes != null) { pixelData = basePixmapRes.MainLayer; bool hasAtlas = (basePixmapRes.Atlas != null && basePixmapRes.Atlas.Count > 0); this.atlas = hasAtlas ? basePixmapRes.Atlas.ToArray() : null; } if (pixelData == null) { pixelData = Pixmap.Checkerboard.Res.MainLayer; } this.AdjustSize(pixelData.Width, pixelData.Height); this.SetupNativeRes(); if (this.texSizeMode != TextureSizeMode.NonPowerOfTwo && (this.pxWidth != this.texWidth || this.pxHeight != this.texHeight)) { if (this.texSizeMode == TextureSizeMode.Enlarge) { PixelData oldData = pixelData; pixelData = oldData.CloneResize(this.texWidth, this.texHeight); // Fill border pixels manually - that's cheaper than ColorTransparentPixels here. oldData.DrawOnto(pixelData, BlendMode.Solid, this.pxWidth, 0, 1, this.pxHeight, this.pxWidth - 1, 0); oldData.DrawOnto(pixelData, BlendMode.Solid, 0, this.pxHeight, this.pxWidth, 1, 0, this.pxHeight - 1); } else { pixelData = pixelData.CloneRescale(this.texWidth, this.texHeight, ImageScaleFilter.Linear); } } // Load pixel data to video memory this.nativeTex.LoadData( this.pixelformat, pixelData.Width, pixelData.Height, pixelData.Data, ColorDataLayout.Rgba, ColorDataElementType.Byte); // Adjust atlas to represent UV coordinates if (this.atlas != null) { Vector2 scale; scale.X = this.uvRatio.X / this.pxWidth; scale.Y = this.uvRatio.Y / this.pxHeight; for (int i = 0; i < this.atlas.Length; i++) { this.atlas[i].X *= scale.X; this.atlas[i].W *= scale.X; this.atlas[i].Y *= scale.Y; this.atlas[i].H *= scale.Y; } } } else { this.atlas = null; this.AdjustSize(this.size.X, this.size.Y); this.SetupNativeRes(); } }