2

Consider the following code sample, from msdn,

private void SetPixel_Example(PaintEventArgs e)
{
    // Create a Bitmap object from a file.
    Bitmap myBitmap = new Bitmap("Grapes.jpg");

    // Draw myBitmap to the screen.
    e.Graphics.DrawImage(myBitmap, 0, 0, myBitmap.Width, myBitmap.Height);

    // Set each pixel in myBitmap to black.
    for (int Xcount = 0; Xcount < myBitmap.Width; Xcount++)
    {
        for (int Ycount = 0; Ycount < myBitmap.Height; Ycount++)
        {
            myBitmap.SetPixel(Xcount, Ycount, Color.Black);
        }
    }

    // Draw myBitmap to the screen again.
    e.Graphics.DrawImage(myBitmap, myBitmap.Width, 0, myBitmap.Width, myBitmap.Height);
}

Note that the outer loop in the nest for loop iterates on indexes towards the bitmap's width, and the inner loop iterates on indexes towards the bitmap's height. I saw code snippets of the same style in several other places.

My question is: Does this mean that a Bitmap object stores its pixels information column by column internally, that is, thinking of all pixels as a matrix in the screen, it is stored in the main memory by column, as in programming language Fortran. The reasoning behind this question is to avoid cache miss, nested loop should be arranged according the memory format of a 2-D data structure.

Tatranskymedved
  • 4,194
  • 3
  • 21
  • 47
John Z. Li
  • 1,893
  • 2
  • 12
  • 19
  • 1
    No, `GetPixel()` and `SetPixel()` abstract those _details_ from you. How image is stored internally depends on the format (roughly the number of bits per pixel). Of course (besides range checking) you pay a HUGE performance price for this. See also [this answer](https://stackoverflow.com/a/17208320/1207195) and especially its links. – Adriano Repetti May 04 '18 at 09:01
  • 1
    @TheGeneral somewhere there will be some linear memory that is the data, but it isn't an array in .NET terms - it is an unmanaged pointer to memory owned by the GDI layer – Marc Gravell May 04 '18 at 09:08
  • @MarcGravell happily corrected by you sir – TheGeneral May 04 '18 at 09:09
  • Arranging nested loops and optimizing cache hits are totally useless in **this particular example**, because `GetPixel` and `SetPixel` are *terrifying* slow. – dymanoid May 04 '18 at 09:15
  • 2
    It is stored row by row, bgra plus, maybe a padding called stride. Look for examples of using LockBits to a) see more of the internals and b) learn how to access the pixels really fast. Those code snippets are actually usually written the other way round, but there is hardly a speed difference, if any.. And to make it all black use Graphics.Clear(Color.black); MSDN has great examples and also terrible ones. This one is not so good.. – TaW May 04 '18 at 10:51
  • Wow, that's from MSDN? That place has some really crappy examples. – Nyerguds May 04 '18 at 11:31

1 Answers1

2

The source code of the Bitmap can be found here. Internally the bitmap details are stored in Image object (a reference to in-memory C++ object), which is part of GDI+.

What you've found on MSDN is an abstraction layer (as Adriano Repetti said), which allows you not to deal with the code behind. The thing is, if You want to work with such objects, You have to go through these "abstraction layers", which might decrease the performance. Other way around is to use some other library or program this Bitmap/Image object holders yourself.

Tatranskymedved
  • 4,194
  • 3
  • 21
  • 47
  • 2
    `Image` isn't C++; [here it is](https://referencesource.microsoft.com/#System.Drawing/commonui/System/Drawing/Image.cs) - it is C# - and the `Bitmap` *is* an `Image`; it also doesn't contain the actual data - that is in at an unmanaged pointer location, the `nativeImage` field (`IntPtr`); *that* is the unmanaged object here. – Marc Gravell May 04 '18 at 09:25
  • 1
    @MarcGravell Well, technically both statements are true. The bitmap (inheriting from .NET `Image`) is holding pointer to in-memory (unmanaged) object, which is called also `Image` (GDI+). This is probably where the confusion is coming from. – Tatranskymedved May 04 '18 at 09:44
  • ah, fair enough; makes sense – Marc Gravell May 04 '18 at 09:49