コード例 #1
0
 /// <summary>
 /// Clips the specified <paramref name="source"/> using the specified <paramref name="clippingRegion"/>.
 /// Unlike the <see cref="O:KGySoft.Drawing.Imaging.BitmapDataExtensions.Clone">Clone</see> methods, this one returns a wrapper,
 /// providing access only to the specified region of the original <paramref name="source"/>.
 /// <br/>See the <strong>Remarks</strong> section for details.
 /// </summary>
 /// <param name="source">The source bitmap data to be clipped.</param>
 /// <param name="clippingRegion">A <see cref="Rectangle"/> that specifies a region within the <paramref name="source"/>.</param>
 /// <returns>An <see cref="IWritableBitmapData"/> that provides access only to the specified region withing the <paramref name="source"/>.</returns>
 /// <exception cref="ArgumentNullException"><paramref name="source"/> is <see langword="null"/>.</exception>
 /// <exception cref="ArgumentOutOfRangeException"><paramref name="clippingRegion"/> has no overlapping region with source bounds.</exception>
 /// <remarks>
 /// <para>The <see cref="IBitmapData.RowSize"/> property of the returned instance can be 0, indicating that the <see cref="IWritableBitmapDataRow.WriteRaw{T}">WriteRaw</see>
 /// method cannot be used. It can occur if the left edge of the clipping is not zero.</para>
 /// <para>Even if <see cref="IBitmapData.RowSize"/> property of the returned instance is a nonzero value it can happen that it is too low to access all columns
 /// by the <see cref="IWritableBitmapDataRow.WriteRaw{T}">WriteRaw</see> method. It can occur with indexed <see cref="IBitmapData.PixelFormat"/>s if the right edge of the clipping is not on byte boundary.</para>
 /// </remarks>
 public static IWritableBitmapData Clip(this IWritableBitmapData source, Rectangle clippingRegion)
 {
     if (source == null)
         throw new ArgumentNullException(nameof(source), PublicResources.ArgumentNull);
     return clippingRegion.Location.IsEmpty && clippingRegion.Size == source.GetSize()
         ? source
         : new ClippedBitmapData(source, clippingRegion);
 }
コード例 #2
0
 /// <summary>
 /// Clears the content of the specified <paramref name="bitmapData"/> and fills it with the specified <paramref name="color"/>.
 /// <br/>This method is similar to <see cref="Graphics.Clear">Graphics.Clear</see> except that this one supports any <see cref="PixelFormat"/> and also dithering.
 /// </summary>
 /// <param name="bitmapData">The <see cref="IWritableBitmapData"/> to be cleared.</param>
 /// <param name="color">A <see cref="Color32"/> that represents the desired result color of the <paramref name="bitmapData"/>.
 /// If it has transparency, which is not supported by <see cref="IBitmapData.PixelFormat"/> of <paramref name="bitmapData"/>, then the result might be either
 /// completely transparent (depends also on <see cref="IBitmapData.AlphaThreshold"/>), or the color will be blended with <see cref="IBitmapData.BackColor"/>.
 /// </param>
 /// <param name="ditherer">The ditherer to be used for the clearing. Has no effect if <see cref="IBitmapData.PixelFormat"/> of <paramref name="bitmapData"/> has at least 24 bits-per-pixel size. This parameter is optional.
 /// <br/>Default value: <see langword="null"/>.</param>
 /// <remarks>
 /// <note>This method adjusts the degree of parallelization automatically, blocks the caller, and does not support cancellation or reporting progress. Use the <see cref="BeginClear">BeginClear</see>
 /// or <see cref="ClearAsync">ClearAsync</see> (in .NET 4.0 and above) methods for asynchronous call and to adjust parallelization, set up cancellation and for reporting progress.</note>
 /// </remarks>
 /// <seealso cref="BitmapExtensions.Clear(Bitmap, Color, IDitherer, Color, byte)"/>
 public static void Clear(this IWritableBitmapData bitmapData, Color32 color, IDitherer?ditherer = null)
 {
     if (bitmapData == null)
     {
         throw new ArgumentNullException(nameof(bitmapData), PublicResources.ArgumentNull);
     }
     DoClear(AsyncContext.Null, bitmapData, color, ditherer);
 }
