. NET Framework WPF load high quality large graphics slow performance optimization

Source: Internet
Author: User
Tags foreach

The most recent project encountered a problem with a very high memory footprint when multiple pictures are loaded at the same time in WPF.

Problem background:

Load multiple pictures in one listview, note: We need to load the picture resolution is very high.

Code:

XAML:

<Grid>     <Grid.RowDefinitions>          <rowdefinition height= "Auto"/>         <
rowdefinition height= "*"/>     </Grid.RowDefinitions>          <button content= "Load"  width= " height="  margin= "0,10"  click= "Button_Click"/>          <listview grid.row= "1"  x:name= "Lvimages" >         <ListView.ItemTemplate>              <DataTemplate>                  <image source= "{Binding  ImageSource} " maxwidth="/>              </datatemplate&gT         </ListView.ItemTemplate>          <ListView.Template>              <ControlTemplate>                  <Grid>                      <scrollviewer verticalscrollbarvisibility= "Auto"   horizontalscrollbarvisibility= "Hidden" >            
             <ItemsPresenter />                      </ScrollViewer>                  &lT;/grid>             </ControlTemplate>         </ListView.Template>          <ListView.ItemsPanel>              <ItemsPanelTemplate>                  <stackpanel isitemshost= "True"  virtualizingpanel.virtualizationmode= "Recycling"  virtualizingpanel.isvirtualizing= "True"/>              </ItemsPanelTemplate>         </ Listview.itemspanel>     </ListView> </Grid>


C #:

Public partial class mainwindow : window {    public 
MainWindow ()     {        initializecomponent (); &NBSP;&NBSP;&NBSP;&NBSP}     private void button_click (object sender,  Routedeventargs e)     {        
LvImages.Items.Clear ();         // image folder location: d:\pics          string[] files = system.io.directory.getfiles (@ "D:\
Pics ");         List<ImageSourceModel> models = new 
List<imagesourcemodel> ();         foreach (var path in files)          {             bitmapimage image = new bitmapimage ();             image.
BeginInit ();             image.
Urisource = new system.uri (path);             image.
EndInit ();             image.
Freeze ();             models.
ADD (New imagesourcemodel ()  { imagesource = image });         }         
lvimages.itemssource = models; &NBSP;&NBSP;&NBSP;&NBSP}} public class imagesourcemodel {    public  IMAGESOURCE&NBSP;IMAGESOURCE&NBSP;{&NBSP;GET;&NBSP;SET;&NBSP}}


Memory footprint (20 pictures loaded at this time, memory footprint >1g):


Optimization scenario:

1. Initial load, only part of the picture and display. When the ScrollViewer scroll to the bottom, load the part again. For this scenario, you can refer to the WPF MVVM mode to implement the ListView Drop-down display for more content;

But this does not solve the eventual memory footprint.

2. Set the Decodepixelwidth property to the picture,

BitmapImage image = new BitmapImage ();

Image. BeginInit ();

Image. UriSource = new System.Uri (path);

Image. Decodepixelwidth = 800;

Image. EndInit ();

Image. Freeze ();

Models. ADD (New Imagesourcemodel () {imagesource = image});


The memory footprint at this point is as shown


The

memory is significantly reduced, with the same amount of picture memory occupied by only around 40M.

Finally, we can combine optimization Scenario 1 with Optimization Scenario 2. This will not occur when you load more than one picture of the cotton phenomenon. In addition, from the user experience point of view we can be shown in the picture before the first with a loading animation effect of the transition.




WPF large picture processing speed optimization: pointer operation, parallel operation, dozens of times-times optimization

I've been using GDI + to do WinForm based image processing, This resolution moved all the way to WPF (mainly to show the layout is convenient)
The picture is
2512*3307 's big 8.3 million pixel
Class library based on Writablebitmapex WPF version
function is an extension method that I wrote myself, and I just took advantage of the Writablebitmapex provided by the environment, I am lazy to write from beginning to end the
 
1. Standard int32 array traversal calculation release
0.28s

Unsafe public static void testgray1 (this writeablebitmap bmp) {     using  (var context = bmp. Getbitmapcontext ())     {        int height  = context.
Height;         int width = context.
Width;         for  (int y = 0; y <  height; y++)         {                           
      for  (int x = 0; x < width; x++)             {                 int&Nbsp;pos=y * context.
width + x;                 var c  = context.
Pixels[pos];                 var r
 =  (Byte) (c >> 16);                 var g
 =  (Byte) (c >> 8);                 var b
 =  (Byte) (c);                                  var gray =  (R
&NBSP;*&NBSP;38&NBSP;+&NBSP;G&NBSP;*&NBSP;75&NBSP;+&NBSP;B&NBSP;*&NBSP;15)  >> 7);           &Nbsp;     var color= (255 << 24)  |  (gray <<
&NBSP;16)  |  (gray << 8)  | gray;                 context.
Pixels[pos]=color;             }          }    &nbsp}}



