зеркало из https://github.com/SixLabors/docs-v1.git
315 строки
16 KiB
HTML
315 строки
16 KiB
HTML
<!DOCTYPE html>
|
||
<!--[if IE]><![endif]-->
|
||
<html>
|
||
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||
<title>Working with Pixel Buffers </title>
|
||
<meta name="viewport" content="width=device-width">
|
||
<meta name="title" content="Working with Pixel Buffers ">
|
||
<meta name="generator" content="docfx 2.59.0.0">
|
||
|
||
<link rel="shortcut icon" href="../../favicon.ico">
|
||
<link rel="stylesheet" href="../../styles/docfx.vendor.css">
|
||
<link rel="stylesheet" href="../../styles/docfx.css">
|
||
<link rel="stylesheet" href="../../styles/main.css">
|
||
<meta property="docfx:navrel" content="../../toc">
|
||
<meta property="docfx:tocrel" content="../toc">
|
||
|
||
<meta property="docfx:rel" content="../../">
|
||
|
||
</head>
|
||
<body data-spy="scroll" data-target="#affix" data-offset="120">
|
||
<div id="wrapper">
|
||
<header>
|
||
|
||
<nav id="autocollapse" class="navbar navbar-inverse ng-scope" role="navigation">
|
||
<div class="container">
|
||
<div class="navbar-header">
|
||
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#navbar">
|
||
<span class="sr-only">Toggle navigation</span>
|
||
<span class="icon-bar"></span>
|
||
<span class="icon-bar"></span>
|
||
<span class="icon-bar"></span>
|
||
</button>
|
||
|
||
<a class="navbar-brand" href="../../index.html">
|
||
<img id="logo" class="svg" src="../../logo.svg" alt="">
|
||
</a>
|
||
</div>
|
||
<div class="collapse navbar-collapse" id="navbar">
|
||
<form class="navbar-form navbar-right" role="search" id="search">
|
||
<div class="form-group">
|
||
<input type="text" class="form-control" id="search-query" placeholder="Search" autocomplete="off">
|
||
</div>
|
||
</form>
|
||
|
||
<ul class="nav level1 navbar-nav">
|
||
<li>
|
||
<a href="../../articles/imagesharp/index.html" title="Articles">Articles</a>
|
||
</li>
|
||
<li>
|
||
<a href="../../api/index.html" title="API Documentation">API Documentation</a>
|
||
</li>
|
||
</ul> </div>
|
||
</div>
|
||
</nav>
|
||
|
||
<div class="subnav navbar navbar-default">
|
||
<div class="container hide-when-search" id="breadcrumb">
|
||
<ul class="breadcrumb">
|
||
<li></li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</header>
|
||
<div class="container body-content">
|
||
|
||
<div id="search-results">
|
||
<div class="search-list">Search Results for <span></span></div>
|
||
<div class="sr-items">
|
||
<p><i class="glyphicon glyphicon-refresh index-loading"></i></p>
|
||
</div>
|
||
<ul id="pagination" data-first="First" data-prev="Previous" data-next="Next" data-last="Last"></ul>
|
||
</div>
|
||
</div>
|
||
<div role="main" class="container body-content hide-when-search">
|
||
<div class="sidenav hide-when-search">
|
||
<a class="btn toc-toggle collapse" data-toggle="collapse" href="#sidetoggle" aria-expanded="false" aria-controls="sidetoggle">Show / Hide Table of Contents</a>
|
||
<div class="sidetoggle collapse" id="sidetoggle">
|
||
<div>
|
||
<div class="sidefilter">
|
||
<form class="toc-filter">
|
||
<span class="glyphicon glyphicon-filter filter-icon"></span>
|
||
<input type="text" id="toc_filter_input" placeholder="Enter here to filter..." onkeypress="if(event.keyCode==13) {return false;}">
|
||
</form>
|
||
</div>
|
||
<div class="sidetoc">
|
||
<div class="toc" id="toc">
|
||
|
||
<ul class="nav level1">
|
||
<li class="">
|
||
<span class="expand-stub"></span>
|
||
<a href="../imagesharp/index.html" title="ImageSharp" class="">ImageSharp</a>
|
||
|
||
<ul class="nav level2">
|
||
<li class="">
|
||
<span class="expand-stub"></span>
|
||
<a href="../imagesharp/gettingstarted.html" title="Getting Started" class="">Getting Started</a>
|
||
|
||
<ul class="nav level3">
|
||
<li class="">
|
||
<a href="../imagesharp/pixelformats.html" title="Pixel Formats" class="">Pixel Formats</a>
|
||
</li>
|
||
<li class="">
|
||
<a href="../imagesharp/imageformats.html" title="Image Formats" class="">Image Formats</a>
|
||
</li>
|
||
<li class="">
|
||
<span class="expand-stub"></span>
|
||
<a href="../imagesharp/processing.html" title="Processing Images" class="">Processing Images</a>
|
||
|
||
<ul class="nav level4">
|
||
<li class="">
|
||
<a href="../imagesharp/resize.html" title="Resizing Images" class="">Resizing Images</a>
|
||
</li>
|
||
</ul> </li>
|
||
<li class="active">
|
||
<a href="../imagesharp/pixelbuffers.html" title="Working with Pixel Buffers" class="active">Working with Pixel Buffers</a>
|
||
</li>
|
||
<li class="">
|
||
<a href="../imagesharp/configuration.html" title="Configuration" class="">Configuration</a>
|
||
</li>
|
||
<li class="">
|
||
<a href="../imagesharp/memorymanagement.html" title="Memory Management" class="">Memory Management</a>
|
||
</li>
|
||
</ul> </li>
|
||
</ul> </li>
|
||
<li class="">
|
||
<span class="expand-stub"></span>
|
||
<a href="../imagesharp.drawing/index.html" title="ImageSharp.Drawing" class="">ImageSharp.Drawing</a>
|
||
|
||
<ul class="nav level2">
|
||
<li class="">
|
||
<a href="../imagesharp.drawing/gettingstarted.html" title="Getting Started" class="">Getting Started</a>
|
||
</li>
|
||
</ul> </li>
|
||
<li class="">
|
||
<span class="expand-stub"></span>
|
||
<a href="../imagesharp.web/index.html" title="ImageSharp.Web" class="">ImageSharp.Web</a>
|
||
|
||
<ul class="nav level2">
|
||
<li class="">
|
||
<span class="expand-stub"></span>
|
||
<a href="../imagesharp.web/gettingstarted.html" title="Getting Started" class="">Getting Started</a>
|
||
|
||
<ul class="nav level3">
|
||
<li class="">
|
||
<a href="../imagesharp.web/processingcommands.html" title="Processing Commands" class="">Processing Commands</a>
|
||
</li>
|
||
<li class="">
|
||
<a href="../imagesharp.web/imageproviders.html" title="Image Providers" class="">Image Providers</a>
|
||
</li>
|
||
<li class="">
|
||
<a href="../imagesharp.web/imagecaches.html" title="Image Caches" class="">Image Caches</a>
|
||
</li>
|
||
</ul> </li>
|
||
</ul> </li>
|
||
<li class="">
|
||
<span class="expand-stub"></span>
|
||
<a href="../fonts/index.html" title="Fonts" class="">Fonts</a>
|
||
|
||
<ul class="nav level2">
|
||
<li class="">
|
||
<a href="../fonts/gettingstarted.html" title="Getting Started" class="">Getting Started</a>
|
||
</li>
|
||
<li class="">
|
||
<a href="../fonts/customrendering.html" title="Custom Rendering" class="">Custom Rendering</a>
|
||
</li>
|
||
</ul> </li>
|
||
</ul> </div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="article row grid-right">
|
||
<div class="col-md-10">
|
||
<article class="content wrap" id="_content" data-uid="">
|
||
<h1 id="working-with-pixel-buffers">Working with Pixel Buffers</h1>
|
||
|
||
<h3 id="setting-individual-pixels-using-indexers">Setting individual pixels using indexers</h3>
|
||
<p>A very basic and readable way for manipulating individual pixels is to use the indexer either on <code>Image<T></code> or <code>ImageFrame<T></code>:</p>
|
||
<pre><code class="lang-C#">using (Image<Rgba32> image = new Image<Rgba32>(400, 400))
|
||
{
|
||
image[200, 200] = Rgba32.White; // also works on ImageFrame<T>
|
||
}
|
||
</code></pre><p>The idexer is an order of magnitude faster than the <code>.GetPixel(x, y)</code> and <code>.SetPixel(x,y)</code> methods of <code>System.Drawing</code> but there's still room for improvement.</p>
|
||
<h3 id="efficient-pixel-manipulation">Efficient pixel manipulation</h3>
|
||
<p>If you want to achieve killer speed in your own low-level pixel manipulation routines, you should utilize the per-row methods. These methods take advantage of the <a href="https://www.codemag.com/Article/1807051/Introducing-.NET-Core-2.1-Flagship-Types-Span-T-and-Memory-T">brand-new <code>Span<T></code>-based memory manipulation primitives</a> from <a href="https://www.nuget.org/packages/System.Memory/">System.Memory</a>, providing a fast, yet safe low-level solution to manipulate pixel data.</p>
|
||
<p>This is how you can implement efficient row-by-row pixel manipulation:</p>
|
||
<pre><code class="lang-C#">using SixLabors.ImageSharp;
|
||
|
||
// ...
|
||
|
||
using (Image<Rgba32> image = new Image<Rgba32>(400, 400))
|
||
{
|
||
for (int y = 0; y < image.Height; y++)
|
||
{
|
||
Span<Rgba32> pixelRowSpan = image.GetPixelRowSpan(y);
|
||
for (int x = 0; x < image.Width; x++)
|
||
{
|
||
pixelRowSpan[x] = new Rgba32(x/255, y/255, 50, 255);
|
||
}
|
||
}
|
||
}
|
||
</code></pre><h3 id="parallel-pixel-format-agnostic-image-manipulation">Parallel, pixel-format agnostic image manipulation</h3>
|
||
<p>There is a way to process image data that is even faster than using the approach mentioned before, and that also has the advantage of working on images of any underlying pixel-format, in a completely transparent way: using the <a class="xref" href="../../api/ImageSharp/SixLabors.ImageSharp.Processing.PixelRowDelegateExtensions.html#SixLabors_ImageSharp_Processing_PixelRowDelegateExtensions_ProcessPixelRowsAsVector4_SixLabors_ImageSharp_Processing_IImageProcessingContext_SixLabors_ImageSharp_Processing_PixelRowOperation_">ProcessPixelRowsAsVector4(IImageProcessingContext, PixelRowOperation)</a> APIs.</p>
|
||
<p>This is how you can use this extension to manipulate an image:</p>
|
||
<pre><code class="lang-C#">// ...
|
||
|
||
image.Mutate(c => c.ProcessPixelRowsAsVector4(row =>
|
||
{
|
||
for (int x = 0; x < row.Length; x++)
|
||
{
|
||
// We can apply any custom processing logic here
|
||
row[x] = Vector4.SquareRoot(row[x]);
|
||
}
|
||
}));
|
||
</code></pre><p>This API receives a <a class="xref" href="../../api/ImageSharp/SixLabors.ImageSharp.Processing.PixelRowOperation.html">PixelRowOperation</a> instance as input, and uses it to modify the pixel data of the target image. It does so by automatically executing the input operation in parallel, on multiple pixel rows at the same time, to fully leverage the power of modern multicore CPUs. The <code>ProcessPixelRowsAsVector4</code> extension also takes care of converting the pixel data to/from the <code>Vector4</code> format, which means the same operation can be used to easily process images of any existing pixel-format, without having to implement the processing logic again for each of them.</p>
|
||
<p>This extension offers the fastest, easiest and most flexible way to implement custom image processors in ImageSharp.</p>
|
||
<h3 id="spant-limitations"><code>Span<T></code> limitations</h3>
|
||
<p>Please be aware that <strong><code>Span<T></code> has a very specific limitation</strong>: it is a stack-only type! Read the <em>Is There Anything Span Can’t Do?!</em> section in <a href="https://www.codemag.com/Article/1807051/Introducing-.NET-Core-2.1-Flagship-Types-Span-T-and-Memory-T">this article</a> for more details.
|
||
A short summary of the limitations:</p>
|
||
<ul>
|
||
<li>Span can only live on the execution stack.</li>
|
||
<li>Span cannot be boxed or put on the heap.</li>
|
||
<li>Span cannot be used as a generic type argument.</li>
|
||
<li>Span cannot be an instance field of a type that itself is not stack-only.</li>
|
||
<li>Span cannot be used within asynchronous methods.</li>
|
||
</ul>
|
||
<p><strong>Non-conformant code:</strong></p>
|
||
<pre><code class="lang-C#">Span<Rgba32> span = image.GetRowSpan(y);
|
||
|
||
await Task.Run(() =>
|
||
{
|
||
// ☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠☠
|
||
// ☠☠☠ BANG! YOU HAVE CAPTURED A SPAN ON THE HEAP! ☠☠☠
|
||
|
||
for (int i = 0; i < span.Length; i++)
|
||
{
|
||
span[i] = /* ... */;
|
||
}
|
||
});
|
||
</code></pre><h3 id="exporting-raw-pixel-data-from-an-imaget">Exporting raw pixel data from an <code>Image<T></code></h3>
|
||
<p>You can use <a class="xref" href="../../api/ImageSharp/SixLabors.ImageSharp.Image-1.html#SixLabors_ImageSharp_Image_1_TryGetSinglePixelSpan_">TryGetSinglePixelSpan</a> to access the whole contigous pixel buffer, for example, to copy the pixel data into an array. For large, multi-megapixel images, however, the data must be accessed and copied per row:</p>
|
||
<pre><code class="lang-C#">if(image.TryGetSinglePixelSpan(out var pixelSpan))
|
||
{
|
||
Rgba32[] pixelArray = pixelSpan.ToArray();
|
||
}
|
||
</code></pre><p>Or:</p>
|
||
<pre><code class="lang-C#">Rgba32[] pixelArray = /* your pixel buffer being reused */
|
||
if(image.TryGetSinglePixelSpan(out var pixelSpan))
|
||
{
|
||
pixelSpan.CopyTo(pixelArray);
|
||
}
|
||
</code></pre><p>Or:</p>
|
||
<pre><code class="lang-C#">if(image.TryGetSinglePixelSpan(out var pixelSpan))
|
||
{
|
||
byte[] rgbaBytes = MemoryMarshal.AsBytes(pixelSpan).ToArray();
|
||
}
|
||
</code></pre><h3 id="loading-raw-pixel-data-into-an-imaget">Loading raw pixel data into an <code>Image<T></code></h3>
|
||
<pre><code class="lang-C#">int width = ...;
|
||
int height = ...;
|
||
Rgba32[] rgbaData = GetMyRgbaArray();
|
||
using (var image = Image.LoadPixelData(rgbaData, width, height))
|
||
{
|
||
// Work with the image
|
||
}
|
||
</code></pre><pre><code class="lang-C#">int width = ...;
|
||
int height = ...;
|
||
byte[] rgbaBytes = GetMyRgbaBytes();
|
||
using (var image = Image.LoadPixelData<Rgba32>(rgbaBytes, width, height))
|
||
{
|
||
// Work with the image
|
||
}
|
||
</code></pre></article>
|
||
</div>
|
||
|
||
<div class="hidden-sm col-md-2" role="complementary">
|
||
<div class="sideaffix">
|
||
<div class="contribution">
|
||
<ul class="nav">
|
||
<li>
|
||
<a href="https://github.com/SixLabors/docs/blob/master/articles/imagesharp/pixelbuffers.md/#L1" class="contribution-link">Improve this Doc</a>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
<nav class="bs-docs-sidebar hidden-print hidden-xs hidden-sm affix" id="affix">
|
||
<h5>In This Article</h5>
|
||
<div></div>
|
||
</nav>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<footer>
|
||
<div class="grad-bottom"></div>
|
||
<div class="footer">
|
||
<div class="container">
|
||
<span class="pull-right">
|
||
<a href="#top">Back to top</a>
|
||
</span>
|
||
|
||
<span>Generated by <strong>DocFX</strong></span>
|
||
</div>
|
||
</div>
|
||
</footer>
|
||
</div>
|
||
|
||
<script type="text/javascript" src="../../styles/docfx.vendor.js"></script>
|
||
<script type="text/javascript" src="../../styles/docfx.js"></script>
|
||
<script type="text/javascript" src="../../styles/main.js"></script>
|
||
</body>
|
||
</html>
|