コード例 #3
0
 /// <summary>
 /// Begins to clear the content of the specified <paramref name="bitmapData"/> and fills it with the specified <paramref name="color"/> asynchronously.
 /// <br/>This method is similar to <see cref="Graphics.Clear">Graphics.Clear</see> except that this one supports any <see cref="PixelFormat"/> and also dithering.
 /// </summary>
 /// <param name="bitmapData">The <see cref="IWritableBitmapData"/> to be cleared.</param>
 /// <param name="color">A <see cref="Color32"/> that represents the desired result color of the <paramref name="bitmapData"/>.
 /// If it has transparency, which is not supported by <see cref="IBitmapData.PixelFormat"/> of <paramref name="bitmapData"/>, then the result might be either
 /// completely transparent (depends also on <see cref="IBitmapData.AlphaThreshold"/>), or the color will be blended with <see cref="IBitmapData.BackColor"/>.
 /// </param>
 /// <param name="ditherer">The ditherer to be used for the clearing. Has no effect if <see cref="IBitmapData.PixelFormat"/> of <paramref name="bitmapData"/> has at least 24 bits-per-pixel size. This parameter is optional.
 /// <br/>Default value: <see langword="null"/>.</param>
 /// <param name="asyncConfig">The configuration of the asynchronous operation such as parallelization, cancellation, reporting progress, etc. This parameter is optional.
 /// <br/>Default value: <see langword="null"/>.</param>
 /// <returns>A <see cref="Task"/> that represents the asynchronous operation, which could still be pending.</returns>
 /// <remarks>
 /// <para>This method is not a blocking call even if the <see cref="AsyncConfigBase.MaxDegreeOfParallelism"/> property of the <paramref name="asyncConfig"/> parameter is 1.</para>
 /// </remarks>
 public static Task ClearAsync(this IWritableBitmapData bitmapData, Color32 color, IDitherer?ditherer = null, TaskConfig?asyncConfig = null)
 {
     if (bitmapData == null)
     {
         throw new ArgumentNullException(nameof(bitmapData), PublicResources.ArgumentNull);
     }
     return(AsyncContext.DoOperationAsync(ctx => DoClear(ctx, bitmapData, color, ditherer), asyncConfig));
 }
コード例 #4
0
 /// <summary>
 /// Tries to the set the specified <paramref name="palette"/> for this <see cref="IWritableBitmapData"/>.
 /// <br/>See the <strong>Remarks</strong> section for details.
 /// </summary>
 /// <param name="bitmapData">The <see cref="IWritableBitmapData"/> whose <see cref="IBitmapData.Palette"/> should be set.</param>
 /// <param name="palette">A <see cref="Palette"/> instance to set.</param>
 /// <returns><see langword="true"/>&#160;<paramref name="palette"/> can be set as the <see cref="IBitmapData.Palette"/> of this <paramref name="bitmapData"/>; otherwise, <see langword="false"/>.</returns>
 /// <remarks>
 /// <para>Setting may fail if <paramref name="bitmapData"/>&#160;<see cref="IBitmapData.PixelFormat"/> is not an indexed one,
 /// the number of entries in <paramref name="palette"/> is less than <see cref="Palette.Count"/> of the current <see cref="IBitmapData.Palette"/>,
 /// the number of entries in <paramref name="palette"/> is larger than the possible maximum number of colors of the current <see cref="IBitmapData.PixelFormat"/>,
 /// or when the current <see cref="IWritableBitmapData"/> does not support setting the palette.</para>
 /// <para>The <see cref="Palette.BackColor">Palette.BackColor</see> and <see cref="Palette.AlphaThreshold">Palette.AlphaThreshold</see> properties of the <see cref="IBitmapData.Palette"/> property will
 /// continue to return the same value as the original <see cref="IBitmapData.BackColor"/> and <see cref="IBitmapData.AlphaThreshold"/> values of this <paramref name="bitmapData"/>.</para>
 /// </remarks>
 /// <exception cref="ArgumentNullException"><paramref name="bitmapData"/> is <see langword="null"/>.</exception>
 public static bool TrySetPalette(this IWritableBitmapData bitmapData, Palette palette)
 {
     if (bitmapData == null)
     {
         throw new ArgumentNullException(nameof(bitmapData));
     }
     if (palette == null)
     {
         throw new ArgumentNullException(nameof(palette));
     }
     return(bitmapData is IBitmapDataInternal internalBitmapData && internalBitmapData.TrySetPalette(palette));
 }
