Accurate display of pixels scalable by Graphics.DrawImage

I have a Winforms application that uses Graphics.DrawImageto stretch and draw a bitmap, and I need help understanding how the source pixels map to the destination.

Ideally, I want to write a function like:

 Point MapPixel(Point p, Size src, Size dst)

which takes the coordinate of the pixel in the original image and returns the coordinate of the "upper left" pixel corresponding to it at the scaled destination.

For clarity, a trivial example is presented here in which a 2x2 bitmap is scaled to 4x4:

Zoom example

The arrow shows how to feed the point (1,0) into MapPixel:

MapPixel(new Point(1, 0), new Size(2, 2), new Size(4, 4))

should give the result (2.0).

It is easier to make MapPixel work for the above example using logic, for example:

double scaleX = (double)dst.Width / (double)src.Width;
x_dst = (int)Math.Round((double)x_src * scaleX);

, - , dst.Width src.Width. DrawImage , , , , .

2x1 :

Bitmap src = new Bitmap(2, 1);
src.SetPixel(0, 0, Color.Red);
src.SetPixel(1, 0, Color.Blue);

Bitmap[] dst = {
  new Bitmap(3, 1),
  new Bitmap(5, 1),
  new Bitmap(7, 1),
  new Bitmap(9, 1)};

// Draw stretched images
foreach (Bitmap b in dst) {
  using (Graphics g = Graphics.FromImage(b)) {
    g.InterpolationMode = InterpolationMode.NearestNeighbor;
    g.PixelOffsetMode = PixelOffsetMode.Half;
    g.DrawImage(src, 0, 0, b.Width, b.Height);
  }
}

src dst, , , MapPixel :

Scaling examples

, DrawImage , . , , . , , , .

MapPixel, MidpointRounding.AwayFromZero, Math.Round , ( , ). Graphics - ScaleTransform, DrawImageUnscaled, TransformPoints . , TransformPoints , DrawImage DrawImageUnscaled.

GDI + , .

, , .

, , , InterpolationMode.NearestNeighbor, - ( ), PixelOffsetMode.Half , , DrawImage .

x = 7 4px 13px x = 8 4px 17px.

unit test, , MapPixel. 100- - , "", . , , , . (, , ), .

, - DrawImage ( ) MapPixel.

+3
1

( , ). :

( N)

[0, origN] () [0, destN]

, , :

 origPos                    destPos
---------  for orig, and,  --------- for dest
  origN                      destN

dest , ::

for current_dest_position in range(destLength):
    required_source_position=floor( (current_dest_position*sourceN)/destN )

srcN destN ( 0, ), 16, dest 64, srcN 15, destN - 63 ( (k) [0, k-1]). , , , (javascript, php, lua, python ..) C/++, int :

required_source_position=(int)((current_dest_position*sourceN)/destN);

. N (X, Y, Z ..).

0

Source: https://habr.com/ru/post/1795414/


All Articles