2. Standard int32 pointer traversal calculation release

0.04s

Unsafe public static void testgray2 (this writeablebitmap bmp) {     using  (var context = bmp. Getbitmapcontext ())     {        var ptr  = context.
Pixels;         int height = context.
Height;         int width = context.
Width;         for  (int y = 0; y <  height; y++)         {             for  (int x = 0; x < width; x++)              {       
         var c = *ptr;                var r
 =  (Byte) (c >> 16)  ;                 var g
 =  (Byte) (c >> 8)  ;                 var b
 =  (Byte) (c)  ;                 var gray  =  ((r * 38 + g * 75 + b * 15)  >> 
7);                 var color  =  (255 << 24)  |  (gray << 16)  |  (gray <
&LT;&NBSP;8)  | gray;                 *ptr = color;
                ptr++;             }          }    &nbsp}}



3.colorstruct pointer traversal calculation

0.02 s

should be already up to the limit speed [except for the latter parallel way], I can't think of any other way to improve the processing speed

And this is the most intuitive, easiest way to understand, and easy to maintain



[StructLayout (layoutkind.sequential)] Public struct pixelcolor {    public 
byte blue;
    public byte Green;
    public byte Red;
    public byte Alpha; }     unsafe public static void testgray3 (This WriteableBitmap  bmp)     {        using  (var  Context = bmp. Getbitmapcontext ())         {             var ptr =  (pixelcolor*) context.
Pixels;             int height = context.
Height;             int width = context.
Width;             for  (int y = 0; y < height; y++)              {                 for  (int x = 0; x <  width; x++)                  {                 
   var c = *ptr;                      var gray =  (c.red * 38 + c.green * 75 + c.
BLUE&NBSP;*&NBSP;15)  >> 7);                       (*PTR). Green= (*PTR). Red= (*PTR).blue =  (byte) gray;                   
  ptr++;                 }   
          }         }     }




4. In contrast, I tested the speed of GDI + pointer processing pictures

0.06s


Public static unsafe bitmap togray (bitmap img) {    var rect  = new system.drawing.rectangle (0, 0, img. Width, img.
Height);     var data = img. LockBits (rect, system.drawing.imaging.imagelockmode.readonly, 
SYSTEM.DRAWING.IMAGING.PIXELFORMAT.FORMAT32BPPARGB);     var ptr =  (colortype*) data.
Scan0.topointer ();     var bytes = new int32[img. Width * img.
Height];     var height = img.
Height;     var width = img.
Width;     for  (int y = 0; y < height; y++)      {        for  (int x = 0; x  < width; x++)         {            var color = *ptr;             var gray =  (color. R * 38 + color. G * 75 + color.
B&NBSP;*&NBSP;15)  >> 7);              (*PTR). r =  (*PTR). g =  (*PTR).
b =  (byte) gray;
            ptr++; &NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP}     }     img.
Unlockbits (data);
    return img; }




5. The plays are coming. I've always been puzzled by parallel.for, why he spends several times as much as normal for. Today, after a careful study, found that the original is wrong with the

0.01 seconds    release

Notebook i5cpu, if the desktop I7 will be more powerful, the speed will become Hanchen lower. The


mainly utilizes the method of cyclic parallelization of Microsoft's Task Parallel library.

Note: The default parallel loop is slow for a small function body, which must be created using Partitioner to create the loop body, which is described in MSDN and is key among the keys

Unsafe public static void testgray5 (this writeablebitmap bmp) {       using  (var context = bmp. Getbitmapcontext ())     {        int height  = context.
Height;         int width = context.
Width;         parallel.foreach (Partitioner.create (0, height),  (h)  =>         {             var ptr =  (pixelcolor*) context.
Pixels;             ptr += h.Item1 * 
Width             for  (int y = h. item1; y < h.item2; y++)              {                 for  (int x = 0; x < width; x++)                  {                     var c
 = *ptr;                      var gray =  (c.red * 38 + c.green * 75 + c.
BLUE&NBSP;*&NBSP;15)  >> 7);                       (*PTR). green =  (*PTR). red =  (*PTR).
blue =  (byte) gray;                     ptr++;                 }              }         }
); &NBSP;&NBSP;&NBSP;&NBSP}}




Feelings

1. Never use a property or function in a loop, and it is likely to decrease the number of times it is calculated.

Because a property is essentially a function, and it is best not to call a function in a loop, if you do need inline code, C # has no inline, then the copy code, anyway, for speed.

2. The pointer-shift operation seems to be 10 times times faster than direct array access.

I feel either the reason for the cache hit or the array itself being encapsulated by attributes. Equivalent to calling the function again.

3.TPL Task Parallel Library really works, it seems that Microsoft has already considered a large number of data parallel cycle optimization problem 09, but I always use the wrong way, just feel very slow.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.