コード例 #5
0
        public void ToGrayscaleTest()
        {
            using Bitmap bmp = Icons.Information.ExtractBitmap(new Size(256, 256));

            new PerformanceTest {
                Iterations = 100, CpuAffinity = null
            }
            .AddCase(() =>
            {
                using var result = new Bitmap(bmp.Width, bmp.Height);
                using (Graphics g = Graphics.FromImage(result))
                {
                    // Grayscale color matrix
                    var colorMatrix = new ColorMatrix(new float[][]
                    {
                        new float[] { ColorExtensions.RLum, ColorExtensions.RLum, ColorExtensions.RLum, 0, 0 },
                        new float[] { ColorExtensions.GLum, ColorExtensions.GLum, ColorExtensions.GLum, 0, 0 },
                        new float[] { ColorExtensions.BLum, ColorExtensions.BLum, ColorExtensions.BLum, 0, 0 },
                        new float[] { 0, 0, 0, 1, 0 },
                        new float[] { 0, 0, 0, 0, 1 }
                    });

                    using (var attrs = new ImageAttributes())
                    {
                        attrs.SetColorMatrix(colorMatrix);
                        g.DrawImage(bmp, new Rectangle(0, 0, result.Width, result.Height), 0, 0, result.Width, result.Height, GraphicsUnit.Pixel, attrs);
                    }
                }
            }, "Graphics.DrawImage(..., ImageAttributes)")
            .AddCase(() =>
            {
                using var result = new Bitmap(bmp.Width, bmp.Height);
                using IReadableBitmapData src = bmp.GetReadableBitmapData();
                using IWritableBitmapData dst = result.GetWritableBitmapData();
                IReadableBitmapDataRow rowSrc = src.FirstRow;
                IWritableBitmapDataRow rowDst = dst.FirstRow;
                do
                {
                    for (int x = 0; x < src.Width; x++)
                    {
                        rowDst[x] = rowSrc[x].ToGray();
                    }
                } while (rowSrc.MoveNextRow() && rowDst.MoveNextRow());
            }, "Sequential processing")
            .AddCase(() =>
            {
                using var result = bmp.ToGrayscale();
            }, "ImageExtensions.ToGrayscale")
            .DoTest()
            .DumpResults(Console.Out);
        }
コード例 #6
0
 private static void DoClear(IAsyncContext context, IWritableBitmapData bitmapData, Color32 color, IDitherer ditherer)
 {
     IBitmapDataInternal accessor = bitmapData as IBitmapDataInternal ?? new BitmapDataWrapper(bitmapData, false, true);
     try
     {
         if (ditherer == null || !accessor.PixelFormat.CanBeDithered())
             ClearDirect(context, accessor, color);
         else
             ClearWithDithering(context, accessor, color, ditherer);
     }
     finally
     {
         if (!ReferenceEquals(accessor, bitmapData))
             accessor.Dispose();
     }
 }
