/// <inheritdoc/> protected override void OnApply(ImageBase source, ImageBase target, Rectangle targetRectangle, Rectangle sourceRectangle) { float radians = (float)ImageMaths.DegreesToRadians(this.Angle); double cosradians = Math.Cos(radians); double sinradians = Math.Sin(radians); float lumR = .213f; float lumG = .715f; float lumB = .072f; float oneMinusLumR = 1 - lumR; float oneMinusLumG = 1 - lumG; float oneMinusLumB = 1 - lumB; // The matrix is set up to preserve the luminance of the image. // See http://graficaobscura.com/matrix/index.html // Number are taken from https://msdn.microsoft.com/en-us/library/jj192162(v=vs.85).aspx Matrix4x4 matrix4X4 = new Matrix4x4() { M11 = (float)(lumR + (cosradians * oneMinusLumR) - (sinradians * lumR)), M12 = (float)(lumR - (cosradians * lumR) - (sinradians * 0.143)), M13 = (float)(lumR - (cosradians * lumR) - (sinradians * oneMinusLumR)), M21 = (float)(lumG - (cosradians * lumG) - (sinradians * lumG)), M22 = (float)(lumG + (cosradians * oneMinusLumG) + (sinradians * 0.140)), M23 = (float)(lumG - (cosradians * lumG) + (sinradians * lumG)), M31 = (float)(lumB - (cosradians * lumB) + (sinradians * oneMinusLumB)), M32 = (float)(lumB - (cosradians * lumB) - (sinradians * 0.283)), M33 = (float)(lumB + (cosradians * oneMinusLumB) + (sinradians * lumB)) }; this.matrix = matrix4X4; }
/// <inheritdoc/> protected override void OnApply(ImageBase source, ImageBase target, Rectangle targetRectangle, Rectangle sourceRectangle) { if (this.Greyscale) { new GreyscaleBt709().Apply(source, source, sourceRectangle); } }
/// <inheritdoc/> protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) { int sourceY = sourceRectangle.Y; int sourceBottom = sourceRectangle.Bottom; int startX = sourceRectangle.X; int endX = sourceRectangle.Right; Vector3 inverseVector = Vector3.One; Parallel.For( startY, endY, y => { if (y >= sourceY && y < sourceBottom) { for (int x = startX; x < endX; x++) { Color color = source[x, y]; Vector3 vector = inverseVector - color.ToVector3(); target[x, y] = new Color(vector, color.A); } this.OnRowProcessed(); } }); }
/// <inheritdoc/> protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) { if (source.Bounds == target.Bounds) { target.SetPixels(target.Width, target.Height, source.Pixels); return; } int targetY = this.cropRectangle.Y; int startX = targetRectangle.X; int targetX = this.cropRectangle.X; int endX = this.cropRectangle.Width; int maxX = endX - 1; int maxY = this.cropRectangle.Bottom - 1; Parallel.For( startY, endY, y => { for (int x = startX; x < endX; x++) { int offsetY = y + targetY; offsetY = offsetY.Clamp(0, maxY); int offsetX = x + targetX; offsetX = offsetX.Clamp(0, maxX); target[x, y] = source[offsetX, offsetY]; } this.OnRowProcessed(); }); }
/// <inheritdoc/> public void Encode(ImageBase image, Stream stream) { Guard.NotNull(image, nameof(image)); Guard.NotNull(stream, nameof(stream)); int imageWidth = image.Width; int imageHeight = image.Height; ushort max = JpegConstants.MaxLength; if (imageWidth > max || imageHeight > max) { throw new ImageFormatException($"Image dimensions exceed maximum allowable bounds of {max}px."); } using (EndianBinaryWriter writer = new EndianBinaryWriter(new BigEndianBitConverter(), stream)) { this.WriteApplicationHeader(image, writer); this.WriteDescreteQuantizationTables(writer); this.WriteStartOfFrame(image, writer); this.WriteHuffmanTables(writer); this.WriteStartOfScan(image, writer); writer.Write(new[] { JpegConstants.Markers.XFF, JpegConstants.Markers.EOI }); } }
/// <inheritdoc/> protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) { float contrast = (100f + this.Value) / 100f; int sourceY = sourceRectangle.Y; int sourceBottom = sourceRectangle.Bottom; int startX = sourceRectangle.X; int endX = sourceRectangle.Right; Vector4 contrastVector = new Vector4(contrast, contrast, contrast, 1); Vector4 shiftVector = new Vector4(.5f, .5f, .5f, 1); Parallel.For( startY, endY, y => { if (y >= sourceY && y < sourceBottom) { for (int x = startX; x < endX; x++) { Vector4 color = Color.Expand(source[x, y]).ToVector4(); color -= shiftVector; color *= contrastVector; color += shiftVector; target[x, y] = Color.Compress(new Color(color)); } this.OnRowProcessed(); } }); }
/// <inheritdoc/> protected override void OnApply(ImageBase source, ImageBase target, Rectangle targetRectangle, Rectangle sourceRectangle) { float saturationFactor = this.saturation / 100f; // Stop at -1 to prevent inversion. saturationFactor++; // The matrix is set up to "shear" the colour space using the following set of values. // Note that each colour component has an effective luminance which contributes to the // overall brightness of the pixel. // See http://graficaobscura.com/matrix/index.html float saturationComplement = 1.0f - saturationFactor; float saturationComplementR = 0.3086f * saturationComplement; float saturationComplementG = 0.6094f * saturationComplement; float saturationComplementB = 0.0820f * saturationComplement; Matrix4x4 matrix4X4 = new Matrix4x4() { M11 = saturationComplementR + saturationFactor, M12 = saturationComplementR, M13 = saturationComplementR, M21 = saturationComplementG, M22 = saturationComplementG + saturationFactor, M23 = saturationComplementG, M31 = saturationComplementB, M32 = saturationComplementB, M33 = saturationComplementB + saturationFactor, }; this.matrix = matrix4X4; }
/// <inheritdoc/> protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) { float threshold = this.Value; Color upper = this.UpperColor; Color lower = this.LowerColor; int sourceY = sourceRectangle.Y; int sourceBottom = sourceRectangle.Bottom; int startX = sourceRectangle.X; int endX = sourceRectangle.Right; Parallel.For( startY, endY, y => { if (y >= sourceY && y < sourceBottom) { for (int x = startX; x < endX; x++) { Color color = source[x, y]; // Any channel will do since it's greyscale. target[x, y] = color.B >= threshold ? upper : lower; } this.OnRowProcessed(); } }); }
/// <inheritdoc/> public void Encode(ImageBase image, Stream stream) { Guard.NotNull(image, nameof(image)); Guard.NotNull(stream, nameof(stream)); int imageWidth = image.Width; int imageHeight = image.Height; SampleRow[] rows = new SampleRow[imageHeight]; Parallel.For( 0, imageHeight, y => { byte[] samples = new byte[imageWidth * 3]; for (int x = 0; x < imageWidth; x++) { Bgra32 color = Color.ToNonPremultiplied(image[x, y]); int start = x * 3; samples[start] = color.R; samples[start + 1] = color.G; samples[start + 2] = color.B; } rows[y] = new SampleRow(samples, imageWidth, 8, 3); }); using (JpegImage jpg = new JpegImage(rows, Colorspace.RGB)) { jpg.WriteJpeg(stream, new CompressionParameters { Quality = this.Quality }); } }
/// <inheritdoc/> protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) { float brightness = this.Value / 100f; int sourceY = sourceRectangle.Y; int sourceBottom = sourceRectangle.Bottom; int startX = sourceRectangle.X; int endX = sourceRectangle.Right; Parallel.For( startY, endY, y => { if (y >= sourceY && y < sourceBottom) { for (int x = startX; x < endX; x++) { Color color = Color.Expand(source[x, y]); Vector3 vector3 = color.ToVector3(); vector3 += new Vector3(brightness); target[x, y] = Color.Compress(new Color(vector3, color.A)); } this.OnRowProcessed(); } }); }
/// <inheritdoc/> protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) { float alpha = this.Value / 100f; int sourceY = sourceRectangle.Y; int sourceBottom = sourceRectangle.Bottom; int startX = sourceRectangle.X; int endX = sourceRectangle.Right; Vector4 alphaVector = new Vector4(1, 1, 1, alpha); Parallel.For( startY, endY, y => { if (y >= sourceY && y < sourceBottom) { for (int x = startX; x < endX; x++) { Vector4 color = Color.ToNonPremultiplied(source[x, y]).ToVector4(); color *= alphaVector; target[x, y] = Color.FromNonPremultiplied(new Color(color)); } this.OnRowProcessed(); } }); }
public override QuantizedImage Quantize(ImageBase image, int maxColors) { colors = NumUtils.Clamp(maxColors, 1, 255); if (octree == null){ octree = new Octree(GetBitsNeededForColorDepth(maxColors)); } return base.Quantize(image, maxColors); }
public void Encode(ImageBase image, Stream stream) { JpegEncoderCore encode = new JpegEncoderCore(); if (subsampleSet){ encode.Encode(image, stream, Quality, Subsample); } else{ encode.Encode(image, stream, Quality, Quality >= 80 ? JpegSubsample.Ratio444 : JpegSubsample.Ratio420); } }
/// <summary> /// Applies the process to the specified portion of the specified <see cref="ImageBase"/> at the specified location /// and with the specified size. /// </summary> /// <param name="target">Target image to apply the process to.</param> /// <param name="source">The source image. Cannot be null.</param> /// <param name="sourceRectangle"> /// The <see cref="Rectangle"/> structure that specifies the portion of the image object to draw. /// </param> /// <param name="startY">The index of the row within the source image to start processing.</param> /// <param name="endY">The index of the row within the source image to end processing.</param> /// <param name="kernel">The kernel operator.</param> private void ApplyConvolution( ImageBase target, ImageBase source, Rectangle sourceRectangle, int startY, int endY, float[,] kernel) { int kernelHeight = kernel.GetLength(0); int kernelWidth = kernel.GetLength(1); int radiusY = kernelHeight >> 1; int radiusX = kernelWidth >> 1; int sourceY = sourceRectangle.Y; int sourceBottom = sourceRectangle.Bottom; int startX = sourceRectangle.X; int endX = sourceRectangle.Right; int maxY = sourceBottom - 1; int maxX = endX - 1; Parallel.For( startY, endY, y => { if (y >= sourceY && y < sourceBottom) { for (int x = startX; x < endX; x++) { Color destination = new Color(); // Apply each matrix multiplier to the color components for each pixel. for (int fy = 0; fy < kernelHeight; fy++) { int fyr = fy - radiusY; int offsetY = y + fyr; offsetY = offsetY.Clamp(0, maxY); for (int fx = 0; fx < kernelWidth; fx++) { int fxr = fx - radiusX; int offsetX = x + fxr; offsetX = offsetX.Clamp(0, maxX); Color currentColor = source[offsetX, offsetY]; destination += kernel[fy, fx] * currentColor; } } target[x, y] = destination; } this.OnRowProcessed(); } }); }
/// <inheritdoc/> protected override void AfterApply(ImageBase source, ImageBase target, Rectangle targetRectangle, Rectangle sourceRectangle) { new Vignette { Color = new Color(102 / 255f, 34 / 255f, 0) }.Apply(target, target, targetRectangle); new Glow { Color = new Color(1, 153 / 255f, 102 / 255f, .7f), RadiusX = target.Width / 4f, RadiusY = target.Width / 4f } .Apply(target, target, targetRectangle); }
/// <inheritdoc/> protected override void OnApply(ImageBase source, ImageBase target, Rectangle targetRectangle, Rectangle sourceRectangle) { if (this.kernelY == null) { this.kernelY = this.CreateBoxKernel(false); } if (this.kernelX == null) { this.kernelX = this.CreateBoxKernel(true); } }
public OAMEditor(XElement langxml, Bank bank, SpriteBase sprite, ImageBase image, PaletteBase palette) { InitializeComponent(); this.bank = bank; numOAM.Maximum = bank.oams.Length - 1; preview = true; this.sprite = sprite; this.image = image; this.palette = palette; Read_Language(langxml); }
/// <summary> /// Execute the first pass through the pixels in the image /// </summary> /// <param name="source">The source data</param> /// <param name="width">The width in pixels of the image.</param> /// <param name="height">The height in pixels of the image.</param> protected virtual void FirstPass(ImageBase source, int width, int height) { // Loop through each row for (int y = 0; y < height; y++) { // And loop through each column for (int x = 0; x < width; x++) { // Now I have the pixel, call the FirstPassQuantize function... this.InitialQuantizePixel(source[x, y]); } } }
public QuantizedImage Quantize(ImageBase image, int maxColors) { if (image == null){ throw new ArgumentNullException(); } int colorCount = NumUtils.Clamp(maxColors,1, 256); Clear(); using (IPixelAccessor imagePixels = image.Lock()){ Build3DHistogram(imagePixels); Get3DMoments(); Box[] cube; BuildCube(out cube, ref colorCount); return GenerateResult(imagePixels, colorCount, cube); } }
/// <inheritdoc/> protected override void Apply( ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) { float[,] kernelX = this.KernelX; float[,] kernelY = this.KernelY; ImageBase firstPass = new Image(source.Width, source.Height); this.ApplyConvolution(firstPass, source, sourceRectangle, startY, endY, kernelX); this.ApplyConvolution(target, firstPass, sourceRectangle, startY, endY, kernelY); }
public void Apply(ImageBase target, ImageBase source, Rectangle rectangle) { for (int y = rectangle.Y; y < rectangle.Bottom; y++) { for (int x = rectangle.X; x < rectangle.Right; x++) { Color color = source[x, y]; color.R = (byte)(255 - color.R); color.G = (byte)(255 - color.G); color.B = (byte)(255 - color.B); target[x, y] = color; } } }
public OAMEditor(string langxml, Bank bank, SpriteBase sprite, ImageBase image, PaletteBase palette) { InitializeComponent(); this.bank = bank; numOAM.Maximum = bank.oams.Length - 1; numOffset.Maximum = (bank.data_size == 0) ? image.Tiles.Length / (0x20 << (int)sprite.BlockSize) - 1 : bank.data_size / (0x20 << (int)sprite.BlockSize) - 1; preview = true; this.sprite = sprite; this.image = image; this.palette = palette; Read_Language(langxml); }
/// <inheritdoc/> public void Encode(ImageBase image, Stream stream) { Guard.NotNull(image, nameof(image)); Guard.NotNull(stream, nameof(stream)); int rowWidth = image.Width; int amount = (image.Width * 3) % 4; if (amount != 0) { rowWidth += 4 - amount; } using (BinaryWriter writer = new BinaryWriter(stream)) { BmpFileHeader fileHeader = new BmpFileHeader { Type = 19778, // BM Offset = 54, FileSize = 54 + (image.Height * rowWidth * 3) }; WriteHeader(writer, fileHeader); BmpInfoHeader infoHeader = new BmpInfoHeader { HeaderSize = 40, Height = image.Height, Width = image.Width, BitsPerPixel = 24, Planes = 1, Compression = BmpCompression.RGB, ImageSize = image.Height * rowWidth * 3, ClrUsed = 0, ClrImportant = 0 }; WriteInfo(writer, infoHeader); this.WriteImage(writer, image); writer.Flush(); } }
public void Apply(ImageBase target, ImageBase source, Rectangle rectangle) { byte temp = 0; for (int y = rectangle.Y; y < rectangle.Bottom; y++) { for (int x = rectangle.X; x < rectangle.Right; x++) { Color color = source[x, y]; temp = (byte)(color.R * _cr + color.G * _cg + color.B * _cb); color.R = temp; color.G = temp; color.B = temp; target[x, y] = color; } } }
public void Apply(ImageBase target, ImageBase source, Rectangle rectangle) { byte temp = 0; for (int y = rectangle.Y; y < rectangle.Bottom; y++) { for (int x = rectangle.X; x < rectangle.Right; x++) { Color color = source[x, y]; temp = (byte)(0.299 * color.R + 0.587 * color.G + 0.114 * color.B); color.R = (byte)((temp > 206) ? 255 : temp + 49); color.G = (byte)((temp < 14) ? 0 : temp - 14); color.B = (byte)((temp < 56) ? 0 : temp - 56); target[x, y] = color; } } }
public void Encode(ImageBase image, Stream stream, BmpBitsPerPixel bitsPerPixel) { if (image == null || stream == null) { throw new ArgumentNullException(); } bmpBitsPerPixel = bitsPerPixel; int rowWidth = image.Width; // TODO: Check this for varying file formats. int amount = (image.Width * (int)bmpBitsPerPixel) % 4; if (amount != 0) { rowWidth += 4 - amount; } // Do not use IDisposable pattern here as we want to preserve the stream. EndianBinaryWriter writer = new EndianBinaryWriter(EndianBitConverter.Little, stream); int bpp = (int)bmpBitsPerPixel; BmpFileHeader fileHeader = new BmpFileHeader { Type = 19778, // BM Offset = 54, FileSize = 54 + image.Height * rowWidth * bpp }; BmpInfoHeader infoHeader = new BmpInfoHeader { HeaderSize = 40, Height = image.Height, Width = image.Width, BitsPerPixel = (short)(8 * bpp), Planes = 1, ImageSize = image.Height * rowWidth * bpp, ClrUsed = 0, ClrImportant = 0 }; WriteHeader(writer, fileHeader); WriteInfo(writer, infoHeader); WriteImage(writer, image); writer.Flush(); }
/// <summary> /// Writes the graphics control extension to the stream. /// </summary> /// <typeparam name="T">The pixel format.</typeparam> /// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam> /// <param name="image">The <see cref="ImageBase{T,TP}"/> to encode.</param> /// <param name="writer">The stream to write to.</param> /// <param name="transparencyIndex">The index of the color in the color palette to make transparent.</param> private void WriteGraphicalControlExtension <T, TP>(ImageBase <T, TP> image, EndianBinaryWriter writer, int transparencyIndex) where T : IPackedVector <TP> where TP : struct { // TODO: Check transparency logic. bool hasTransparent = transparencyIndex > -1; DisposalMethod disposalMethod = hasTransparent ? DisposalMethod.RestoreToBackground : DisposalMethod.Unspecified; GifGraphicsControlExtension extension = new GifGraphicsControlExtension() { DisposalMethod = disposalMethod, TransparencyFlag = hasTransparent, TransparencyIndex = transparencyIndex, DelayTime = image.FrameDelay }; // Reduce the number of writes. byte[] intro = { GifConstants.ExtensionIntroducer, GifConstants.GraphicControlLabel, 4 // Size }; writer.Write(intro); PackedField field = new PackedField(); field.SetBits(3, 3, (int)extension.DisposalMethod); // 1-3 : Reserved, 4-6 : Disposal // TODO: Allow this as an option. field.SetBit(6, false); // 7 : User input - 0 = none field.SetBit(7, extension.TransparencyFlag); // 8: Has transparent. writer.Write(field.Byte); writer.Write((ushort)extension.DelayTime); writer.Write((byte)(extension.TransparencyIndex == -1 ? 255 : extension.TransparencyIndex)); writer.Write(GifConstants.Terminator); }
public void Apply(ImageBase target, ImageBase source, Rectangle rectangle) { double pixel = 0, contrast = (100.0 + _contrast) / 100.0; for (int y = rectangle.Y; y < rectangle.Bottom; y++) { for (int x = rectangle.X; x < rectangle.Right; x++) { Color color = source[x, y]; pixel = color.R / 255.0; pixel -= 0.5; pixel *= contrast; pixel += 0.5; pixel *= 255; pixel = pixel.RemainBetween(0, 255); color.R = (byte)pixel; pixel = color.G / 255.0; pixel -= 0.5; pixel *= contrast; pixel += 0.5; pixel *= 255; pixel = pixel.RemainBetween(0, 255); color.G = (byte)pixel; pixel = color.B / 255.0; pixel -= 0.5; pixel *= contrast; pixel += 0.5; pixel *= 255; pixel = pixel.RemainBetween(0, 255); color.B = (byte)pixel; target[x, y] = color; } } }
/// <inheritdoc/> public virtual QuantizedImage <TColor> Quantize(ImageBase <TColor> image, int maxColors) { Guard.NotNull(image, nameof(image)); // Get the size of the source image int height = image.Height; int width = image.Width; byte[] quantizedPixels = new byte[width * height]; TColor[] colorPalette; using (PixelAccessor <TColor> pixels = image.Lock()) { // Call the FirstPass function if not a single pass algorithm. // For something like an Octree quantizer, this will run through // all image pixels, build a data structure, and create a palette. if (!this.singlePass) { this.FirstPass(pixels, width, height); } // Collect the palette. Required before the second pass runs. colorPalette = this.GetPalette(); if (this.Dither) { // We clone the image as we don't want to alter the original. using (Image <TColor> clone = new Image <TColor>(image)) using (PixelAccessor <TColor> clonedPixels = clone.Lock()) { this.SecondPass(clonedPixels, quantizedPixels, width, height); } } else { this.SecondPass(pixels, quantizedPixels, width, height); } } return(new QuantizedImage <TColor>(width, height, colorPalette, quantizedPixels)); }
/// <inheritdoc/> protected override void OnApply(ImageBase <TPixel> source, Rectangle sourceRectangle) { using (ImageBase <TPixel> temp = new Image <TPixel>(source)) { // Detect the edges. new SobelProcessor <TPixel>().Apply(temp, sourceRectangle); // Apply threshold binarization filter. new BinaryThresholdProcessor <TPixel>(this.Value).Apply(temp, sourceRectangle); // Search for the first white pixels Rectangle rectangle = ImageMaths.GetFilteredBoundingRectangle(temp, 0); if (rectangle == sourceRectangle) { return; } new CropProcessor <TPixel>(rectangle).Apply(source, sourceRectangle); } }
public override async Task <ImageBase> CacheHeroImage() { ImageBase img = null; int width = -1; foreach (ImageBase image in Images.FindAll(i => i.ImageType == SDK.Images.ImageType.Hero)) { if (image.Width > width) { img = image; width = image.Width; } } img ??= (await GetScreenshots()).FirstOrDefault(); if (InternalPackage != null) { InternalPackage.HeroImageCache = img; } return(img); }
/// <summary> /// Encodes the image to the specified stream from the <see cref="ImageBase{TPixel}"/>. /// </summary> /// <typeparam name="TPixel">The pixel format.</typeparam> /// <param name="image">The <see cref="ImageBase{TPixel}"/> to encode from.</param> /// <param name="stream">The <see cref="Stream"/> to encode the image data to.</param> public void Encode <TPixel>(ImageBase <TPixel> image, Stream stream) where TPixel : struct, IPixel <TPixel> { Guard.NotNull(image, nameof(image)); Guard.NotNull(stream, nameof(stream)); // Cast to int will get the bytes per pixel short bpp = (short)(8 * (int)this.bitsPerPixel); int bytesPerLine = 4 * (((image.Width * bpp) + 31) / 32); this.padding = bytesPerLine - (image.Width * (int)this.bitsPerPixel); // Do not use IDisposable pattern here as we want to preserve the stream. EndianBinaryWriter writer = new EndianBinaryWriter(Endianness.LittleEndian, stream); BmpInfoHeader infoHeader = new BmpInfoHeader { HeaderSize = BmpInfoHeader.Size, Height = image.Height, Width = image.Width, BitsPerPixel = bpp, Planes = 1, ImageSize = image.Height * bytesPerLine, ClrUsed = 0, ClrImportant = 0 }; BmpFileHeader fileHeader = new BmpFileHeader { Type = 19778, // BM Offset = 54, FileSize = 54 + infoHeader.ImageSize }; WriteHeader(writer, fileHeader); this.WriteInfo(writer, infoHeader); this.WriteImage(writer, image); writer.Flush(); }
protected override void Apply(ImageBase target, ImageBase source, Rectangle rectangle, int startY, int endY) { var radius = Radius >= 0 ? Radius : Math.Min(rectangle.Width, rectangle.Height) * 0.5; var radiusSq = radius * radius; var centerX = (rectangle.Left + rectangle.Right) * 0.5; var centerY = (rectangle.Top + rectangle.Bottom) * 0.5; var count = offsetsX.Length; var inc = 1.0 / count; for (int y = startY; y < endY; y++) { for (int x = rectangle.X; x < rectangle.Right; x++) { var a = 0.0; var color = source[x, y]; for (var i = 0; i < count; i++) { var cx = (x + offsetsX[i] - centerX); var cy = (y + offsetsY[i] - centerY); if (radiusSq > cx * cx + cy * cy) { a += inc; } } if (a < 1.0) { color = new Color( (byte)(color.R), (byte)(color.G), (byte)(color.B), (byte)(a * color.A)); } target[x, y] = color; } } }
/// <inheritdoc/> protected override void OnApply(ImageBase <TColor, TPacked> source, Rectangle sourceRectangle) { if (this.Image.Bounds.Size != this.Size) { this.Image = this.Image.Resize(this.Size.Width, this.Size.Height); } // Align start/end positions. Rectangle bounds = this.Image.Bounds; int minX = Math.Max(this.Location.X, sourceRectangle.X); int maxX = Math.Min(this.Location.X + bounds.Width, sourceRectangle.Width); int minY = Math.Max(this.Location.Y, sourceRectangle.Y); int maxY = Math.Min(this.Location.Y + bounds.Height, sourceRectangle.Bottom); float alpha = this.Alpha / 100F; using (PixelAccessor <TColor, TPacked> toBlendPixels = this.Image.Lock()) using (PixelAccessor <TColor, TPacked> sourcePixels = source.Lock()) { Parallel.For( minY, maxY, this.ParallelOptions, y => { for (int x = minX; x < maxX; x++) { Vector4 backgroundVector = sourcePixels[x, y].ToVector4(); Vector4 sourceVector = toBlendPixels[x - minX, y - minY].ToVector4(); // Lerping colors is dependent on the alpha of the blended color backgroundVector = Vector4BlendTransforms.PremultipliedLerp(backgroundVector, sourceVector, alpha); TColor packed = default(TColor); packed.PackFromVector4(backgroundVector); sourcePixels[x, y] = packed; } }); } }
public void Apply(ImageBase target, ImageBase source, Rectangle rectangle) { // Make sure we stop combining when the whole image that should be combined has been processed. if (rectangle.Right > _blendedImage.PixelWidth) { rectangle.Width = _blendedImage.PixelWidth - rectangle.Left; } if (rectangle.Bottom > _blendedImage.PixelHeight) { rectangle.Height = _blendedImage.PixelHeight - rectangle.Top; } for (int y = rectangle.Y; y < rectangle.Bottom; y++) { for (int x = rectangle.X; x < rectangle.Right; x++) { Color color = source[x, y], blendedColor = _blendedImage[x, y]; // combining colors is dependent o the alpha of the blended color double alphaFactor = GlobalAlphaFactor != null ? GlobalAlphaFactor.Value : blendedColor.A / 255.0; double invertedAlphaFactor = 1 - alphaFactor; int r = (int) (color.R * invertedAlphaFactor) + (int) (blendedColor.R * alphaFactor); int g = (int) (color.G * invertedAlphaFactor) + (int) (blendedColor.G * alphaFactor); int b = (int) (color.B * invertedAlphaFactor) + (int) (blendedColor.B * alphaFactor); r = r.RemainBetween(0, 255); g = g.RemainBetween(0, 255); b = b.RemainBetween(0, 255); color.R = (byte)r; color.G = (byte)g; color.B = (byte)b; target[x, y] = color; } } }
/// <summary> /// Encodes the data of the specified image and writes the result to /// the specified stream. /// </summary> /// <param name="image">The image, where the data should be get from. /// Cannot be null (Nothing in Visual Basic).</param> /// <param name="stream">The stream, where the image data should be written to. /// Cannot be null (Nothing in Visual Basic).</param> /// <exception cref="ArgumentNullException"> /// <para><paramref name="image"/> is null (Nothing in Visual Basic).</para> /// <para>- or -</para> /// <para><paramref name="stream"/> is null (Nothing in Visual Basic).</para> /// </exception> public void Encode(ImageBase image, Stream stream) { Guard.NotNull(image, "image"); Guard.NotNull(stream, "stream"); int rowWidth = image.PixelWidth; int amount = (image.PixelWidth * 3) % 4; if (amount != 0) { rowWidth += 4 - amount; } BinaryWriter writer = new BinaryWriter(stream); BmpFileHeader fileHeader = new BmpFileHeader(); fileHeader.Type = 19778; fileHeader.Offset = 54; fileHeader.FileSize = 54 + image.PixelHeight * rowWidth * 3; Write(writer, fileHeader); BmpInfoHeader infoHeader = new BmpInfoHeader(); infoHeader.HeaderSize = 40; infoHeader.Height = image.PixelHeight; infoHeader.Width = image.PixelWidth; infoHeader.BitsPerPixel = 24; infoHeader.Planes = 1; infoHeader.Compression = BmpCompression.RGB; infoHeader.ImageSize = image.PixelHeight * rowWidth * 3; infoHeader.ClrUsed = 0; infoHeader.ClrImportant = 0; Write(writer, infoHeader); WriteImage(writer, image); writer.Flush(); }
public void Apply(ImageBase target, ImageBase source, Rectangle rectangle) { PrepareFilter(); if (_filter != null) { int filterSize = _filter.GetLength(0); for (int y = rectangle.Y; y < rectangle.Bottom; y++) { for (int x = rectangle.X; x < rectangle.Right; x++) { double r = 0, g = 0, b = 0; Color color = source[x, y]; for (int filterY = 0; filterY < filterSize; filterY++) { for (int filterX = 0; filterX < filterSize; filterX++) { int imageX = (x - filterSize / 2 + filterX + rectangle.Width) % rectangle.Width; int imageY = (y - filterSize / 2 + filterY + rectangle.Height) % rectangle.Height; Color tempColor = source[imageX, imageY]; r += tempColor.R * _filter[filterX, filterY]; g += tempColor.G * _filter[filterX, filterY]; b += tempColor.B * _filter[filterX, filterY]; } } color.R = (byte)(_factor * r + _bias).RemainBetween(0, 255); color.G = (byte)(_factor * g + _bias).RemainBetween(0, 255); color.B = (byte)(_factor * b + _bias).RemainBetween(0, 255); target[x, y] = color; } } } }
public void Apply(ImageBase target, ImageBase source, Rectangle rectangle) { // Make sure we stop combining when the whole image that should be combined has been processed. if (rectangle.Right > _blendedImage.PixelWidth) { rectangle.Width = _blendedImage.PixelWidth - rectangle.Left; } if (rectangle.Bottom > _blendedImage.PixelHeight) { rectangle.Height = _blendedImage.PixelHeight - rectangle.Top; } for (int y = rectangle.Y; y < rectangle.Bottom; y++) { for (int x = rectangle.X; x < rectangle.Right; x++) { Color color = source[x, y], blendedColor = _blendedImage[x, y]; // combining colors is dependent o the alpha of the blended color double alphaFactor = GlobalAlphaFactor != null ? GlobalAlphaFactor.Value : blendedColor.A / 255.0; double invertedAlphaFactor = 1 - alphaFactor; int r = (int)(color.R * invertedAlphaFactor) + (int)(blendedColor.R * alphaFactor); int g = (int)(color.G * invertedAlphaFactor) + (int)(blendedColor.G * alphaFactor); int b = (int)(color.B * invertedAlphaFactor) + (int)(blendedColor.B * alphaFactor); r = r.RemainBetween(0, 255); g = g.RemainBetween(0, 255); b = b.RemainBetween(0, 255); color.R = (byte)r; color.G = (byte)g; color.B = (byte)b; target[x, y] = color; } } }
/// <summary> /// Encodes the data of the specified image and writes the result to /// the specified stream. /// </summary> /// <param name="image">The image, where the data should be get from. /// Cannot be null (Nothing in Visual Basic).</param> /// <param name="stream">The stream, where the image data should be written to. /// Cannot be null (Nothing in Visual Basic).</param> /// <exception cref="ArgumentNullException"> /// <para><paramref name="image"/> is null (Nothing in Visual Basic).</para> /// <para>- or -</para> /// <para><paramref name="stream"/> is null (Nothing in Visual Basic).</para> /// </exception> public void Encode(ImageBase image, Stream stream) { Guard.NotNull(image, "image"); Guard.NotNull(stream, "stream"); // Write the png header. stream.Write( new byte[] { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A }, 0, 8); PngHeader header = new PngHeader(); header.Width = image.PixelWidth; header.Height = image.PixelHeight; header.ColorType = 6; header.BitDepth = 8; header.FilterMethod = 0; header.CompressionMethod = 0; header.InterlaceMethod = 0; WriteHeaderChunk(stream, header); WritePhysicsChunk(stream, image); WriteGammaChunk(stream); if (IsWritingUncompressed) { WriteDataChunksFast(stream, image); } else { WriteDataChunks(stream, image); } WriteEndChunk(stream); stream.Flush(); }
public void FileSave(ImageBase model, Context context) { var imagList = Request.Form["FileList"]; if (string.IsNullOrEmpty(imagList)) { return; } model.FileList = Newtonsoft.Json.JsonConvert.DeserializeObject <List <FileModel> >(imagList); var type = model.FileList.Select(x => new { x.Type, x.SubType }).Distinct().ToList(); List <Pictures> a = new List <Pictures>(); foreach (var item in type) { var fileList = context.Pictures.Where(x => x.RecordType == item.Type && x.RecordType2 == item.SubType && (x.RelationId == model.Id || x.RelationId == Guid.Empty)); a.AddRange(fileList); } //Silinecekler var del = a.Where(x => model.FileList.Any(t => t.IsDeleted && t.Id == x.Id)).ToList(); //dataDelete context.Pictures.RemoveRange(del); //Update var update = a.Where(x => model.FileList.Any(t => !t.IsDeleted && x.Id == t.Id)).ToList(); foreach (var item in update) { var f = model.FileList.FirstOrDefault(x => x.Id == item.Id); if (item.RelationId == Guid.Empty) { item.RelationId = model.Id; } item.RecordType2 = f.SubType; item.Title = f.Title; } context.Pictures.UpdateRange(update); }
/// <inheritdoc/> public void Encode(ImageBase imageBase, Stream stream) { Guard.NotNull(imageBase, nameof(imageBase)); Guard.NotNull(stream, nameof(stream)); Image image = (Image)imageBase; // Write the header. // File Header signature and version. this.WriteString(stream, GifConstants.FileType); this.WriteString(stream, GifConstants.FileVersion); // Calculate the quality. int quality = this.Quality > 0 ? this.Quality : imageBase.Quality; quality = quality > 0 ? quality.Clamp(1, 256) : 256; // Get the number of bits. int bitDepth = this.GetBitsNeededForColorDepth(quality); // Write the LSD and check to see if we need a global color table. // Always true just now. this.WriteGlobalLogicalScreenDescriptor(image, stream, bitDepth); QuantizedImage quantized = this.WriteColorTable(imageBase, stream, quality, bitDepth); this.WriteGraphicalControlExtension(imageBase, stream); this.WriteImageDescriptor(quantized, quality, stream); if (image.Frames.Any()) { this.WriteApplicationExtension(stream, image.RepeatCount, image.Frames.Count); foreach (ImageFrame frame in image.Frames) { this.WriteGraphicalControlExtension(frame, stream); this.WriteFrameImageDescriptor(frame, stream); } } // TODO: Write Comments extension etc this.WriteByte(stream, GifConstants.EndIntroducer); }
/// <inheritdoc/> protected override void OnApply(ImageBase <TColor, TPacked> source, Rectangle sourceRectangle) { ImageBase <TColor, TPacked> temp = new Image <TColor, TPacked>(source.Width, source.Height); temp.ClonePixels(source.Width, source.Height, source.Pixels); // Detect the edges. new SobelProcessor <TColor, TPacked>().Apply(temp, sourceRectangle); // Apply threshold binarization filter. new BinaryThresholdProcessor <TColor, TPacked>(this.Value).Apply(temp, sourceRectangle); // Search for the first white pixels Rectangle rectangle = ImageMaths.GetFilteredBoundingRectangle(temp, 0); if (rectangle == sourceRectangle) { return; } new CropProcessor <TColor, TPacked>(rectangle).Apply(source, sourceRectangle); }
public virtual QuantizedImage Quantize(ImageBase image, int maxColors) { if (image == null) { throw new ArgumentNullException(); } int height = image.Height; int width = image.Width; byte[] quantizedPixels = new byte[width * height]; List <Color2> palette; using (IPixelAccessor pixels = image.Lock()){ if (!singlePass) { FirstPass(pixels, width, height); } palette = GetPalette(); SecondPass(pixels, quantizedPixels, width, height); } return(new QuantizedImage(width, height, palette.ToArray(), quantizedPixels, TransparentIndex)); }
/// <summary> /// Writes the physical dimension information to the stream. /// </summary> /// <typeparam name="T">The pixel format.</typeparam> /// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam> /// <param name="stream">The <see cref="Stream"/> containing image data.</param> /// <param name="imageBase">The image base.</param> private void WritePhysicalChunk <T, TP>(Stream stream, ImageBase <T, TP> imageBase) where T : IPackedVector <TP> where TP : struct { Image <T, TP> image = imageBase as Image <T, TP>; if (image != null && image.HorizontalResolution > 0 && image.VerticalResolution > 0) { // 39.3700787 = inches in a meter. int dpmX = (int)Math.Round(image.HorizontalResolution * 39.3700787D); int dpmY = (int)Math.Round(image.VerticalResolution * 39.3700787D); byte[] chunkData = new byte[9]; WriteInteger(chunkData, 0, dpmX); WriteInteger(chunkData, 4, dpmY); chunkData[8] = 1; this.WriteChunk(stream, PngChunkTypes.Physical, chunkData); } }
private void WriteImage(EndianBinaryWriter writer, ImageBase image) { // TODO: Add more compression formats. int amount = (image.Width * (int)bmpBitsPerPixel) % 4; if (amount != 0) { amount = 4 - amount; } using (IPixelAccessor pixels = image.Lock()){ switch (bmpBitsPerPixel) { case BmpBitsPerPixel.Pixel32: Write32bit(writer, pixels, amount); break; case BmpBitsPerPixel.Pixel24: Write24bit(writer, pixels, amount); break; } } }
/// <inheritdoc/> protected override void OnApply(ImageBase <TPixel> source, Rectangle sourceRectangle) { int startY = sourceRectangle.Y; int endY = sourceRectangle.Bottom; int startX = sourceRectangle.X; int endX = sourceRectangle.Right; // Align start/end positions. int minX = Math.Max(0, startX); int maxX = Math.Min(source.Width, endX); int minY = Math.Max(0, startY); int maxY = Math.Min(source.Height, endY); // Reset offset if necessary. if (minX > 0) { startX = 0; } if (minY > 0) { startY = 0; } using (PixelAccessor <TPixel> sourcePixels = source.Lock()) { for (int y = minY; y < maxY; y++) { int offsetY = y - startY; for (int x = minX; x < maxX; x++) { int offsetX = x - startX; TPixel sourceColor = sourcePixels[offsetX, offsetY]; TPixel transformedColor = sourceColor.ToVector4().X >= this.Threshold ? this.UpperColor : this.LowerColor; this.Diffuser.Dither(sourcePixels, sourceColor, transformedColor, offsetX, offsetY, maxX, maxY); } } } }
/// <inheritdoc/> protected override void OnApply(ImageBase <TPixel> source, Rectangle sourceRectangle) { int startY = sourceRectangle.Y; int endY = sourceRectangle.Bottom; int startX = sourceRectangle.X; int endX = sourceRectangle.Right; // Align start/end positions. int minX = Math.Max(0, startX); int maxX = Math.Min(source.Width, endX); int minY = Math.Max(0, startY); int maxY = Math.Min(source.Height, endY); // Reset offset if necessary. if (minX > 0) { startX = 0; } if (minY > 0) { startY = 0; } byte[] bytes = new byte[4]; for (int y = minY; y < maxY; y++) { int offsetY = y - startY; Span <TPixel> row = source.GetRowSpan(offsetY); for (int x = minX; x < maxX; x++) { int offsetX = x - startX; TPixel sourceColor = row[offsetX]; this.Dither.Dither(source, sourceColor, this.UpperColor, this.LowerColor, bytes, this.Index, offsetX, offsetY, maxX, maxY); } } }
/// <inheritdoc/> protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) { int sourceY = sourceRectangle.Y; int sourceBottom = sourceRectangle.Bottom; int startX = sourceRectangle.X; int endX = sourceRectangle.Right; Rectangle bounds = this.toBlend.Bounds; float alpha = this.Value / 100f; Parallel.For( startY, endY, y => { if (y >= sourceY && y < sourceBottom) { for (int x = startX; x < endX; x++) { Color color = source[x, y]; if (bounds.Contains(x, y)) { Color blendedColor = this.toBlend[x, y]; if (blendedColor.A > 0) { // Lerping colors is dependent on the alpha of the blended color float alphaFactor = alpha > 0 ? alpha : blendedColor.A; color = Color.Lerp(color, blendedColor, alphaFactor); } } target[x, y] = color; } this.OnRowProcessed(); } }); }
protected override void Apply(ImageBase target, ImageBase source, Rectangle rectangle, int startY, int endY) { if (UseHsbSpace) { HsbColor tint = HsbColor.FromRgb(TintColor); for (int y = startY; y < endY; y++) { for (int x = rectangle.X; x < rectangle.Right; x++) { Color color = source[x, y]; HsbColor hsb = HsbColor.FromRgb(color); hsb.H = tint.H; hsb.A *= tint.A; target[x, y] = hsb.ToRgb(); } } } else { for (int y = startY; y < endY; y++) { for (int x = rectangle.X; x < rectangle.Right; x++) { Color color = source[x, y]; target[x, y] = new Color( r: (byte)(color.R * TintColor.R / 255), g: (byte)(color.G * TintColor.G / 255), b: (byte)(color.B * TintColor.B / 255), a: color.A); } } } }
/// <summary> /// Collects the grayscale pixel data. /// </summary> /// <typeparam name="T">The pixel format.</typeparam> /// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam> /// <param name="image">The image to encode.</param> private void CollectGrayscaleBytes <T, TP>(ImageBase <T, TP> image) where T : IPackedVector <TP> where TP : struct { // Copy the pixels across from the image. this.pixelData = new byte[this.width * this.height * this.bytesPerPixel]; int stride = this.width * this.bytesPerPixel; using (IPixelAccessor <T, TP> pixels = image.Lock()) { Parallel.For( 0, this.height, Bootstrapper.Instance.ParallelOptions, y => { for (int x = 0; x < this.width; x++) { // Convert the color to YCbCr and store the luminance // Optionally store the original color alpha. int dataOffset = (y * stride) + (x * this.bytesPerPixel); Color source = new Color(pixels[x, y].ToVector4()); YCbCr luminance = source; for (int i = 0; i < this.bytesPerPixel; i++) { if (i == 0) { this.pixelData[dataOffset] = ((byte)luminance.Y).Clamp(0, 255); } else { this.pixelData[dataOffset + i] = source.A; } } } }); } }
/// <summary> /// Rotates the image 180 degrees clockwise at the centre point. /// </summary> /// <param name="target">The target image.</param> /// <param name="source">The source image.</param> private void Rotate180(ImageBase <TColor, TPacked> target, ImageBase <TColor, TPacked> source) { int width = source.Width; int height = source.Height; using (PixelAccessor <TColor, TPacked> sourcePixels = source.Lock()) using (PixelAccessor <TColor, TPacked> targetPixels = target.Lock()) { Parallel.For( 0, height, this.ParallelOptions, y => { for (int x = 0; x < width; x++) { int newX = width - x - 1; int newY = height - y - 1; targetPixels[newX, newY] = sourcePixels[x, y]; } }); } }
public static WriteableBitmap ToBitmap(ImageBase image) { Guard.NotNull(image, "image"); var bitmap = new WriteableBitmap(image.PixelWidth, image.PixelHeight); ImageBase temp = image; byte[] pixels = temp.Pixels; int[] raster = bitmap.Pixels; Buffer.BlockCopy(pixels, 0, raster, 0, pixels.Length); for (int i = 0; i < raster.Length; i++) { int abgr = raster[i]; int a = (abgr >> 24) & 0xff; float m = a / 255f; int argb = a << 24 | (int)((abgr & 0xff) * m) << 16 | (int)(((abgr >> 8) & 0xff) * m) << 8 | (int)(((abgr >> 16) & 0xff) * m); raster[i] = argb; } bitmap.Invalidate(); return(bitmap); }
public override void Write(string fileOut, ImageBase image, PaletteBase palette) { BinaryWriter bw = new BinaryWriter(File.OpenWrite(fileOut)); bw.Write(scx.type); bw.Write(scx.unknown1); bw.Write(scx.unknown2); bw.Write(scx.unknown3); bw.Write(scx.unknown4); bw.Write((ushort)Width); bw.Write((ushort)Height); bw.Write(Map.Length * 2); bw.Write(Map.Length * 2); for (int i = 0; i < Map.Length; i++) { bw.Write(Actions.MapInfo(Map[i])); } bw.Flush(); bw.Close(); }
/// <inheritdoc/> public override void Apply(ImageBase <TColor, TPacked> target, ImageBase <TColor, TPacked> source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) { int startX = targetRectangle.X; int endX = targetRectangle.Right; int sourceX = sourceRectangle.X; int sourceY = sourceRectangle.Y; using (PixelAccessor <TColor, TPacked> sourcePixels = source.Lock()) using (PixelAccessor <TColor, TPacked> targetPixels = target.Lock()) { Parallel.For( startY, endY, this.ParallelOptions, y => { for (int x = startX; x < endX; x++) { targetPixels[x, y] = sourcePixels[x + sourceX, y + sourceY]; } }); } }
/// <inheritdoc/> public QuantizedImage Quantize(ImageBase imageBase) { // Get the size of the source image int height = imageBase.Height; int width = imageBase.Width; // Call the FirstPass function if not a single pass algorithm. // For something like an Octree quantizer, this will run through // all image pixels, build a data structure, and create a palette. if (!this.singlePass) { this.FirstPass(imageBase, width, height); } byte[] quantizedPixels = new byte[width * height]; // Get the pallete List<Bgra32> palette = this.GetPalette(); this.SecondPass(imageBase, quantizedPixels, width, height); return new QuantizedImage(width, height, palette.ToArray(), quantizedPixels); }
/// <summary> /// Applies the box filter kernel around one pixel. /// </summary> /// <param name="original">The original image to blur</param> /// <param name="target">The result</param> /// <param name="centerRow">Vertical coordinate of the result pixel</param> /// <param name="centerCol">Horizontal coordinate of the result pixel</param> protected virtual void Kernel(ImageBase original, ImageBase target, int centerRow, int centerCol) { int top = Math.Max(0, centerRow - radius); int bottom = Math.Min(original.Height - 1, centerRow + radius); int left = Math.Max(0, centerCol - radius); int right = Math.Min(original.Width - 1, centerCol + radius); int area = (bottom - top + 1) * (right - left + 1); float normalization = 1.0f / area; for (int chan = 0; chan < original.NumChannels; ++chan) { float result = 0; for (int row = top; row <= bottom; ++row) { for (int col = left; col <= right; ++col) { result += original.GetPixelChannel(col, row, chan) * normalization; } } target.SetPixelChannel(centerCol, centerRow, chan, result); } }
public void Resize(ImageBase source, ImageBase target, int width, int height) { byte[] newPixels = new byte[width * height * 4]; double xFactor = (double)source.PixelWidth / width; double yFactor = (double)source.PixelHeight / height; int dstOffsetLine = 0; int dstOffset = 0; int srcOffsetLine = 0; int srcOffset = 0; byte[] sourcePixels = source.Pixels; for (int y = 0; y < height; y++) { dstOffsetLine = 4 * width * y; // Calculate the line offset at the source image, where the pixels should be get from. srcOffsetLine = 4 * source.PixelWidth * (int)(y * yFactor); for (int x = 0; x < width; x++) { dstOffset = dstOffsetLine + 4 * x; srcOffset = srcOffsetLine + 4 * (int)(x * xFactor); newPixels[dstOffset + 0] = sourcePixels[srcOffset + 0]; newPixels[dstOffset + 1] = sourcePixels[srcOffset + 1]; newPixels[dstOffset + 2] = sourcePixels[srcOffset + 2]; newPixels[dstOffset + 3] = sourcePixels[srcOffset + 3]; } } target.SetPixels(width, height, newPixels); }
/// <summary> /// Writes the graphics control extension to the stream. /// </summary> /// <typeparam name="TPixel">The pixel format.</typeparam> /// <param name="image">The <see cref="ImageBase{TPixel}"/> to encode.</param> /// <param name="metaData">The metadata of the image or frame.</param> /// <param name="writer">The stream to write to.</param> /// <param name="transparencyIndex">The index of the color in the color palette to make transparent.</param> private void WriteGraphicalControlExtension <TPixel>(ImageBase <TPixel> image, IMetaData metaData, EndianBinaryWriter writer, int transparencyIndex) where TPixel : struct, IPixel <TPixel> { // TODO: Check transparency logic. bool hasTransparent = transparencyIndex < 255; DisposalMethod disposalMethod = hasTransparent ? DisposalMethod.RestoreToBackground : DisposalMethod.Unspecified; GifGraphicsControlExtension extension = new GifGraphicsControlExtension() { DisposalMethod = disposalMethod, TransparencyFlag = hasTransparent, TransparencyIndex = transparencyIndex, DelayTime = metaData.FrameDelay }; // Write the intro. this.buffer[0] = GifConstants.ExtensionIntroducer; this.buffer[1] = GifConstants.GraphicControlLabel; this.buffer[2] = 4; writer.Write(this.buffer, 0, 3); PackedField field = default(PackedField); field.SetBits(3, 3, (int)extension.DisposalMethod); // 1-3 : Reserved, 4-6 : Disposal // TODO: Allow this as an option. field.SetBit(6, false); // 7 : User input - 0 = none field.SetBit(7, extension.TransparencyFlag); // 8: Has transparent. writer.Write(field.Byte); writer.Write((ushort)extension.DelayTime); writer.Write((byte)extension.TransparencyIndex); writer.Write(GifConstants.Terminator); }
/// <summary> /// Rotates the image 90 degrees clockwise at the centre point. /// </summary> /// <param name="source">The source image.</param> private void Rotate90(ImageBase <TPixel> source) { int width = source.Width; int height = source.Height; using (var targetPixels = new PixelAccessor <TPixel>(height, width)) { Parallel.For( 0, height, this.ParallelOptions, y => { Span <TPixel> sourceRow = source.GetRowSpan(y); int newX = height - y - 1; for (int x = 0; x < width; x++) { targetPixels[newX, x] = sourceRow[x]; } }); source.SwapPixelsBuffers(targetPixels); } }