コード例 #7
0
        private static Bitmap ReadRawBitmap(BinaryReader br)
        {
            var size        = new Size(br.ReadInt32(), br.ReadInt32());
            var pixelFormat = (PixelFormat)br.ReadInt32();

            Color[] palette = null;
            if (pixelFormat.ToBitsPerPixel() <= 8)
            {
                palette = new Color[br.ReadInt32()];
                for (int i = 0; i < palette.Length; i++)
                {
                    palette[i] = Color.FromArgb(br.ReadInt32());
                }
            }

            var result = new Bitmap(size.Width, size.Height, pixelFormat);

            if (palette != null)
            {
                ColorPalette resultPalette = result.Palette;
                if (resultPalette.Entries.Length != palette.Length)
                {
                    resultPalette = (ColorPalette)Reflector.CreateInstance(typeof(ColorPalette), palette.Length);
                }
                for (int i = 0; i < palette.Length; i++)
                {
                    resultPalette.Entries[i] = palette[i];
                }
                result.Palette = resultPalette;
            }

            using (IWritableBitmapData data = result.GetWritableBitmapData())
            {
                int width = data.RowSize >> 2;
                IWritableBitmapDataRow row = data.FirstRow;
                do
                {
                    for (int x = 0; x < width; x++)
                    {
                        row.WriteRaw(x, br.ReadInt32());
                    }
                } while (row.MoveNextRow());
            }

            return(result);
        }
コード例 #8
0
        public void ClearTest(PixelFormat pixelFormat, uint argb)
        {
            const int size  = 512;
            Color     color = Color.FromArgb((int)argb);

            new PerformanceTest {
                TestName = $"{pixelFormat} {size}x{size}", Iterations = 10, CpuAffinity = null
            }
            .AddCase(() =>
            {
                using var bmp = new Bitmap(size, size, pixelFormat);
                using var g   = Graphics.FromImage(bmp);
                g.Clear(color);
            }, "Graphics.Clear")
            .AddCase(() =>
            {
                using var bmp = new Bitmap(size, size, pixelFormat);
                using IWritableBitmapData acc = bmp.GetWritableBitmapData();
                var c = new Color32(color);
                IWritableBitmapDataRow row = acc.FirstRow;
                do
                {
                    for (int x = 0; x < acc.Width; x++)
                    {
                        row[x] = c;
                    }
                } while (row.MoveNextRow());
            }, "Sequential clear")
            .AddCase(() =>
            {
                using var bmp = new Bitmap(size, size, pixelFormat);
                bmp.Clear(color);
            }, "BitmapDataAccessor.Clear")
            .DoTest()
            .DumpResults(Console.Out);
        }
コード例 #9
0
        public static Bitmap?ToBitmap(this Graphics graphics, bool visibleClipOnly)
        {
            if (!OSUtils.IsWindows)
            {
                throw new PlatformNotSupportedException(Res.RequiresWindows);
            }

            if (graphics == null)
            {
                throw new ArgumentNullException(nameof(graphics), PublicResources.ArgumentNull);
            }

            if (visibleClipOnly && graphics.IsVisibleClipEmpty)
            {
                return(null);
            }

            Bitmap        result;
            RectangleF    visibleRect;
            int           sourceLeft, sourceTop, targetWidth, targetHeight;
            GraphicsState state = graphics.Save();

            try
            {
                // resetting the identity matrix so VisibleClipBounds will be correct
                graphics.Transform = new Matrix();

                // obtaining size in pixels
                graphics.PageUnit = GraphicsUnit.Pixel;
                visibleRect       = graphics.VisibleClipBounds;
                sourceLeft        = (int)visibleRect.Left;
                sourceTop         = (int)visibleRect.Top;
                targetWidth       = (int)visibleRect.Width;
                targetHeight      = (int)visibleRect.Height;

                // there is a source image: copying so transparency is preserved
                Image?imgSource = graphics.GetBackingImage();
                if (imgSource != null)
                {
                    if (imgSource is Metafile)
                    {
                        throw new NotSupportedException(Res.GraphicsExtensionsToBitmapMetafileNotSupported);
                    }
                    if (!visibleClipOnly)
                    {
                        return((Bitmap)imgSource.Clone());
                    }

                    if (targetWidth == 0 || targetHeight == 0)
                    {
                        return(null);
                    }

                    result = new Bitmap(targetWidth, targetHeight, imgSource.PixelFormat);
                    using IReadableBitmapData src = ((Bitmap)imgSource).GetReadableBitmapData();
                    using IWritableBitmapData dst = result.GetWritableBitmapData();
                    src.CopyTo(dst, new Rectangle(sourceLeft, sourceTop, targetWidth, targetHeight), Point.Empty);
                    return(result);
                }
            }
            finally
            {
                graphics.Restore(state);
            }

            IntPtr dcSource = graphics.GetHdc();

            if (!visibleClipOnly)
            {
                sourceLeft = 0;
                sourceTop  = 0;

                // obtaining container Window
                IntPtr hwnd = User32.WindowFromDC(dcSource);
                if (hwnd != IntPtr.Zero)
                {
                    //// Show in whole screen
                    //RECT rect;
                    //GetWindowRect(hwnd, out rect); // the full rect of self control on screen
                    //// Show in screen
                    //GetWindowRect(hwnd, out rect);
                    //left = -rect.Left;
                    //top = -rect.Top;
                    //width = GetDeviceCaps(dcSource, DeviceCap.HORZRES);
                    //height = GetDeviceCaps(dcSource, DeviceCap.VERTRES);
                    //visibleRect.Offset(rect.Left, rect.Top);

                    //// Show in parent control
                    //IntPtr hwndParent = GetParent(hwnd);
                    //if (hwndParent != IntPtr.Zero)
                    //{
                    //    RECT rectParent;
                    //    GetWindowRect(hwndParent, out rectParent);
                    //    left = rectParent.Left - rect.Left;
                    //    top = rectParent.Top - rect.Top;
                    //    width = rectParent.Right - rectParent.Left;
                    //    height = rectParent.Bottom - rectParent.Top;
                    //    visibleRect.Offset(-left, -top);
                    //}
                    //else

                    // Show in container control
                    Rectangle rect = User32.GetClientRect(hwnd);
                    if (rect.Right < visibleRect.Right && rect.Bottom < visibleRect.Bottom)
                    {
                        // Visible rect is larger than client rect: calculating from full size.
                        // This is usually the case when Graphics is created for nonclient area
                        rect = User32.GetWindowRect(hwnd);
                    }

                    targetWidth  = rect.Right - rect.Left;
                    targetHeight = rect.Bottom - rect.Top;
                }
                else if (visibleRect.Location != Point.Empty)
                {
                    // no window: surrounding symmetrically or max 100 px
                    targetWidth  = (int)(visibleRect.Right + Math.Min(visibleRect.Left, 100f));
                    targetHeight = (int)(visibleRect.Bottom + Math.Min(visibleRect.Top, 100f));
                }
            }

            // the container control is too small
            if (targetWidth <= 0 || targetHeight <= 0)
            {
                graphics.ReleaseHdc(dcSource);
                return(null);
            }

            // creating a compatible bitmap
            IntPtr dcTarget  = Gdi32.CreateCompatibleDC(dcSource);
            IntPtr hbmResult = Gdi32.CreateCompatibleBitmap(dcSource, targetWidth, targetHeight);

            Gdi32.SelectObject(dcTarget, hbmResult);

            // Copy content
            Gdi32.BitBlt(dcTarget, 0, 0, targetWidth, targetHeight, dcSource, sourceLeft, sourceTop);
            result = Image.FromHbitmap(hbmResult);

            //cleanup
            graphics.ReleaseHdc(dcSource);
            Gdi32.DeleteDC(dcTarget);
            Gdi32.DeleteObject(hbmResult);

            return(result);
        }
コード例 #10
0
 /// <summary>
 /// Begins to clear the content of the specified <paramref name="bitmapData"/> and fills it with the specified <paramref name="color"/> asynchronously.
 /// <br/>This method is similar to <see cref="Graphics.Clear">Graphics.Clear</see> except that this one supports any <see cref="PixelFormat"/> and also dithering.
 /// <br/>See the <strong>Remarks</strong> section for details.
 /// </summary>
 /// <param name="bitmapData">The <see cref="IWritableBitmapData"/> to be cleared.</param>
 /// <param name="color">A <see cref="Color32"/> that represents the desired result color of the <paramref name="bitmapData"/>.
 /// If it has transparency, which is not supported by <see cref="IBitmapData.PixelFormat"/> of <paramref name="bitmapData"/>, then the result might be either
 /// completely transparent (depends also on <see cref="IBitmapData.AlphaThreshold"/>), or the color will be blended with <see cref="IBitmapData.BackColor"/>.
 /// </param>
 /// <param name="ditherer">The ditherer to be used for the clearing. Has no effect if <see cref="IBitmapData.PixelFormat"/> of <paramref name="bitmapData"/> has at least 24 bits-per-pixel size. This parameter is optional.
 /// <br/>Default value: <see langword="null"/>.</param>
 /// <param name="asyncConfig">The configuration of the asynchronous operation such as parallelization, cancellation, reporting progress, etc. This parameter is optional.
 /// <br/>Default value: <see langword="null"/>.</param>
 /// <returns>An <see cref="IAsyncResult"/> that represents the asynchronous operation, which could still be pending.</returns>
 /// <remarks>
 /// <para>In .NET Framework 4.0 and above you can use also the <see cref="ClearAsync">ClearAsync</see> method.</para>
 /// <para>To finish the operation and to get the exception that occurred during the operation you have to call the <see cref="EndClear">EndClear</see> method.</para>
 /// <para>This method is not a blocking call even if the <see cref="AsyncConfigBase.MaxDegreeOfParallelism"/> property of the <paramref name="asyncConfig"/> parameter is 1.</para>
 /// </remarks>
 public static IAsyncResult BeginClear(this IWritableBitmapData bitmapData, Color32 color, IDitherer ditherer = null, AsyncConfig asyncConfig = null)
 {
     if (bitmapData == null)
         throw new ArgumentNullException(nameof(bitmapData), PublicResources.ArgumentNull);
     return AsyncContext.BeginOperation(ctx => DoClear(ctx, bitmapData, color, ditherer), asyncConfig);
 }
コード例 #11
0
        internal ClippedBitmapData(IBitmapData source, Rectangle clippingRegion)
        {
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }

            region = clippingRegion;

            // source is already clipped: unwrapping to prevent tiered nesting (not calling Unwrap because other types should not be extracted here)
            if (source is ClippedBitmapData parent)
            {
                BitmapData = parent.BitmapData;
                region.Offset(parent.region.Location);
                region.Intersect(parent.region);
            }
            else
            {
                BitmapData = source;
                region.Intersect(new Rectangle(Point.Empty, source.GetSize()));
            }

            if (region.IsEmpty)
            {
                throw new ArgumentOutOfRangeException(nameof(clippingRegion), PublicResources.ArgumentOutOfRange);
            }

            bitmapDataType = BitmapData switch
            {
                IBitmapDataInternal _ => BitmapDataType.Internal,
                IReadWriteBitmapData _ => BitmapDataType.ReadWrite,
                IReadableBitmapData _ => BitmapDataType.Readable,
                IWritableBitmapData _ => BitmapDataType.Writable,
                                    _ => BitmapDataType.None
            };

            PixelFormat    = BitmapData.PixelFormat;
            BackColor      = BitmapData.BackColor;
            AlphaThreshold = BitmapData.AlphaThreshold;
            Palette        = BitmapData.Palette;
            int bpp = PixelFormat.ToBitsPerPixel();

            int maxRowSize = (region.Width * bpp) >> 3;
            RowSize = region.Left > 0
                      // Any clipping from the left disables raw access because ReadRaw/WriteRaw offset depends on size of T,
                      // which will fail for any T whose size is not the same as the actual pixel size
                ? 0
                      // Even one byte padding is disabled to protect the right edge of a region by default
                : Math.Min(source.RowSize, maxRowSize);

            if (bpp >= 8 || RowSize < maxRowSize)
            {
                return;
            }

            // 1/4bpp: Adjust RowSize if needed
            // right edge: if not at byte boundary but that is the right edge of the original image, then we allow including padding
            if (PixelFormat.IsAtByteBoundary(region.Width) && region.Right == BitmapData.Width)
            {
                RowSize++;
            }
        }